libiptc.c revision 7cd002826d0f329620cb738bc4dc4760ef5e084a
17cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette/* Library which manipulates firewall rules.  Version $Revision: 1.44 $ */
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Architecture of firewall rules is as follows:
4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *
5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Chains go INPUT, FORWARD, OUTPUT then user chains.
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Each user chain starts with an ERROR node.
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Every chain ends with an unconditional jump: a RETURN for user chains,
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * and a POLICY for built-ins.
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
113ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
123ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte * COPYING for details).
133ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte * (C) 2000-2003 by the Netfilter Core Team <coreteam@netfilter.org>
143ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte *
15fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
163ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte *	- Reimplementation of chain cache to use offsets instead of entries
17fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte * 	- performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
19fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 	  don't rebuild the chain cache after every operation, instead fix it
20fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 	  up after a ruleset change.
213ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte */
22e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
237cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette#include<sys/types.h>
247cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette#include<sys/socket.h>
257cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#ifndef __OPTIMIZE__
310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald WelteSTRUCT_ENTRY_TARGET *
320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald WelteGET_TARGET(STRUCT_ENTRY *e)
330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (void *)e + e->target_offset;
350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#endif
370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
4279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell= { [HOOK_PRE_ROUTING]  "PREROUTING",
4379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_IN]     "INPUT",
4479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_FORWARD]      "FORWARD",
4579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_OUT]    "OUTPUT",
4610758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_POST_ROUTING] "POSTROUTING",
4710758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#ifdef HOOK_DROPPING
4810758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_DROPPING]	"DROPPING"
4910758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#endif
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
571cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_ZEROED,
581cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_SET
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Convenience structures */
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct ipt_error_target
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
6679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET t;
6779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char error[TABLE_MAXNAMELEN];
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestruct chain_cache
7130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
7279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char name[TABLE_MAXNAMELEN];
730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* This is the first rule in chain. */
740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int start_off;
750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Last rule in chain */
760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int end_off;
7730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell};
7830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
7979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellSTRUCT_TC_HANDLE
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Have changes been made? */
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int changed;
830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Size in here reflects original state. */
8479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct counter_map *counter_map;
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Array of hook names */
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char **hooknames;
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
9030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Cached position of chain heads (NULL = no cache). */
9130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int cache_num_chains;
9230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int cache_num_builtins;
9330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *cache_chain_heads;
9430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
9530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Chain iterator: current chain cache entry. */
9630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *cache_chain_iteration;
9730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
9830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Rule iterator: terminal rule */
9979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *cache_rule_end;
100175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Number in here reflects current state. */
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int new_number;
10379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GET_ENTRIES entries;
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
106175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
10779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_changed(TC_HANDLE_T h)
108175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
109175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
110175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
111175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
112380ba5f3074a16fbaa8869d9594962d58b5f8608Harald Welte#ifdef IPTC_DEBUG
11379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void do_check(TC_HANDLE_T h, unsigned int line);
114849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
11530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else
11630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h)
11730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
12079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_number(const STRUCT_ENTRY *i,
12179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   const STRUCT_ENTRY *seek,
122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
13179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellentry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
135725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
13679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			  get_number, seek, &pos) == 0) {
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %i not an entry!\n",
138725d97a79cf0b332ed45cb7d254915178328427dRusty Russell			(char *)seek - (char *)h->entries.entrytable);
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
14579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_entry_n(STRUCT_ENTRY *i,
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int number,
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int *pos,
14879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    STRUCT_ENTRY **pe)
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*pos == number) {
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*pe = i;
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic STRUCT_ENTRY *
15979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellindex2entry(TC_HANDLE_T h, unsigned int index)
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
16279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *ret = NULL;
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
164725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
16579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      get_entry_n, index, &pos, &ret);
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic inline STRUCT_ENTRY *
1710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteget_entry(TC_HANDLE_T h, unsigned int offset)
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic inline unsigned long
1770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteentry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (void *)e - (void *)h->entries.entrytable;
1800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
1819e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
1820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic inline unsigned long
1830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteindex2offset(TC_HANDLE_T h, unsigned int index)
1840113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
1850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return entry2offset(h, index2entry(h, index));
186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1883ea8f40262386e6b1445a617841f28702fe74d9dHarald Weltestatic inline STRUCT_ENTRY *
1893ea8f40262386e6b1445a617841f28702fe74d9dHarald Welteoffset2entry(TC_HANDLE_T h, unsigned int offset)
1903ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
1913ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte	return (STRUCT_ENTRY *) ((void *)h->entries.entrytable+offset);
1923ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
1933ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
1943ea8f40262386e6b1445a617841f28702fe74d9dHarald Weltestatic inline unsigned int
1953ea8f40262386e6b1445a617841f28702fe74d9dHarald Welteoffset2index(const TC_HANDLE_T h, unsigned int offset)
1963ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
1973ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte	return entry2index(h, offset2entry(h, offset));
1983ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
1993ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
2003ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
2010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic const char *
2020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteget_errorlabel(TC_HANDLE_T h, unsigned int offset)
2030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
2040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *e;
2050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
2060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = get_entry(h, offset);
2070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) {
2080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		fprintf(stderr, "ERROR: offset %u not an error node!\n",
2090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			offset);
2100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		abort();
2110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
2120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
2130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (const char *)GET_TARGET(e)->data;
2140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
21779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic TC_HANDLE_T
2180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltealloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
22179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
22379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	len = sizeof(STRUCT_TC_HANDLE)
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ num_rules * sizeof(struct counter_map);
226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = malloc(len)) == NULL) {
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->changed = 0;
2330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_num_chains = 0;
2340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_chain_heads = NULL;
2350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->counter_map = (void *)h
2360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		+ sizeof(STRUCT_TC_HANDLE)
2370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		+ size;
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->entries.name, tablename);
240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
24479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_HANDLE_T
24579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INIT(const char *tablename)
246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
24779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
24879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
2490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int i;
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
25379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INIT;
254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
255e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	if (sockfd != -1) {
256366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte		close(sockfd);
257e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
258e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	}
259366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte
260841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
261841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		errno = EINVAL;
262841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		return NULL;
263841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
264841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
26579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (sockfd < 0)
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
270841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
27279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((h = alloc_handle(info.name, info.size, info.num_entries))
276841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == NULL) {
277841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		close(sockfd);
278e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
280841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Too hard --RR */
283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dynlib = dlopen(pathname, RTLD_NOW);
286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!dynlib) {
287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = dlsym(dynlib, "hooknames");
291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!h->hooknames) {
292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#else
296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = hooknames;
297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
3010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->new_number = h->info.num_entries;
3020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < h->info.num_entries; i++)
3030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->counter_map[i]
3040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
3050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->entries.size = h->info.size;
307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
30879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
31079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       &tmp) < 0) {
312841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		close(sockfd);
313e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(h);
315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
3177e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
322841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssonvoid
323841e4aed2349046eb2c0b1375139c06569a93bd0Martin JosefssonTC_FREE(TC_HANDLE_T *h)
324841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
325841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	close(sockfd);
326e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	sockfd = -1;
3270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((*h)->cache_chain_heads)
3280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		free((*h)->cache_chain_heads);
329841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	free(*h);
330841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	*h = NULL;
331841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson}
332841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
33479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellprint_match(const STRUCT_ENTRY_MATCH *m)
335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
336228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
34079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
34179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
34379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DUMP_ENTRIES(const TC_HANDLE_T handle)
344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("libiptc v%s.  %u entries, %u bytes.\n",
34880fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte	       IPTABLES_VERSION,
349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->new_number, handle->entries.size);
350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
35267088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_PRE_ROUTING],
35367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_IN],
35467088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_FORWARD],
35567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_OUT],
35667088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_POST_ROUTING]);
357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
35867088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_PRE_ROUTING],
35967088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_IN],
36067088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_FORWARD],
36167088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_OUT],
36267088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_POST_ROUTING]);
363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
364725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size,
36579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      dump_entry, handle);
366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
36830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns 0 if not hook entry, else hooknumber + 1 */
36930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic inline unsigned int
37079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
37130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
37230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int i;
37330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
37479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
37530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if ((h->info.valid_hooks & (1 << i))
37630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		    && get_entry(h, h->info.hook_entry[i]) == e)
37730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			return i+1;
37830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
37930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return 0;
38030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
38130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
3820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic inline int
3830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteadd_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev)
3840113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
3850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int builtin;
3860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
3870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Last entry.  End it. */
3880113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (entry2offset(h, e) + e->next_offset == h->entries.size) {
3890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* This is the ERROR node at end of the table */
3900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->cache_chain_heads[h->cache_num_chains-1].end_off =
3910113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			entry2offset(h, *prev);
3920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
3930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
3940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
3950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* We know this is the start of a new chain if it's an ERROR
3960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	   target, or a hook entry point */
3970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
3980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* prev was last entry in previous chain */
3990113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->cache_chain_heads[h->cache_num_chains-1].end_off
4000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= entry2offset(h, *prev);
4010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		strcpy(h->cache_chain_heads[h->cache_num_chains].name,
4030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		       (const char *)GET_TARGET(e)->data);
4040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->cache_chain_heads[h->cache_num_chains].start_off
4050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= entry2offset(h, (void *)e + e->next_offset);
4060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->cache_num_chains++;
4070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	} else if ((builtin = is_hook_entry(e, h)) != 0) {
4080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (h->cache_num_chains > 0)
4090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			/* prev was last entry in previous chain */
4100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			h->cache_chain_heads[h->cache_num_chains-1].end_off
4110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				= entry2offset(h, *prev);
4120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		strcpy(h->cache_chain_heads[h->cache_num_chains].name,
4140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		       h->hooknames[builtin-1]);
4150113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->cache_chain_heads[h->cache_num_chains].start_off
4160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= entry2offset(h, (void *)e);
4170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		h->cache_num_chains++;
4180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
4190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	*prev = e;
4210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return 0;
4220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
42430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic int alphasort(const void *a, const void *b)
42530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
42630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return strcmp(((struct chain_cache *)a)->name,
42730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		      ((struct chain_cache *)b)->name);
42830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
4290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic int populate_cache(TC_HANDLE_T h)
4310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
4320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int i;
4330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *prev;
4340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* # chains < # rules / 2 + num builtins - 1 */
4360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_chain_heads = malloc((h->new_number / 2 + 4)
4370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				      * sizeof(struct chain_cache));
4380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!h->cache_chain_heads) {
4390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = ENOMEM;
4400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
4410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
4420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_num_chains = 0;
4440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_num_builtins = 0;
4450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Count builtins */
4470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < NUMHOOKS; i++) {
4480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (h->info.valid_hooks & (1 << i))
4490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			h->cache_num_builtins++;
4500113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
4510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	prev = NULL;
4530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
4540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		      add_chain, h, &prev);
4550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	qsort(h->cache_chain_heads + h->cache_num_builtins,
4570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	      h->cache_num_chains - h->cache_num_builtins,
4580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	      sizeof(struct chain_cache), alphasort);
4590113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return 1;
4610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
4620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4630113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic int
4640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltecorrect_cache(TC_HANDLE_T h, unsigned int offset, int delta)
4650113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
4660113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int i;		/* needs to be signed because deleting first
4670113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   chain can make it drop to -1 */
4680113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4690113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!delta)
4700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 1;
4710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < h->cache_num_chains; i++) {
4730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		struct chain_cache *cc = &h->cache_chain_heads[i];
4740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (delta < 0) {
4760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			/* take care about deleted chains */
4770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			if (cc->start_off > offset+delta
4780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			    && cc->end_off < offset) {
4790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				/* this chain is within the deleted range,
4800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				 * let's remove it from the cache */
4810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				void *start;
4820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				unsigned int size;
4830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4840113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				h->cache_num_chains--;
4850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				/* no need for memmove since we are
4870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				 * removing the last entry */
4880113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				if (i >= h->cache_num_chains)
4890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					continue;
4900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4910113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				start = &h->cache_chain_heads[i+1];
4920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				size = (h->cache_num_chains-i)
4930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					* sizeof(struct chain_cache);
4940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				memmove(cc, start, size);
4950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
4960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				/* iterate over same index again, since
4970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				 * it is now a different chain */
4980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				i--;
4990113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				continue;
5000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			}
5010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		}
5020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (cc->start_off > offset)
5040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			cc->start_off += delta;
5050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (cc->end_off >= offset)
5070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			cc->end_off += delta;
5080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
5090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* HW_FIXME: sorting might be needed, but just in case a new chain was
5100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	 * added */
5110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return 1;
5130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
5140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5150113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic int
5160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteadd_chain_cache(TC_HANDLE_T h, const char *name, unsigned int start_off,
5170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		unsigned int end_off)
5180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
5190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *ccs = realloc(h->cache_chain_heads,
5200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					  (h->new_number / 2 + 4 + 1)
5210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					   * sizeof(struct chain_cache));
5220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *newcc;
5230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!ccs)
5250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
5260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_chain_heads = ccs;
5280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newcc = &h->cache_chain_heads[h->cache_num_chains];
5290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	h->cache_num_chains++;
5300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	strncpy(newcc->name, name, TABLE_MAXNAMELEN-1);
532073df8feb0a8c4023ce40138e519ac9b341b1ca2Karsten Desler	newcc->name[TABLE_MAXNAMELEN-1] = '\0';
5330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newcc->start_off = start_off;
5340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newcc->end_off = end_off;
5350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return 1;
5370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
5380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Returns cache ptr if found, otherwise NULL. */
5400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic struct chain_cache *
5410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltefind_label(const char *name, TC_HANDLE_T handle)
5420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
5430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int i;
5440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (handle->cache_chain_heads == NULL
5460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    && !populate_cache(handle))
5470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
5480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* FIXME: Linear search through builtins, then binary --RR */
5500113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < handle->cache_num_chains; i++) {
5510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (strcmp(handle->cache_chain_heads[i].name, name) == 0)
5520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			return &handle->cache_chain_heads[i];
5530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
5540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
5550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return NULL;
5560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
55979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
56130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return find_label(chain, handle) != NULL;
562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns the position of the final (ie. unconditional) element. */
565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
56679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_chain_end(const TC_HANDLE_T handle, unsigned int start)
567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int last_off, off;
56979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	last_off = start;
572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(handle, start);
573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Terminate when we meet a error label or a hook entry. */
575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (off = start + e->next_offset;
576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     off < handle->entries.size;
577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     last_off = off, off += e->next_offset) {
57879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY_TARGET *t;
579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(handle, off);
582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit an entry point. */
58479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		for (i = 0; i < NUMHOOKS; i++) {
585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if ((handle->info.valid_hooks & (1 << i))
586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && off == handle->info.hook_entry[i])
587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				return last_off;
588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit a user chain label */
59179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		t = GET_TARGET(e);
59267088e73ce7707229c56987868f112051defca5aRusty Russell		if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return last_off;
594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* SHOULD NEVER HAPPEN */
596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		handle->entries.size, off);
598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	abort();
599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
60130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
6038c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_CHAIN(TC_HANDLE_T *handle)
604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
6050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((*handle)->cache_chain_heads == NULL
6060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    && !populate_cache(*handle))
6070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
6080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
6090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	(*handle)->cache_chain_iteration
6100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		= &(*handle)->cache_chain_heads[0];
61130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
6120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (*handle)->cache_chain_iteration->name;
61330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
61430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
61530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
61630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
61779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NEXT_CHAIN(TC_HANDLE_T *handle)
61830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
6190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	(*handle)->cache_chain_iteration++;
62030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
6210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
6220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    == (*handle)->cache_num_chains)
62330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
62430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
6250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (*handle)->cache_chain_iteration->name;
62630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
62730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
62830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
62979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
6308c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
63130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
6320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
63330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
63430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	c = find_label(chain, *handle);
63530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
63630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
63730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
64030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
6410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (c->start_off == c->end_off)
64230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
64330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
6440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	(*handle)->cache_rule_end = offset2entry(*handle, c->end_off);
6450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return offset2entry(*handle, c->start_off);
646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
64830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
64979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
6508c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
65130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
6520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((void *)prev + prev->next_offset
6530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    == (void *)(*handle)->cache_rule_end)
65430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
65530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
6560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (void *)prev + prev->next_offset;
65730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
65830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
65930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#if 0
660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
66279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int off = 0;
66579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *start, *end;
666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&off, chain, *handle)) {
669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	start = get_entry(*handle, off);
674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	end = get_entry(*handle, get_chain_end(*handle, off));
675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2index(*handle, end) - entry2index(*handle, start);
677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get n'th rule in this chain. */
68079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *TC_GET_RULE(const char *chain,
68179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				unsigned int n,
68279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				TC_HANDLE_T *handle)
683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0, chainindex;
685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&pos, chain, *handle)) {
688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, pos));
693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return index2entry(*handle, chainindex + n);
695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
69630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
69830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic const char *
69979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russelltarget_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int spos;
7020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int labelidx;
7030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *jumpto;
704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
70530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* To avoid const warnings */
70679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
70730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
70879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
70979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		return GET_TARGET(e)->u.user.name;
710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Standard target: evaluate */
71279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	spos = *(int *)GET_TARGET(e)->data;
713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (spos < 0) {
71479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		if (spos == RETURN)
71579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_RETURN;
716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_ACCEPT-1)
71779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_ACCEPT;
718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_DROP-1)
71979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_DROP;
7202f4e5d92c73906e0dc2ae42fee5c05740528e92bJames Morris		else if (spos == -NF_QUEUE-1)
72167088e73ce7707229c56987868f112051defca5aRusty Russell			return LABEL_QUEUE;
722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
7230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
7240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			entry2offset(handle, e), handle->entries.size,
7250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			spos);
726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
7290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	jumpto = get_entry(handle, spos);
730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fall through rule */
732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (jumpto == (void *)e + e->next_offset)
733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return "";
734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must point to head of a chain: ie. after error rule */
736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labelidx = entry2index(handle, jumpto) - 1;
737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return get_errorlabel(handle, index2offset(handle, labelidx));
738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns a pointer to the target name of this position. */
74179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst char *TC_GET_TARGET(const STRUCT_ENTRY *e,
74279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			  TC_HANDLE_T *handle)
743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Is this a built-in chain?  Actually returns hook + 1. */
748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
74979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
75379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((handle->info.valid_hooks & (1 << i))
755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && handle->hooknames[i]
756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && strcmp(handle->hooknames[i], chain) == 0)
757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return i+1;
758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the policy of a given built-in chain */
763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
76479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_POLICY(const char *chain,
76579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      STRUCT_COUNTERS *counters,
76679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
7680113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int start;
76979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int hook;
771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
77279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	hook = TC_BUILTIN(chain, *handle);
7730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (hook != 0)
7740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		start = (*handle)->info.hook_entry[hook-1];
7750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	else
7769e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte		return NULL;
7779e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
7780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = get_entry(*handle, get_chain_end(*handle, start));
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*counters = e->counters;
780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
7840113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic inline int
78579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellcorrect_verdict(STRUCT_ENTRY *e,
786725d97a79cf0b332ed45cb7d254915178328427dRusty Russell		char *base,
787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int offset, int delta_offset)
788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
78979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
790725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	unsigned int curr = (char *)e - base;
791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Trap: insert of fall-through rule.  Don't change fall-through
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   verdict to jump-over-next-rule. */
79479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && t->verdict > (int)offset
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && !(curr == offset &&
797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		 t->verdict == curr + e->next_offset)) {
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict += delta_offset;
799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Adjusts standard verdict jump positions after an insertion/deletion. */
805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
80679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
808725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE((*handle)->entries.entrytable,
80979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      (*handle)->entries.size,
810725d97a79cf0b332ed45cb7d254915178328427dRusty Russell		      correct_verdict, (char *)(*handle)->entries.entrytable,
81179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      offset, delta_offset);
812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
813175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
8170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* If prepend is set, then we are prepending to a chain: if the
8180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte * insertion position is an entry point, keep the entry point. */
8190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic int
8200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteinsert_rules(unsigned int num_rules, unsigned int rules_size,
8210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     const STRUCT_ENTRY *insert,
8220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     unsigned int offset, unsigned int num_rules_offset,
8230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     int prepend,
8240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     TC_HANDLE_T *handle)
8250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
8260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	TC_HANDLE_T newh;
8270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_GETINFO newinfo;
8280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int i;
8290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (offset >= (*handle)->entries.size) {
8310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = EINVAL;
8320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
8330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
8340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newinfo = (*handle)->info;
8360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Fix up entry points. */
8380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < NUMHOOKS; i++) {
8390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* Entry points to START of chain, so keep same if
8400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte                   inserting on at that point. */
8410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if ((*handle)->info.hook_entry[i] > offset)
8420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			newinfo.hook_entry[i] += rules_size;
8430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* Underflow always points to END of chain (policy),
8450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		   so if something is inserted at same point, it
8460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		   should be advanced. */
8470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if ((*handle)->info.underflow[i] >= offset)
8480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			newinfo.underflow[i] += rules_size;
8490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
8500113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh = alloc_handle((*handle)->info.name,
8520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			    (*handle)->entries.size + rules_size,
8530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			    (*handle)->new_number + num_rules);
8540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!newh)
8550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
8560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->info = newinfo;
8570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Copy pre... */
8590113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset);
8600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* ... Insert new ... */
8610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy((char *)newh->entries.entrytable + offset, insert, rules_size);
8620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* ... copy post */
8630113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy((char *)newh->entries.entrytable + offset + rules_size,
8640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	       (char *)(*handle)->entries.entrytable + offset,
8650113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	       (*handle)->entries.size - offset);
8660113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8670113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Move counter map. */
8680113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Copy pre... */
8690113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(newh->counter_map, (*handle)->counter_map,
8700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	       sizeof(struct counter_map) * num_rules_offset);
8710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* ... copy post */
8720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(newh->counter_map + num_rules_offset + num_rules,
8730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	       (*handle)->counter_map + num_rules_offset,
8740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	       sizeof(struct counter_map) * ((*handle)->new_number
8750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					     - num_rules_offset));
8760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Set intermediates to no counter copy */
8770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < num_rules; i++)
8780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		newh->counter_map[num_rules_offset+i]
8790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= ((struct counter_map){ COUNTER_MAP_SET, 0 });
8800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->new_number = (*handle)->new_number + num_rules;
8820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->entries.size = (*handle)->entries.size + rules_size;
8830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->hooknames = (*handle)->hooknames;
8840113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->cache_chain_heads = (*handle)->cache_chain_heads;
8860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->cache_num_builtins = (*handle)->cache_num_builtins;
8870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->cache_num_chains = (*handle)->cache_num_chains;
8880113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->cache_rule_end = (*handle)->cache_rule_end;
8890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newh->cache_chain_iteration = (*handle)->cache_chain_iteration;
8900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!correct_cache(newh, offset, rules_size)) {
8910113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		free(newh);
8920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
8930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
8940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	free(*handle);
8960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	*handle = newh;
8970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
8980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return set_verdict(offset, rules_size, handle);
8990113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
9000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltestatic int
9020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltedelete_rules(unsigned int num_rules, unsigned int rules_size,
9030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     unsigned int offset, unsigned int num_rules_offset,
9040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     TC_HANDLE_T *handle)
9050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
9060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int i;
9070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (offset + rules_size > (*handle)->entries.size) {
9090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = EINVAL;
9100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
9110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
912fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
9130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Fix up entry points. */
9140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < NUMHOOKS; i++) {
9150113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* In practice, we never delete up to a hook entry,
9160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		   since the built-in chains are always first,
9170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		   so these two are never equal */
9180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if ((*handle)->info.hook_entry[i] >= offset + rules_size)
9190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			(*handle)->info.hook_entry[i] -= rules_size;
9200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		else if ((*handle)->info.hook_entry[i] > offset) {
9210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
9220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				i, (*handle)->info.hook_entry[i], offset);
9230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			abort();
9240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		}
9250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* Underflow points to policy (terminal) rule in
9270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte                   built-in, so sequality is valid here (when deleting
9280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte                   the last rule). */
9290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if ((*handle)->info.underflow[i] >= offset + rules_size)
9300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			(*handle)->info.underflow[i] -= rules_size;
9310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		else if ((*handle)->info.underflow[i] > offset) {
9320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
9330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte				i, (*handle)->info.underflow[i], offset);
9340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			abort();
9350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		}
9360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
9370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Move the rules down. */
9390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memmove((char *)(*handle)->entries.entrytable + offset,
9400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		(char *)(*handle)->entries.entrytable + offset + rules_size,
9410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		(*handle)->entries.size - (offset + rules_size));
9420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Move the counter map down. */
9440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memmove(&(*handle)->counter_map[num_rules_offset],
9450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		&(*handle)->counter_map[num_rules_offset + num_rules],
9460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		sizeof(struct counter_map)
9470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		* ((*handle)->new_number - (num_rules + num_rules_offset)));
9480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Fix numbers */
9500113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	(*handle)->new_number -= num_rules;
9510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	(*handle)->entries.size -= rules_size;
9520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Fix the chain cache */
9540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!correct_cache(*handle, offset+rules_size, -(int)rules_size))
9550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
9560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
9570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return set_verdict(offset, -(int)rules_size, handle);
9580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
96179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstandard_map(STRUCT_ENTRY *e, int verdict)
962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
96379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
96579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
96767088e73ce7707229c56987868f112051defca5aRusty Russell	if (t->target.u.target_size
9688c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
97379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
97479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(t->target.u.user.name, STANDARD_TARGET);
975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
9797e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
98179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmap_target(const TC_HANDLE_T handle,
98279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   STRUCT_ENTRY *e,
983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int offset,
98479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   STRUCT_ENTRY_TARGET *old)
985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
9860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
989e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*old = *t;
991e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
993228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(t->u.user.name, "") == 0)
994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, offset + e->next_offset);
995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
99679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
997e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_ACCEPT - 1);
99879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_DROP - 1);
100067088e73ce7707229c56987868f112051defca5aRusty Russell	else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_QUEUE - 1);
100279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
100379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		return standard_map(e, RETURN);
100479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (TC_BUILTIN(t->u.user.name, handle)) {
1005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
1006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
1009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
10100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		struct chain_cache *c;
1011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1012228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		c = find_label(t->u.user.name, handle);
101330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (c)
10143ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte			return standard_map(e, c->start_off);
1015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1017e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
1018e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset to all 0 for your memcmp convenience. */
1019228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
1020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
102179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	       FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
1022e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1023e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1024e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
102679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellunmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
1027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
102879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1030e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
1031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
1032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*t = *old;
1033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
10350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
103779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
103879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
103979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned int rulenum,
104079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
10420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int chainindex, offset;
10430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET old;
10440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
10450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *tmp;
10460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int ret;
1047e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INSERT_ENTRY;
104930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1051e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
10540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	chainindex = offset2index(*handle, c->start_off);
10550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
10560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	tmp = index2entry(*handle, chainindex + rulenum);
10570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!tmp || tmp > offset2entry(*handle, c->end_off)) {
1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
10610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	offset = index2offset(*handle, chainindex + rulenum);
1062e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
10630113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Mapping target actually alters entry, but that's
10640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte           transparent to the caller. */
10650113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
10660113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
10680113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = insert_rules(1, e->next_offset, e, offset,
10690113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   chainindex + rulenum, rulenum == 0, handle);
10700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unmap_target((STRUCT_ENTRY *)e, &old);
10710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1072e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1073e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1074e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
107679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
107779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 const STRUCT_ENTRY *e,
107879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 unsigned int rulenum,
107979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 TC_HANDLE_T *handle)
1080e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
10810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int chainindex, offset;
10820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET old;
10830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
10840113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *tmp;
10850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int ret;
1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
108779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_REPLACE_ENTRY;
1088e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
108930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1092e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1093e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
10940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	chainindex = offset2index(*handle, c->start_off);
10950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
10960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	tmp = index2entry(*handle, chainindex + rulenum);
10970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!tmp || tmp >= offset2entry(*handle, c->end_off)) {
1098e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	offset = index2offset(*handle, chainindex + rulenum);
11030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Replace = delete and insert. */
11040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
11050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			  offset, chainindex + rulenum, handle))
1106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
11090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
11100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
11110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = insert_rules(1, e->next_offset, e, offset,
11120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   chainindex + rulenum, 1, handle);
11130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unmap_target((STRUCT_ENTRY *)e, &old);
11140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
112079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
112179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
112279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
11240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
11250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET old;
11260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int ret;
1127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
112879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_APPEND_ENTRY;
112930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!map_target(*handle, (STRUCT_ENTRY *)e,
11350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			c->end_off, &old))
11360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
11370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
11380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = insert_rules(1, e->next_offset, e, c->end_off,
11390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   offset2index(*handle, c->end_off), 0, handle);
11400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unmap_target((STRUCT_ENTRY *)e, &old);
11410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
114579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmatch_different(const STRUCT_ENTRY_MATCH *a,
1146edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1147edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1148edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
115079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY_MATCH *b;
1151edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
115430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1156228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1159228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
116273ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	*maskptr += ALIGN(sizeof(*a));
1163edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
116473ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1165edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1166edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1167edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1168edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1169edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1170edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1171edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1172edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russelltarget_different(const unsigned char *a_targdata,
1173edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *b_targdata,
1174edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 unsigned int tdatasize,
1175edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *mask)
1176edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1177edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1178edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	for (i = 0; i < tdatasize; i++)
1179edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
118090e712a00913fe2a2f885142439c392392dc08a8Rusty Russell			return 1;
1181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
118579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int
118679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_same(const STRUCT_ENTRY *a,
118779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY *b,
118879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unsigned char *matchmask);
1189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Delete the first rule in `chain' which matches `fw'. */
1191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
119279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
119379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *origfw,
119479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned char *matchmask,
119579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
11970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int offset;
11980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
11990113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *e, *fw;
1200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
120179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_ENTRY;
120230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	fw = malloc(origfw->next_offset);
12080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (fw == NULL) {
12090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = ENOMEM;
12100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
12110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
12120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
12130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (offset = c->start_off; offset < c->end_off;
12140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	     offset += e->next_offset) {
12150113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		STRUCT_ENTRY_TARGET discard;
12160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
12170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		memcpy(fw, origfw, origfw->next_offset);
12180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
12190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* FIXME: handle this in is_same --RR */
12200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (!map_target(*handle, fw, offset, &discard)) {
12210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			free(fw);
12220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			return 0;
12230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		}
12240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		e = get_entry(*handle, offset);
12250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
12260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#if 0
12270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		printf("Deleting:\n");
12280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		dump_entry(newe);
12290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#endif
12300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (is_same(e, fw, matchmask)) {
12310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			int ret;
12320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			ret = delete_rules(1, e->next_offset,
12330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					   offset, entry2index(*handle, e),
12340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte					   handle);
12350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			free(fw);
12360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			return ret;
1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	free(fw);
1241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
12437e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
124779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
124879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    unsigned int rulenum,
124979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
12510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int index;
12520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int ret;
12530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *e;
12540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
1255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
125679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_NUM_ENTRY;
12570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!(c = find_label(chain, *handle))) {
1258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	index = offset2index(*handle, c->start_off) + rulenum;
12630113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
12640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (index >= offset2index(*handle, c->end_off)) {
1265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12690113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = index2entry(*handle, index);
12700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (e == NULL) {
12710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = EINVAL;
12720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
12730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
12760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   index, handle);
12770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
128379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CHECK_PACKET(const IPT_CHAINLABEL chain,
128479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY *entry,
128579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
129379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
12950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int startindex, endindex;
12960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *startentry, *endentry;
12970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
12980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int ret;
1299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	iptc_fn = TC_FLUSH_ENTRIES;
13010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!(c = find_label(chain, *handle))) {
1302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
13050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	startindex = offset2index(*handle, c->start_off);
13060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	endindex = offset2index(*handle, c->end_off);
13070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	startentry = offset2entry(*handle, c->start_off);
13080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	endentry = offset2entry(*handle, c->end_off);
1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = delete_rules(endindex - startindex,
13110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   (char *)endentry - (char *)startentry,
13120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   c->start_off, startindex,
13130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   handle);
13140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
131979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
13210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int i, end;
13220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
13237e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
132430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	i = offset2index(*handle, c->start_off);
13300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	end = offset2index(*handle, c->end_off);
13310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (; i <= end; i++) {
13330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
13340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			(*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1336175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13411cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteSTRUCT_COUNTERS *
13421cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_READ_COUNTER(const IPT_CHAINLABEL chain,
13431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
13441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
13451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
13461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
13470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
13480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int chainindex, end;
13491cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13501cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_READ_COUNTER;
13511cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
13521cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!(c = find_label(chain, *handle))) {
13541cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
13551cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
13561cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
13571cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	chainindex = offset2index(*handle, c->start_off);
13590113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	end = offset2index(*handle, c->end_off);
13600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (chainindex + rulenum > end) {
13620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
13630113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
13640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
13650113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13660113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = index2entry(*handle, chainindex + rulenum);
13670113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13680113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return &e->counters;
13691cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
13701cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13711cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
13721cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
13731cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
13741cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
13751cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
13761cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
13770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
13780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int chainindex, end;
13791cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13801cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_ZERO_COUNTER;
13811cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
13821cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!(c = find_label(chain, *handle))) {
13841cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
13851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
13861cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
13871cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13880113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	chainindex = offset2index(*handle, c->start_off);
13890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	end = offset2index(*handle, c->end_off);
13900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13910113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (chainindex + rulenum > end) {
13920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
13930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
13940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
13950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = index2entry(*handle, chainindex + rulenum);
13970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
13980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((*handle)->counter_map[chainindex + rulenum].maptype
13990113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			== COUNTER_MAP_NORMAL_MAP) {
14000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		(*handle)->counter_map[chainindex + rulenum].maptype
14010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			 = COUNTER_MAP_ZEROED;
14020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
14031cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14041cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
14051cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14061cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
14071cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
14081cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14091cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
14101cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_SET_COUNTER(const IPT_CHAINLABEL chain,
14111cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       unsigned int rulenum,
14121cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       STRUCT_COUNTERS *counters,
14131cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       TC_HANDLE_T *handle)
14141cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
14151cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
14160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
14170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int chainindex, end;
14181cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14191cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_SET_COUNTER;
14201cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
14211cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!(c = find_label(chain, *handle))) {
14231cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
14241cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
14251cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
14260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	chainindex = offset2index(*handle, c->start_off);
14280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	end = offset2index(*handle, c->end_off);
14290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (chainindex + rulenum > end) {
14310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
14320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
14330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
14340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = index2entry(*handle, chainindex + rulenum);
14360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	(*handle)->counter_map[chainindex + rulenum].maptype
14380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		= COUNTER_MAP_SET;
14390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
14411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14421cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
14431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
14441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
14451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
14461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
145179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
14540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct {
145579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY head;
1456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_error_target name;
145779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY ret;
145879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_STANDARD_TARGET target;
14590113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	} newc;
14600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int destination;
1461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
146279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_CREATE_CHAIN;
1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
146630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (find_label(chain, *handle)
146779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_DROP) == 0
146879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_ACCEPT) == 0
146967088e73ce7707229c56987868f112051defca5aRusty Russell	    || strcmp(chain, LABEL_QUEUE) == 0
147079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_RETURN) == 0) {
1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
147579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memset(&newc, 0, sizeof(newc));
14810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.head.target_offset = sizeof(STRUCT_ENTRY);
14820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.head.next_offset
148367088e73ce7707229c56987868f112051defca5aRusty Russell		= sizeof(STRUCT_ENTRY)
14848c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell		+ ALIGN(sizeof(struct ipt_error_target));
14850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	strcpy(newc.name.t.u.user.name, ERROR_TARGET);
14860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target));
14870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	strcpy(newc.name.error, chain);
1488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.ret.target_offset = sizeof(STRUCT_ENTRY);
14900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.ret.next_offset
149167088e73ce7707229c56987868f112051defca5aRusty Russell		= sizeof(STRUCT_ENTRY)
14928c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell		+ ALIGN(sizeof(STRUCT_STANDARD_TARGET));
14930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	strcpy(newc.target.target.u.user.name, STANDARD_TARGET);
14940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.target.target.u.target_size
14958c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell		= ALIGN(sizeof(STRUCT_STANDARD_TARGET));
14960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	newc.target.verdict = RETURN;
1497fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
14980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	destination = index2offset(*handle, (*handle)->new_number -1);
1499fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
15000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Add just before terminal entry */
15010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = insert_rules(2, sizeof(newc), &newc.head,
15020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   destination,
15030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   (*handle)->new_number - 1,
15040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   0, handle);
15050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
15060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	set_changed(*handle);
15070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
15080113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* add chain cache info for this chain */
15090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	add_chain_cache(*handle, chain,
15100113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			destination+newc.head.next_offset,
15110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			destination+newc.head.next_offset);
15120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
15130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
151779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellcount_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
151979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
152179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) {
152279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict == offset)
1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*ref)++;
1526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
153379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
153479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  TC_HANDLE_T *handle)
1535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
153630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
153830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*ref = 0;
1544725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE((*handle)->entries.entrytable,
154579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      (*handle)->entries.size,
15463ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte		      count_ref, c->start_off, ref);
1547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
155279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
15540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int labelidx, labeloff;
1555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
15560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
15570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	int ret;
15580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *start;
1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
156079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (!TC_GET_REFERENCES(&references, chain, handle))
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
15627e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
156379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_CHAIN;
1564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
156579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (TC_BUILTIN(chain, *handle)) {
1566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (references > 0) {
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EMLINK;
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (!(c = find_label(chain, *handle))) {
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (c->start_off != c->end_off) {
1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Need label index: preceeds chain start */
15860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	labelidx = offset2index(*handle, c->start_off) - 1;
15870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	labeloff = index2offset(*handle, labelidx);
15880113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
15890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	start = offset2entry(*handle, c->start_off);
15900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
15910113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	ret = delete_rules(2,
15920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   get_entry(*handle, labeloff)->next_offset
15930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   + start->next_offset,
15940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			   labeloff, labelidx, handle);
15950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return ret;
1596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
159979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
160079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    const IPT_CHAINLABEL newname,
160179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
16030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int labeloff, labelidx;
16040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct chain_cache *c;
1605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_error_target *t;
1606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
160779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_RENAME_CHAIN;
1608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16091de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
16101de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte           QUEUE, RETURN. */
161130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (find_label(newname, *handle)
161279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_DROP) == 0
161379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_ACCEPT) == 0
16141de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	    || strcmp(newname, LABEL_QUEUE) == 0
161579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_RETURN) == 0) {
1616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
162030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(oldname, *handle))
162179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || TC_BUILTIN(oldname, *handle)) {
1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
162679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* Need label index: preceeds chain start */
16320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	labelidx = offset2index(*handle, c->start_off) - 1;
16330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	labeloff = index2offset(*handle, labelidx);
1634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_error_target *)
16360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		GET_TARGET(get_entry(*handle, labeloff));
1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->error, 0, sizeof(t->error));
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(t->error, newname);
1640fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
16410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	/* update chain cache */
16420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memset(c->name, 0, sizeof(c->name));
16430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	strcpy(c->name, newname);
16440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
16450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	set_changed(*handle);
16460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
165279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_SET_POLICY(const IPT_CHAINLABEL chain,
165379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      const IPT_CHAINLABEL policy,
16541cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	      STRUCT_COUNTERS *counters,
165579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int hook;
16580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	unsigned int policyoff, ctrindex;
165979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
166079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
166279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_SET_POLICY;
1663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Figure out which chain. */
166479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	hook = TC_BUILTIN(chain, *handle);
1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook == 0) {
1666c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		hook--;
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
16720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (policyoff != (*handle)->info.underflow[hook]) {
16730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
16740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		       chain, policyoff, (*handle)->info.underflow[hook]);
16759e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte		return 0;
16769e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte	}
16779e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
16780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	e = get_entry(*handle, policyoff);
16790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
168179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(policy, LABEL_ACCEPT) == 0)
1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_ACCEPT - 1;
168379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(policy, LABEL_DROP) == 0)
1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_DROP - 1;
1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
16891cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16901cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	ctrindex = entry2index(*handle, e);
16911cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16921cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (counters) {
16931cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		/* set byte and packet counters */
16941cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
16951cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		(*handle)->counter_map[ctrindex].maptype
16970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= COUNTER_MAP_SET;
16981cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16991cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	} else {
17000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		(*handle)->counter_map[ctrindex]
17010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
17021cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
17031cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1704175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
171079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell   libiptc.c: In function `TC_COMMIT':
1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
171679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellsubtract_counters(STRUCT_COUNTERS *answer,
171779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *a,
171879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *b)
1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
172579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_COMMIT(TC_HANDLE_T *handle)
1726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
172879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_REPLACE *repl;
172979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_COUNTERS_INFO *newcounters;
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1731841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	size_t counterlen;
1732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1734841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1735841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	counterlen = sizeof(STRUCT_COUNTERS_INFO)
1736841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson			+ sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
1737841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
173954c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	TC_DUMP_ENTRIES(*handle);
1740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
175379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
17607e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
1764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
1771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_entries = (*handle)->new_number;
1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->size = (*handle)->entries.size;
1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->hook_entry));
1775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->underflow, (*handle)->info.underflow,
1776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->underflow));
1777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
1779725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	memcpy(repl->entries, (*handle)->entries.entrytable,
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size);
1781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
178279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
1783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       sizeof(*repl) + (*handle)->entries.size) < 0) {
1784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
1791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters->num_counters = (*handle)->new_number;
1793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < (*handle)->new_number; i++) {
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int mappos = (*handle)->counter_map[i].mappos;
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		switch ((*handle)->counter_map[i].maptype) {
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NOMAP:
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i]
179879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				= ((STRUCT_COUNTERS){ 0, 0 });
1799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NORMAL_MAP:
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: X + Y + Z.
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in X + Y
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in replacement read.
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i] = repl->counters[mappos];
1810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_ZEROED:
1813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: Y + Z.
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in Y.
1818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in (replacement read - original read).
1819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			subtract_counters(&newcounters->counters[i],
1821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &repl->counters[mappos],
1822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &index2entry(*handle, i)->counters);
1823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
18241cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
18251cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		case COUNTER_MAP_SET:
18261cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			/* Want to set counter (iptables-restore) */
18271cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
18281cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			memcpy(&newcounters->counters[i],
18291cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			       &index2entry(*handle, i)->counters,
18301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			       sizeof(STRUCT_COUNTERS));
18311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
18321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			break;
1833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
183562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell
183662527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#ifdef KERNEL_64_USERSPACE_32
183762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell	{
183862527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		/* Kernel will think that pointer should be 64-bits, and get
183962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   padding.  So we accomodate here (assumption: alignment of
184062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   `counters' is on 64-bit boundary). */
184162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
184262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		if ((unsigned long)&newcounters->counters % 8 != 0) {
184362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			fprintf(stderr,
184462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell				"counters alignment incorrect! Mail rusty!\n");
184562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			abort();
184662527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		}
184762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		*kernptr = newcounters->counters;
184854c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	}
184962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#endif /* KERNEL_64_USERSPACE_32 */
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
185179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
185279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		       newcounters, counterlen) < 0) {
1853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
1864841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	TC_FREE(handle);
1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
1869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
187079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_RAW_SOCKET()
1871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
1873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
1876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
187779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_STRERROR(int err)
1878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
1881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
1882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
1884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
18854ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	  { { TC_INIT, EPERM, "Permission denied (you must be root)" },
188679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INIT, EINVAL, "Module is wrong version" },
18874ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_INIT, ENOENT,
18884ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte		    "Table does not exist (do you need to insmod?)" },
188979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
189079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
189179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EMLINK,
1892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
189379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
189479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
189579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
189679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
18971cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
18981cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
189979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
190079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, EINVAL, "Target problem" },
1901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
190279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CHECK_PACKET, EINVAL,
1903c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
19044ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_CHECK_PACKET, ENOSYS,
19054ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	      "Checking will most likely never get implemented" },
1906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
190779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_ENTRY, ENOENT,
1908c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
190979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, ENOENT,
1910c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
191179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, EINVAL,
1912c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
19134ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte
19144ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, 0, "Incompatible with this kernel" },
19154ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
19164ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
19174ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
19184ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOENT, "No chain/target/match by that name" },
1919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
1920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
1923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
1924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
1925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
1928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1929