Blame view

net/netfilter/x_tables.c 32.5 KB
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * x_tables core - Backend for {ip,ip6,arp}_tables
   *
   * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
   *
   * Based on existing ip_tables code which is
   *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
   *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   */
be91fd5e3   Jan Engelhardt   netfilter: xtable...
15
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
16
  #include <linux/kernel.h>
3a9a231d9   Paul Gortmaker   net: Fix files ex...
17
  #include <linux/module.h>
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
18
19
20
21
22
23
  #include <linux/socket.h>
  #include <linux/net.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/string.h>
  #include <linux/vmalloc.h>
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
24
  #include <linux/mutex.h>
d7fe0f241   Al Viro   [PATCH] severing ...
25
  #include <linux/mm.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
26
  #include <linux/slab.h>
fbabf31e4   Thomas Graf   netfilter: create...
27
  #include <linux/audit.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
28
  #include <net/net_namespace.h>
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
29
30
31
  
  #include <linux/netfilter/x_tables.h>
  #include <linux/netfilter_arp.h>
e3eaa9910   Jan Engelhardt   netfilter: xtable...
32
33
34
  #include <linux/netfilter_ipv4/ip_tables.h>
  #include <linux/netfilter_ipv6/ip6_tables.h>
  #include <linux/netfilter_arp/arp_tables.h>
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
35

2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
36
37
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
043ef46c7   Jan Engelhardt   netfilter: move E...
38
  MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
39
40
  
  #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
41
  struct compat_delta {
255d0dc34   Eric Dumazet   netfilter: x_tabl...
42
43
  	unsigned int offset; /* offset in kernel */
  	int delta; /* delta in 32bit user land */
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
44
  };
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
45
  struct xt_af {
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
46
  	struct mutex mutex;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
47
48
  	struct list_head match;
  	struct list_head target;
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
49
  #ifdef CONFIG_COMPAT
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
50
  	struct mutex compat_mutex;
255d0dc34   Eric Dumazet   netfilter: x_tabl...
51
52
53
  	struct compat_delta *compat_tab;
  	unsigned int number; /* number of slots in compat_tab[] */
  	unsigned int cur; /* number of used slots in compat_tab[] */
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
54
  #endif
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
55
56
57
  };
  
  static struct xt_af *xt;
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
58
59
60
61
62
63
  static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
  	[NFPROTO_UNSPEC] = "x",
  	[NFPROTO_IPV4]   = "ip",
  	[NFPROTO_ARP]    = "arp",
  	[NFPROTO_BRIDGE] = "eb",
  	[NFPROTO_IPV6]   = "ip6",
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
64
  };
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
65
66
  /* Allow this many total (re)entries. */
  static const unsigned int xt_jumpstack_multiplier = 2;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
67
68
  /* Registration hooks for targets. */
  int
a45049c51   Pablo Neira Ayuso   [NETFILTER]: x_ta...
69
  xt_register_target(struct xt_target *target)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
70
  {
76108cea0   Jan Engelhardt   netfilter: Use un...
71
72
  	u_int8_t af = target->family;
  	int ret;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
73

9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
74
  	ret = mutex_lock_interruptible(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
75
76
77
  	if (ret != 0)
  		return ret;
  	list_add(&target->list, &xt[af].target);
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
78
  	mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
79
80
81
82
83
  	return ret;
  }
  EXPORT_SYMBOL(xt_register_target);
  
  void
a45049c51   Pablo Neira Ayuso   [NETFILTER]: x_ta...
84
  xt_unregister_target(struct xt_target *target)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
85
  {
76108cea0   Jan Engelhardt   netfilter: Use un...
86
  	u_int8_t af = target->family;
a45049c51   Pablo Neira Ayuso   [NETFILTER]: x_ta...
87

9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
88
  	mutex_lock(&xt[af].mutex);
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
89
  	list_del(&target->list);
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
90
  	mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
91
92
93
94
  }
  EXPORT_SYMBOL(xt_unregister_target);
  
  int
52d9c42ef   Patrick McHardy   [NETFILTER]: x_ta...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  xt_register_targets(struct xt_target *target, unsigned int n)
  {
  	unsigned int i;
  	int err = 0;
  
  	for (i = 0; i < n; i++) {
  		err = xt_register_target(&target[i]);
  		if (err)
  			goto err;
  	}
  	return err;
  
  err:
  	if (i > 0)
  		xt_unregister_targets(target, i);
  	return err;
  }
  EXPORT_SYMBOL(xt_register_targets);
  
  void
  xt_unregister_targets(struct xt_target *target, unsigned int n)
  {
f68c53015   Changli Gao   netfilter: unregi...
117
118
  	while (n-- > 0)
  		xt_unregister_target(&target[n]);
52d9c42ef   Patrick McHardy   [NETFILTER]: x_ta...
119
120
121
122
  }
  EXPORT_SYMBOL(xt_unregister_targets);
  
  int
a45049c51   Pablo Neira Ayuso   [NETFILTER]: x_ta...
123
  xt_register_match(struct xt_match *match)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
124
  {
76108cea0   Jan Engelhardt   netfilter: Use un...
125
126
  	u_int8_t af = match->family;
  	int ret;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
127

9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
128
  	ret = mutex_lock_interruptible(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
129
130
131
132
  	if (ret != 0)
  		return ret;
  
  	list_add(&match->list, &xt[af].match);
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
133
  	mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
134
135
136
137
138
139
  
  	return ret;
  }
  EXPORT_SYMBOL(xt_register_match);
  
  void
a45049c51   Pablo Neira Ayuso   [NETFILTER]: x_ta...
140
  xt_unregister_match(struct xt_match *match)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
141
  {
76108cea0   Jan Engelhardt   netfilter: Use un...
142
  	u_int8_t af = match->family;
a45049c51   Pablo Neira Ayuso   [NETFILTER]: x_ta...
143

9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
144
  	mutex_lock(&xt[af].mutex);
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
145
  	list_del(&match->list);
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
146
  	mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
147
148
  }
  EXPORT_SYMBOL(xt_unregister_match);
52d9c42ef   Patrick McHardy   [NETFILTER]: x_ta...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  int
  xt_register_matches(struct xt_match *match, unsigned int n)
  {
  	unsigned int i;
  	int err = 0;
  
  	for (i = 0; i < n; i++) {
  		err = xt_register_match(&match[i]);
  		if (err)
  			goto err;
  	}
  	return err;
  
  err:
  	if (i > 0)
  		xt_unregister_matches(match, i);
  	return err;
  }
  EXPORT_SYMBOL(xt_register_matches);
  
  void
  xt_unregister_matches(struct xt_match *match, unsigned int n)
  {
f68c53015   Changli Gao   netfilter: unregi...
172
173
  	while (n-- > 0)
  		xt_unregister_match(&match[n]);
52d9c42ef   Patrick McHardy   [NETFILTER]: x_ta...
174
175
  }
  EXPORT_SYMBOL(xt_unregister_matches);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
176
177
178
179
  
  /*
   * These are weird, but module loading must not be done with mutex
   * held (since they will register), and we have to have a single
adb00ae2e   Stephen Hemminger   netfilter: x_tabl...
180
   * function to use.
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
181
182
183
   */
  
  /* Find match, grabs ref.  Returns ERR_PTR() on error. */
76108cea0   Jan Engelhardt   netfilter: Use un...
184
  struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
185
186
  {
  	struct xt_match *m;
42046e2e4   Patrick McHardy   netfilter: x_tabl...
187
  	int err = -ENOENT;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
188

9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
189
  	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
190
191
192
193
194
195
  		return ERR_PTR(-EINTR);
  
  	list_for_each_entry(m, &xt[af].match, list) {
  		if (strcmp(m->name, name) == 0) {
  			if (m->revision == revision) {
  				if (try_module_get(m->me)) {
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
196
  					mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
197
198
199
200
201
202
  					return m;
  				}
  			} else
  				err = -EPROTOTYPE; /* Found something. */
  		}
  	}
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
203
  	mutex_unlock(&xt[af].mutex);
55b69e910   Jan Engelhardt   netfilter: implem...
204
205
206
207
  
  	if (af != NFPROTO_UNSPEC)
  		/* Try searching again in the family-independent list */
  		return xt_find_match(NFPROTO_UNSPEC, name, revision);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
208
209
210
  	return ERR_PTR(err);
  }
  EXPORT_SYMBOL(xt_find_match);
fd0ec0e62   Jan Engelhardt   netfilter: xtable...
211
212
213
214
  struct xt_match *
  xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
  {
  	struct xt_match *match;
adb00ae2e   Stephen Hemminger   netfilter: x_tabl...
215
216
217
218
219
220
221
  	match = xt_find_match(nfproto, name, revision);
  	if (IS_ERR(match)) {
  		request_module("%st_%s", xt_prefix[nfproto], name);
  		match = xt_find_match(nfproto, name, revision);
  	}
  
  	return match;
fd0ec0e62   Jan Engelhardt   netfilter: xtable...
222
223
  }
  EXPORT_SYMBOL_GPL(xt_request_find_match);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
224
  /* Find target, grabs ref.  Returns ERR_PTR() on error. */
76108cea0   Jan Engelhardt   netfilter: Use un...
225
  struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
226
227
  {
  	struct xt_target *t;
42046e2e4   Patrick McHardy   netfilter: x_tabl...
228
  	int err = -ENOENT;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
229

9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
230
  	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
231
232
233
234
235
236
  		return ERR_PTR(-EINTR);
  
  	list_for_each_entry(t, &xt[af].target, list) {
  		if (strcmp(t->name, name) == 0) {
  			if (t->revision == revision) {
  				if (try_module_get(t->me)) {
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
237
  					mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
238
239
240
241
242
243
  					return t;
  				}
  			} else
  				err = -EPROTOTYPE; /* Found something. */
  		}
  	}
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
244
  	mutex_unlock(&xt[af].mutex);
55b69e910   Jan Engelhardt   netfilter: implem...
245
246
247
248
  
  	if (af != NFPROTO_UNSPEC)
  		/* Try searching again in the family-independent list */
  		return xt_find_target(NFPROTO_UNSPEC, name, revision);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
249
250
251
  	return ERR_PTR(err);
  }
  EXPORT_SYMBOL(xt_find_target);
76108cea0   Jan Engelhardt   netfilter: Use un...
252
  struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
253
254
  {
  	struct xt_target *target;
adb00ae2e   Stephen Hemminger   netfilter: x_tabl...
255
256
257
258
259
260
261
  	target = xt_find_target(af, name, revision);
  	if (IS_ERR(target)) {
  		request_module("%st_%s", xt_prefix[af], name);
  		target = xt_find_target(af, name, revision);
  	}
  
  	return target;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
262
263
  }
  EXPORT_SYMBOL_GPL(xt_request_find_target);
76108cea0   Jan Engelhardt   netfilter: Use un...
264
  static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
265
  {
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
266
  	const struct xt_match *m;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
267
268
269
270
271
272
273
274
275
276
  	int have_rev = 0;
  
  	list_for_each_entry(m, &xt[af].match, list) {
  		if (strcmp(m->name, name) == 0) {
  			if (m->revision > *bestp)
  				*bestp = m->revision;
  			if (m->revision == revision)
  				have_rev = 1;
  		}
  	}
656caff20   Patrick McHardy   netfilter 04/09: ...
277
278
279
  
  	if (af != NFPROTO_UNSPEC && !have_rev)
  		return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
280
281
  	return have_rev;
  }
76108cea0   Jan Engelhardt   netfilter: Use un...
282
  static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
283
  {
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
284
  	const struct xt_target *t;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
285
286
287
288
289
290
291
292
293
294
  	int have_rev = 0;
  
  	list_for_each_entry(t, &xt[af].target, list) {
  		if (strcmp(t->name, name) == 0) {
  			if (t->revision > *bestp)
  				*bestp = t->revision;
  			if (t->revision == revision)
  				have_rev = 1;
  		}
  	}
656caff20   Patrick McHardy   netfilter 04/09: ...
295
296
297
  
  	if (af != NFPROTO_UNSPEC && !have_rev)
  		return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
298
299
300
301
  	return have_rev;
  }
  
  /* Returns true or false (if no such extension at all) */
76108cea0   Jan Engelhardt   netfilter: Use un...
302
  int xt_find_revision(u8 af, const char *name, u8 revision, int target,
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
303
304
305
  		     int *err)
  {
  	int have_rev, best = -1;
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
306
  	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
307
308
309
310
311
312
313
  		*err = -EINTR;
  		return 1;
  	}
  	if (target == 1)
  		have_rev = target_revfn(af, name, revision, &best);
  	else
  		have_rev = match_revfn(af, name, revision, &best);
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
314
  	mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
315
316
317
318
319
320
321
322
323
324
325
326
327
  
  	/* Nothing at all?  Return 0 to try loading module. */
  	if (best == -1) {
  		*err = -ENOENT;
  		return 0;
  	}
  
  	*err = best;
  	if (!have_rev)
  		*err = -EPROTONOSUPPORT;
  	return 1;
  }
  EXPORT_SYMBOL_GPL(xt_find_revision);
451853645   Jan Engelhardt   netfilter: xtable...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  static char *textify_hooks(char *buf, size_t size, unsigned int mask)
  {
  	static const char *const names[] = {
  		"PREROUTING", "INPUT", "FORWARD",
  		"OUTPUT", "POSTROUTING", "BROUTING",
  	};
  	unsigned int i;
  	char *p = buf;
  	bool np = false;
  	int res;
  
  	*p = '\0';
  	for (i = 0; i < ARRAY_SIZE(names); ++i) {
  		if (!(mask & (1 << i)))
  			continue;
  		res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]);
  		if (res > 0) {
  			size -= res;
  			p += res;
  		}
  		np = true;
  	}
  
  	return buf;
  }
916a917df   Jan Engelhardt   netfilter: xtable...
353
  int xt_check_match(struct xt_mtchk_param *par,
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
354
  		   unsigned int size, u_int8_t proto, bool inv_proto)
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
355
  {
bd414ee60   Jan Engelhardt   netfilter: xtable...
356
  	int ret;
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
357
358
  	if (XT_ALIGN(par->match->matchsize) != size &&
  	    par->match->matchsize != -1) {
043ef46c7   Jan Engelhardt   netfilter: move E...
359
360
361
362
  		/*
  		 * ebt_among is exempt from centralized matchsize checking
  		 * because it uses a dynamic-size data set.
  		 */
b402405d7   Jan Engelhardt   netfilter: xtable...
363
364
365
  		pr_err("%s_tables: %s.%u match: invalid size "
  		       "%u (kernel) != (user) %u
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
366
  		       xt_prefix[par->family], par->match->name,
b402405d7   Jan Engelhardt   netfilter: xtable...
367
  		       par->match->revision,
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
368
  		       XT_ALIGN(par->match->matchsize), size);
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
369
370
  		return -EINVAL;
  	}
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
371
372
  	if (par->match->table != NULL &&
  	    strcmp(par->match->table, par->table) != 0) {
3dd5d7e3b   Joe Perches   x_tables: Convert...
373
374
  		pr_err("%s_tables: %s match: only valid in %s table, not %s
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
375
  		       xt_prefix[par->family], par->match->name,
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
376
  		       par->match->table, par->table);
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
377
378
  		return -EINVAL;
  	}
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
379
  	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
451853645   Jan Engelhardt   netfilter: xtable...
380
  		char used[64], allow[64];
3dd5d7e3b   Joe Perches   x_tables: Convert...
381
  		pr_err("%s_tables: %s match: used from hooks %s, but only "
451853645   Jan Engelhardt   netfilter: xtable...
382
383
  		       "valid from %s
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
384
  		       xt_prefix[par->family], par->match->name,
451853645   Jan Engelhardt   netfilter: xtable...
385
386
  		       textify_hooks(used, sizeof(used), par->hook_mask),
  		       textify_hooks(allow, sizeof(allow), par->match->hooks));
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
387
388
  		return -EINVAL;
  	}
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
389
  	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
3dd5d7e3b   Joe Perches   x_tables: Convert...
390
391
  		pr_err("%s_tables: %s match: only valid for protocol %u
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
392
393
  		       xt_prefix[par->family], par->match->name,
  		       par->match->proto);
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
394
395
  		return -EINVAL;
  	}
bd414ee60   Jan Engelhardt   netfilter: xtable...
396
397
398
399
400
401
402
403
  	if (par->match->checkentry != NULL) {
  		ret = par->match->checkentry(par);
  		if (ret < 0)
  			return ret;
  		else if (ret > 0)
  			/* Flag up potential errors. */
  			return -EIO;
  	}
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
404
405
406
  	return 0;
  }
  EXPORT_SYMBOL_GPL(xt_check_match);
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
407
  #ifdef CONFIG_COMPAT
255d0dc34   Eric Dumazet   netfilter: x_tabl...
408
  int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
409
  {
255d0dc34   Eric Dumazet   netfilter: x_tabl...
410
  	struct xt_af *xp = &xt[af];
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
411

255d0dc34   Eric Dumazet   netfilter: x_tabl...
412
413
414
415
416
417
418
419
  	if (!xp->compat_tab) {
  		if (!xp->number)
  			return -EINVAL;
  		xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number);
  		if (!xp->compat_tab)
  			return -ENOMEM;
  		xp->cur = 0;
  	}
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
420

255d0dc34   Eric Dumazet   netfilter: x_tabl...
421
422
  	if (xp->cur >= xp->number)
  		return -EINVAL;
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
423

255d0dc34   Eric Dumazet   netfilter: x_tabl...
424
425
426
427
428
  	if (xp->cur)
  		delta += xp->compat_tab[xp->cur - 1].delta;
  	xp->compat_tab[xp->cur].offset = offset;
  	xp->compat_tab[xp->cur].delta = delta;
  	xp->cur++;
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
429
430
431
  	return 0;
  }
  EXPORT_SYMBOL_GPL(xt_compat_add_offset);
76108cea0   Jan Engelhardt   netfilter: Use un...
432
  void xt_compat_flush_offsets(u_int8_t af)
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
433
  {
255d0dc34   Eric Dumazet   netfilter: x_tabl...
434
435
436
437
  	if (xt[af].compat_tab) {
  		vfree(xt[af].compat_tab);
  		xt[af].compat_tab = NULL;
  		xt[af].number = 0;
5a6351eec   Eric Dumazet   netfilter: fix eb...
438
  		xt[af].cur = 0;
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
439
440
441
  	}
  }
  EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
3e5e524ff   Florian Westphal   netfilter: CONFIG...
442
  int xt_compat_calc_jump(u_int8_t af, unsigned int offset)
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
443
  {
255d0dc34   Eric Dumazet   netfilter: x_tabl...
444
445
446
447
448
449
450
451
452
453
454
455
  	struct compat_delta *tmp = xt[af].compat_tab;
  	int mid, left = 0, right = xt[af].cur - 1;
  
  	while (left <= right) {
  		mid = (left + right) >> 1;
  		if (offset > tmp[mid].offset)
  			left = mid + 1;
  		else if (offset < tmp[mid].offset)
  			right = mid - 1;
  		else
  			return mid ? tmp[mid - 1].delta : 0;
  	}
5a6351eec   Eric Dumazet   netfilter: fix eb...
456
  	return left ? tmp[left - 1].delta : 0;
b386d9f59   Patrick McHardy   [NETFILTER]: ip_t...
457
458
  }
  EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
255d0dc34   Eric Dumazet   netfilter: x_tabl...
459
460
461
462
463
464
  void xt_compat_init_offsets(u_int8_t af, unsigned int number)
  {
  	xt[af].number = number;
  	xt[af].cur = 0;
  }
  EXPORT_SYMBOL(xt_compat_init_offsets);
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
465
  int xt_compat_match_offset(const struct xt_match *match)
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
466
  {
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
467
468
469
470
  	u_int16_t csize = match->compatsize ? : match->matchsize;
  	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
  }
  EXPORT_SYMBOL_GPL(xt_compat_match_offset);
895669513   Patrick McHardy   [NETFILTER]: x_ta...
471
  int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
b0a6363c2   Patrick McHardy   [NETFILTER]: {ip,...
472
  			      unsigned int *size)
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
473
  {
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
474
  	const struct xt_match *match = m->u.kernel.match;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
  	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
  	int pad, off = xt_compat_match_offset(match);
  	u_int16_t msize = cm->u.user.match_size;
  
  	m = *dstptr;
  	memcpy(m, cm, sizeof(*cm));
  	if (match->compat_from_user)
  		match->compat_from_user(m->data, cm->data);
  	else
  		memcpy(m->data, cm->data, msize - sizeof(*cm));
  	pad = XT_ALIGN(match->matchsize) - match->matchsize;
  	if (pad > 0)
  		memset(m->data + match->matchsize, 0, pad);
  
  	msize += off;
  	m->u.user.match_size = msize;
  
  	*size += off;
  	*dstptr += msize;
895669513   Patrick McHardy   [NETFILTER]: x_ta...
494
  	return 0;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
495
496
  }
  EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
739674fb7   Jan Engelhardt   netfilter: xtable...
497
498
  int xt_compat_match_to_user(const struct xt_entry_match *m,
  			    void __user **dstptr, unsigned int *size)
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
499
  {
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
500
  	const struct xt_match *match = m->u.kernel.match;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
501
502
503
504
505
  	struct compat_xt_entry_match __user *cm = *dstptr;
  	int off = xt_compat_match_offset(match);
  	u_int16_t msize = m->u.user.match_size - off;
  
  	if (copy_to_user(cm, m, sizeof(*cm)) ||
a18aa31b7   Patrick McHardy   [NETFILTER]: ip_t...
506
507
508
  	    put_user(msize, &cm->u.user.match_size) ||
  	    copy_to_user(cm->u.user.name, m->u.kernel.match->name,
  			 strlen(m->u.kernel.match->name) + 1))
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
509
  		return -EFAULT;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
510
511
512
513
514
515
516
  
  	if (match->compat_to_user) {
  		if (match->compat_to_user((void __user *)cm->data, m->data))
  			return -EFAULT;
  	} else {
  		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
  			return -EFAULT;
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
517
  	}
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
518
519
520
521
  
  	*size -= off;
  	*dstptr += msize;
  	return 0;
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
522
  }
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
523
524
  EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
  #endif /* CONFIG_COMPAT */
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
525

916a917df   Jan Engelhardt   netfilter: xtable...
526
  int xt_check_target(struct xt_tgchk_param *par,
af5d6dc20   Jan Engelhardt   netfilter: xtable...
527
  		    unsigned int size, u_int8_t proto, bool inv_proto)
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
528
  {
d6b00a534   Jan Engelhardt   netfilter: xtable...
529
  	int ret;
af5d6dc20   Jan Engelhardt   netfilter: xtable...
530
  	if (XT_ALIGN(par->target->targetsize) != size) {
b402405d7   Jan Engelhardt   netfilter: xtable...
531
532
533
  		pr_err("%s_tables: %s.%u target: invalid size "
  		       "%u (kernel) != (user) %u
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
534
  		       xt_prefix[par->family], par->target->name,
b402405d7   Jan Engelhardt   netfilter: xtable...
535
  		       par->target->revision,
af5d6dc20   Jan Engelhardt   netfilter: xtable...
536
  		       XT_ALIGN(par->target->targetsize), size);
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
537
538
  		return -EINVAL;
  	}
af5d6dc20   Jan Engelhardt   netfilter: xtable...
539
540
  	if (par->target->table != NULL &&
  	    strcmp(par->target->table, par->table) != 0) {
3dd5d7e3b   Joe Perches   x_tables: Convert...
541
542
  		pr_err("%s_tables: %s target: only valid in %s table, not %s
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
543
  		       xt_prefix[par->family], par->target->name,
af5d6dc20   Jan Engelhardt   netfilter: xtable...
544
  		       par->target->table, par->table);
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
545
546
  		return -EINVAL;
  	}
af5d6dc20   Jan Engelhardt   netfilter: xtable...
547
  	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
451853645   Jan Engelhardt   netfilter: xtable...
548
  		char used[64], allow[64];
3dd5d7e3b   Joe Perches   x_tables: Convert...
549
  		pr_err("%s_tables: %s target: used from hooks %s, but only "
451853645   Jan Engelhardt   netfilter: xtable...
550
551
  		       "usable from %s
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
552
  		       xt_prefix[par->family], par->target->name,
451853645   Jan Engelhardt   netfilter: xtable...
553
554
  		       textify_hooks(used, sizeof(used), par->hook_mask),
  		       textify_hooks(allow, sizeof(allow), par->target->hooks));
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
555
556
  		return -EINVAL;
  	}
af5d6dc20   Jan Engelhardt   netfilter: xtable...
557
  	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
3dd5d7e3b   Joe Perches   x_tables: Convert...
558
559
  		pr_err("%s_tables: %s target: only valid for protocol %u
  ",
916a917df   Jan Engelhardt   netfilter: xtable...
560
  		       xt_prefix[par->family], par->target->name,
af5d6dc20   Jan Engelhardt   netfilter: xtable...
561
  		       par->target->proto);
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
562
563
  		return -EINVAL;
  	}
d6b00a534   Jan Engelhardt   netfilter: xtable...
564
565
566
567
568
569
570
571
  	if (par->target->checkentry != NULL) {
  		ret = par->target->checkentry(par);
  		if (ret < 0)
  			return ret;
  		else if (ret > 0)
  			/* Flag up potential errors. */
  			return -EIO;
  	}
37f9f7334   Patrick McHardy   [NETFILTER]: xt_t...
572
573
574
  	return 0;
  }
  EXPORT_SYMBOL_GPL(xt_check_target);
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
575
  #ifdef CONFIG_COMPAT
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
576
  int xt_compat_target_offset(const struct xt_target *target)
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
577
  {
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
578
579
580
581
582
583
  	u_int16_t csize = target->compatsize ? : target->targetsize;
  	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
  }
  EXPORT_SYMBOL_GPL(xt_compat_target_offset);
  
  void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
b0a6363c2   Patrick McHardy   [NETFILTER]: {ip,...
584
  				unsigned int *size)
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
585
  {
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
586
  	const struct xt_target *target = t->u.kernel.target;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
  	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
  	int pad, off = xt_compat_target_offset(target);
  	u_int16_t tsize = ct->u.user.target_size;
  
  	t = *dstptr;
  	memcpy(t, ct, sizeof(*ct));
  	if (target->compat_from_user)
  		target->compat_from_user(t->data, ct->data);
  	else
  		memcpy(t->data, ct->data, tsize - sizeof(*ct));
  	pad = XT_ALIGN(target->targetsize) - target->targetsize;
  	if (pad > 0)
  		memset(t->data + target->targetsize, 0, pad);
  
  	tsize += off;
  	t->u.user.target_size = tsize;
  
  	*size += off;
  	*dstptr += tsize;
  }
  EXPORT_SYMBOL_GPL(xt_compat_target_from_user);
739674fb7   Jan Engelhardt   netfilter: xtable...
608
609
  int xt_compat_target_to_user(const struct xt_entry_target *t,
  			     void __user **dstptr, unsigned int *size)
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
610
  {
5452e425a   Jan Engelhardt   [NETFILTER]: anno...
611
  	const struct xt_target *target = t->u.kernel.target;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
612
613
614
615
616
  	struct compat_xt_entry_target __user *ct = *dstptr;
  	int off = xt_compat_target_offset(target);
  	u_int16_t tsize = t->u.user.target_size - off;
  
  	if (copy_to_user(ct, t, sizeof(*ct)) ||
a18aa31b7   Patrick McHardy   [NETFILTER]: ip_t...
617
618
619
  	    put_user(tsize, &ct->u.user.target_size) ||
  	    copy_to_user(ct->u.user.name, t->u.kernel.target->name,
  			 strlen(t->u.kernel.target->name) + 1))
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
620
  		return -EFAULT;
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
621
622
623
624
625
626
627
  
  	if (target->compat_to_user) {
  		if (target->compat_to_user((void __user *)ct->data, t->data))
  			return -EFAULT;
  	} else {
  		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
  			return -EFAULT;
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
628
  	}
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
629
630
631
632
  
  	*size -= off;
  	*dstptr += tsize;
  	return 0;
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
633
  }
9fa492cdc   Patrick McHardy   [NETFILTER]: x_ta...
634
  EXPORT_SYMBOL_GPL(xt_compat_target_to_user);
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
635
  #endif
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
636
637
638
639
640
641
  struct xt_table_info *xt_alloc_table_info(unsigned int size)
  {
  	struct xt_table_info *newinfo;
  	int cpu;
  
  	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
4481374ce   Jan Beulich   mm: replace vario...
642
  	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
643
  		return NULL;
259d4e41f   Eric Dumazet   [NETFILTER]: x_ta...
644
  	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
645
646
647
648
  	if (!newinfo)
  		return NULL;
  
  	newinfo->size = size;
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
649
  	for_each_possible_cpu(cpu) {
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  		if (size <= PAGE_SIZE)
  			newinfo->entries[cpu] = kmalloc_node(size,
  							GFP_KERNEL,
  							cpu_to_node(cpu));
  		else
  			newinfo->entries[cpu] = vmalloc_node(size,
  							cpu_to_node(cpu));
  
  		if (newinfo->entries[cpu] == NULL) {
  			xt_free_table_info(newinfo);
  			return NULL;
  		}
  	}
  
  	return newinfo;
  }
  EXPORT_SYMBOL(xt_alloc_table_info);
  
  void xt_free_table_info(struct xt_table_info *info)
  {
  	int cpu;
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
671
  	for_each_possible_cpu(cpu) {
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
672
673
674
675
676
  		if (info->size <= PAGE_SIZE)
  			kfree(info->entries[cpu]);
  		else
  			vfree(info->entries[cpu]);
  	}
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  
  	if (info->jumpstack != NULL) {
  		if (sizeof(void *) * info->stacksize > PAGE_SIZE) {
  			for_each_possible_cpu(cpu)
  				vfree(info->jumpstack[cpu]);
  		} else {
  			for_each_possible_cpu(cpu)
  				kfree(info->jumpstack[cpu]);
  		}
  	}
  
  	if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE)
  		vfree(info->jumpstack);
  	else
  		kfree(info->jumpstack);
7489aec8e   Eric Dumazet   netfilter: xtable...
692
693
  
  	free_percpu(info->stackptr);
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
694

2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
695
696
697
698
699
  	kfree(info);
  }
  EXPORT_SYMBOL(xt_free_table_info);
  
  /* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
76108cea0   Jan Engelhardt   netfilter: Use un...
700
701
  struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
  				    const char *name)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
702
703
  {
  	struct xt_table *t;
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
704
  	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
705
  		return ERR_PTR(-EINTR);
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
706
  	list_for_each_entry(t, &net->xt.tables[af], list)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
707
708
  		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
  			return t;
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
709
  	mutex_unlock(&xt[af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
710
711
712
713
714
715
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(xt_find_table_lock);
  
  void xt_table_unlock(struct xt_table *table)
  {
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
716
  	mutex_unlock(&xt[table->af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
717
718
  }
  EXPORT_SYMBOL_GPL(xt_table_unlock);
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
719
  #ifdef CONFIG_COMPAT
76108cea0   Jan Engelhardt   netfilter: Use un...
720
  void xt_compat_lock(u_int8_t af)
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
721
722
723
724
  {
  	mutex_lock(&xt[af].compat_mutex);
  }
  EXPORT_SYMBOL_GPL(xt_compat_lock);
76108cea0   Jan Engelhardt   netfilter: Use un...
725
  void xt_compat_unlock(u_int8_t af)
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
726
727
728
729
730
  {
  	mutex_unlock(&xt[af].compat_mutex);
  }
  EXPORT_SYMBOL_GPL(xt_compat_unlock);
  #endif
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
731

7f5c6d4f6   Eric Dumazet   netfilter: get ri...
732
733
  DEFINE_PER_CPU(seqcount_t, xt_recseq);
  EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq);
942e4a2bd   Stephen Hemminger   netfilter: revise...
734

f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
735
736
737
738
  static int xt_jumpstack_alloc(struct xt_table_info *i)
  {
  	unsigned int size;
  	int cpu;
7489aec8e   Eric Dumazet   netfilter: xtable...
739
  	i->stackptr = alloc_percpu(unsigned int);
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
740
741
  	if (i->stackptr == NULL)
  		return -ENOMEM;
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
742
743
744
  
  	size = sizeof(void **) * nr_cpu_ids;
  	if (size > PAGE_SIZE)
3dbd44398   Joe Perches   net: Convert vmal...
745
  		i->jumpstack = vzalloc(size);
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
746
  	else
3dbd44398   Joe Perches   net: Convert vmal...
747
  		i->jumpstack = kzalloc(size, GFP_KERNEL);
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
748
749
  	if (i->jumpstack == NULL)
  		return -ENOMEM;
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  
  	i->stacksize *= xt_jumpstack_multiplier;
  	size = sizeof(void *) * i->stacksize;
  	for_each_possible_cpu(cpu) {
  		if (size > PAGE_SIZE)
  			i->jumpstack[cpu] = vmalloc_node(size,
  				cpu_to_node(cpu));
  		else
  			i->jumpstack[cpu] = kmalloc_node(size,
  				GFP_KERNEL, cpu_to_node(cpu));
  		if (i->jumpstack[cpu] == NULL)
  			/*
  			 * Freeing will be done later on by the callers. The
  			 * chain is: xt_replace_table -> __do_replace ->
  			 * do_replace -> xt_free_table_info.
  			 */
  			return -ENOMEM;
  	}
  
  	return 0;
  }
942e4a2bd   Stephen Hemminger   netfilter: revise...
771

2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
772
773
774
775
776
777
  struct xt_table_info *
  xt_replace_table(struct xt_table *table,
  	      unsigned int num_counters,
  	      struct xt_table_info *newinfo,
  	      int *error)
  {
942e4a2bd   Stephen Hemminger   netfilter: revise...
778
  	struct xt_table_info *private;
f3c5c1bfd   Jan Engelhardt   netfilter: xtable...
779
  	int ret;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
780

d97a9e47b   Jan Engelhardt   netfilter: x_tabl...
781
782
783
784
785
  	ret = xt_jumpstack_alloc(newinfo);
  	if (ret < 0) {
  		*error = ret;
  		return NULL;
  	}
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
786
  	/* Do the substitution. */
942e4a2bd   Stephen Hemminger   netfilter: revise...
787
  	local_bh_disable();
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
788
  	private = table->private;
942e4a2bd   Stephen Hemminger   netfilter: revise...
789

2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
790
791
  	/* Check inside lock: is the old number correct? */
  	if (num_counters != private->number) {
be91fd5e3   Jan Engelhardt   netfilter: xtable...
792
793
  		pr_debug("num_counters != table->private->number (%u/%u)
  ",
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
794
  			 num_counters, private->number);
942e4a2bd   Stephen Hemminger   netfilter: revise...
795
  		local_bh_enable();
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
796
797
798
  		*error = -EAGAIN;
  		return NULL;
  	}
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
799

942e4a2bd   Stephen Hemminger   netfilter: revise...
800
801
802
803
804
805
806
807
808
809
  	table->private = newinfo;
  	newinfo->initial_entries = private->initial_entries;
  
  	/*
  	 * Even though table entries have now been swapped, other CPU's
  	 * may still be using the old entries. This is okay, because
  	 * resynchronization happens because of the locking done
  	 * during the get_counters() routine.
  	 */
  	local_bh_enable();
fbabf31e4   Thomas Graf   netfilter: create...
810
811
812
813
814
815
816
817
818
819
820
821
822
823
  #ifdef CONFIG_AUDIT
  	if (audit_enabled) {
  		struct audit_buffer *ab;
  
  		ab = audit_log_start(current->audit_context, GFP_KERNEL,
  				     AUDIT_NETFILTER_CFG);
  		if (ab) {
  			audit_log_format(ab, "table=%s family=%u entries=%u",
  					 table->name, table->af,
  					 private->number);
  			audit_log_end(ab);
  		}
  	}
  #endif
942e4a2bd   Stephen Hemminger   netfilter: revise...
824
  	return private;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
825
826
  }
  EXPORT_SYMBOL_GPL(xt_replace_table);
35aad0ffd   Jan Engelhardt   netfilter: xtable...
827
828
  struct xt_table *xt_register_table(struct net *net,
  				   const struct xt_table *input_table,
a98da11d8   Alexey Dobriyan   [NETFILTER]: x_ta...
829
830
  				   struct xt_table_info *bootstrap,
  				   struct xt_table_info *newinfo)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
831
832
833
  {
  	int ret;
  	struct xt_table_info *private;
35aad0ffd   Jan Engelhardt   netfilter: xtable...
834
  	struct xt_table *t, *table;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
835

44d34e721   Alexey Dobriyan   [NETFILTER]: x_ta...
836
  	/* Don't add one object to multiple lists. */
35aad0ffd   Jan Engelhardt   netfilter: xtable...
837
  	table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
44d34e721   Alexey Dobriyan   [NETFILTER]: x_ta...
838
839
840
841
  	if (!table) {
  		ret = -ENOMEM;
  		goto out;
  	}
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
842
  	ret = mutex_lock_interruptible(&xt[table->af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
843
  	if (ret != 0)
44d34e721   Alexey Dobriyan   [NETFILTER]: x_ta...
844
  		goto out_free;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
845
846
  
  	/* Don't autoload: we'd eat our tail... */
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
847
  	list_for_each_entry(t, &net->xt.tables[table->af], list) {
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
848
849
850
851
  		if (strcmp(t->name, table->name) == 0) {
  			ret = -EEXIST;
  			goto unlock;
  		}
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
852
853
854
855
  	}
  
  	/* Simplifies replace_table code. */
  	table->private = bootstrap;
784544739   Stephen Hemminger   netfilter: iptabl...
856

2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
857
858
859
860
  	if (!xt_replace_table(table, 0, newinfo, &ret))
  		goto unlock;
  
  	private = table->private;
be91fd5e3   Jan Engelhardt   netfilter: xtable...
861
862
  	pr_debug("table->private->number = %u
  ", private->number);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
863
864
865
  
  	/* save number of initial entries */
  	private->initial_entries = private->number;
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
866
  	list_add(&table->list, &net->xt.tables[table->af]);
a98da11d8   Alexey Dobriyan   [NETFILTER]: x_ta...
867
868
  	mutex_unlock(&xt[table->af].mutex);
  	return table;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
869

2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
870
   unlock:
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
871
  	mutex_unlock(&xt[table->af].mutex);
44d34e721   Alexey Dobriyan   [NETFILTER]: x_ta...
872
873
  out_free:
  	kfree(table);
a98da11d8   Alexey Dobriyan   [NETFILTER]: x_ta...
874
875
  out:
  	return ERR_PTR(ret);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
876
877
878
879
880
881
  }
  EXPORT_SYMBOL_GPL(xt_register_table);
  
  void *xt_unregister_table(struct xt_table *table)
  {
  	struct xt_table_info *private;
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
882
  	mutex_lock(&xt[table->af].mutex);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
883
  	private = table->private;
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
884
  	list_del(&table->list);
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
885
  	mutex_unlock(&xt[table->af].mutex);
44d34e721   Alexey Dobriyan   [NETFILTER]: x_ta...
886
  	kfree(table);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
887
888
889
890
891
892
  
  	return private;
  }
  EXPORT_SYMBOL_GPL(xt_unregister_table);
  
  #ifdef CONFIG_PROC_FS
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
893
894
  struct xt_names_priv {
  	struct seq_net_private p;
76108cea0   Jan Engelhardt   netfilter: Use un...
895
  	u_int8_t af;
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
896
  };
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
897
  static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
898
  {
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
899
  	struct xt_names_priv *priv = seq->private;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
900
  	struct net *net = seq_file_net(seq);
76108cea0   Jan Engelhardt   netfilter: Use un...
901
  	u_int8_t af = priv->af;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
902

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
903
  	mutex_lock(&xt[af].mutex);
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
904
  	return seq_list_start(&net->xt.tables[af], *pos);
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
905
  }
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
906

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
907
908
  static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
909
  	struct xt_names_priv *priv = seq->private;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
910
  	struct net *net = seq_file_net(seq);
76108cea0   Jan Engelhardt   netfilter: Use un...
911
  	u_int8_t af = priv->af;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
912

715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
913
  	return seq_list_next(v, &net->xt.tables[af], pos);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
914
  }
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
915
  static void xt_table_seq_stop(struct seq_file *seq, void *v)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
916
  {
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
917
  	struct xt_names_priv *priv = seq->private;
76108cea0   Jan Engelhardt   netfilter: Use un...
918
  	u_int8_t af = priv->af;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
919

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
920
921
  	mutex_unlock(&xt[af].mutex);
  }
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
922

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
923
924
925
  static int xt_table_seq_show(struct seq_file *seq, void *v)
  {
  	struct xt_table *table = list_entry(v, struct xt_table, list);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
926

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
927
928
929
930
931
932
  	if (strlen(table->name))
  		return seq_printf(seq, "%s
  ", table->name);
  	else
  		return 0;
  }
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
933

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
934
935
936
937
938
939
940
941
942
943
  static const struct seq_operations xt_table_seq_ops = {
  	.start	= xt_table_seq_start,
  	.next	= xt_table_seq_next,
  	.stop	= xt_table_seq_stop,
  	.show	= xt_table_seq_show,
  };
  
  static int xt_table_open(struct inode *inode, struct file *file)
  {
  	int ret;
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
944
  	struct xt_names_priv *priv;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
945

715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
946
947
  	ret = seq_open_net(inode, file, &xt_table_seq_ops,
  			   sizeof(struct xt_names_priv));
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
948
  	if (!ret) {
715cf35ac   Alexey Dobriyan   [NETFILTER]: x_ta...
949
950
  		priv = ((struct seq_file *)file->private_data)->private;
  		priv->af = (unsigned long)PDE(inode)->data;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
951
952
  	}
  	return ret;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
953
  }
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
954
955
956
957
958
  static const struct file_operations xt_table_ops = {
  	.owner	 = THIS_MODULE,
  	.open	 = xt_table_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
0e93bb945   Pavel Emelyanov   netfilter: x_tabl...
959
  	.release = seq_release_net,
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
960
  };
eb132205c   Jan Engelhardt   netfilter: make p...
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
  /*
   * Traverse state for ip{,6}_{tables,matches} for helping crossing
   * the multi-AF mutexes.
   */
  struct nf_mttg_trav {
  	struct list_head *head, *curr;
  	uint8_t class, nfproto;
  };
  
  enum {
  	MTTG_TRAV_INIT,
  	MTTG_TRAV_NFP_UNSPEC,
  	MTTG_TRAV_NFP_SPEC,
  	MTTG_TRAV_DONE,
  };
  
  static void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
      bool is_target)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
979
  {
eb132205c   Jan Engelhardt   netfilter: make p...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  	static const uint8_t next_class[] = {
  		[MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC,
  		[MTTG_TRAV_NFP_SPEC]   = MTTG_TRAV_DONE,
  	};
  	struct nf_mttg_trav *trav = seq->private;
  
  	switch (trav->class) {
  	case MTTG_TRAV_INIT:
  		trav->class = MTTG_TRAV_NFP_UNSPEC;
  		mutex_lock(&xt[NFPROTO_UNSPEC].mutex);
  		trav->head = trav->curr = is_target ?
  			&xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match;
   		break;
  	case MTTG_TRAV_NFP_UNSPEC:
  		trav->curr = trav->curr->next;
  		if (trav->curr != trav->head)
  			break;
  		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
  		mutex_lock(&xt[trav->nfproto].mutex);
  		trav->head = trav->curr = is_target ?
  			&xt[trav->nfproto].target : &xt[trav->nfproto].match;
  		trav->class = next_class[trav->class];
  		break;
  	case MTTG_TRAV_NFP_SPEC:
  		trav->curr = trav->curr->next;
  		if (trav->curr != trav->head)
  			break;
  		/* fallthru, _stop will unlock */
  	default:
  		return NULL;
  	}
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1011

eb132205c   Jan Engelhardt   netfilter: make p...
1012
1013
1014
  	if (ppos != NULL)
  		++*ppos;
  	return trav;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1015
  }
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
1016

eb132205c   Jan Engelhardt   netfilter: make p...
1017
1018
  static void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos,
      bool is_target)
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1019
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1020
1021
  	struct nf_mttg_trav *trav = seq->private;
  	unsigned int j;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1022

eb132205c   Jan Engelhardt   netfilter: make p...
1023
1024
1025
1026
1027
  	trav->class = MTTG_TRAV_INIT;
  	for (j = 0; j < *pos; ++j)
  		if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL)
  			return NULL;
  	return trav;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1028
  }
eb132205c   Jan Engelhardt   netfilter: make p...
1029
  static void xt_mttg_seq_stop(struct seq_file *seq, void *v)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1030
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  	struct nf_mttg_trav *trav = seq->private;
  
  	switch (trav->class) {
  	case MTTG_TRAV_NFP_UNSPEC:
  		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
  		break;
  	case MTTG_TRAV_NFP_SPEC:
  		mutex_unlock(&xt[trav->nfproto].mutex);
  		break;
  	}
  }
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1042

eb132205c   Jan Engelhardt   netfilter: make p...
1043
1044
1045
  static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	return xt_mttg_seq_start(seq, pos, false);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1046
  }
eb132205c   Jan Engelhardt   netfilter: make p...
1047
  static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1048
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1049
1050
  	return xt_mttg_seq_next(seq, v, ppos, false);
  }
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1051

eb132205c   Jan Engelhardt   netfilter: make p...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  static int xt_match_seq_show(struct seq_file *seq, void *v)
  {
  	const struct nf_mttg_trav *trav = seq->private;
  	const struct xt_match *match;
  
  	switch (trav->class) {
  	case MTTG_TRAV_NFP_UNSPEC:
  	case MTTG_TRAV_NFP_SPEC:
  		if (trav->curr == trav->head)
  			return 0;
  		match = list_entry(trav->curr, struct xt_match, list);
  		return (*match->name == '\0') ? 0 :
  		       seq_printf(seq, "%s
  ", match->name);
  	}
  	return 0;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1068
  }
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1069
1070
1071
  static const struct seq_operations xt_match_seq_ops = {
  	.start	= xt_match_seq_start,
  	.next	= xt_match_seq_next,
eb132205c   Jan Engelhardt   netfilter: make p...
1072
  	.stop	= xt_mttg_seq_stop,
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1073
  	.show	= xt_match_seq_show,
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1074
  };
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1075
  static int xt_match_open(struct inode *inode, struct file *file)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1076
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1077
1078
  	struct seq_file *seq;
  	struct nf_mttg_trav *trav;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1079
  	int ret;
eb132205c   Jan Engelhardt   netfilter: make p...
1080
1081
1082
  	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
  	if (trav == NULL)
  		return -ENOMEM;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1083

eb132205c   Jan Engelhardt   netfilter: make p...
1084
1085
1086
1087
  	ret = seq_open(file, &xt_match_seq_ops);
  	if (ret < 0) {
  		kfree(trav);
  		return ret;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1088
  	}
eb132205c   Jan Engelhardt   netfilter: make p...
1089
1090
1091
1092
1093
  
  	seq = file->private_data;
  	seq->private = trav;
  	trav->nfproto = (unsigned long)PDE(inode)->data;
  	return 0;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1094
1095
1096
1097
1098
1099
1100
  }
  
  static const struct file_operations xt_match_ops = {
  	.owner	 = THIS_MODULE,
  	.open	 = xt_match_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
eb132205c   Jan Engelhardt   netfilter: make p...
1101
  	.release = seq_release_private,
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1102
  };
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1103

025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1104
1105
  static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1106
  	return xt_mttg_seq_start(seq, pos, true);
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1107
  }
eb132205c   Jan Engelhardt   netfilter: make p...
1108
  static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1109
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1110
  	return xt_mttg_seq_next(seq, v, ppos, true);
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1111
1112
1113
1114
  }
  
  static int xt_target_seq_show(struct seq_file *seq, void *v)
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	const struct nf_mttg_trav *trav = seq->private;
  	const struct xt_target *target;
  
  	switch (trav->class) {
  	case MTTG_TRAV_NFP_UNSPEC:
  	case MTTG_TRAV_NFP_SPEC:
  		if (trav->curr == trav->head)
  			return 0;
  		target = list_entry(trav->curr, struct xt_target, list);
  		return (*target->name == '\0') ? 0 :
  		       seq_printf(seq, "%s
  ", target->name);
  	}
  	return 0;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1129
1130
1131
1132
1133
  }
  
  static const struct seq_operations xt_target_seq_ops = {
  	.start	= xt_target_seq_start,
  	.next	= xt_target_seq_next,
eb132205c   Jan Engelhardt   netfilter: make p...
1134
  	.stop	= xt_mttg_seq_stop,
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1135
1136
1137
1138
1139
  	.show	= xt_target_seq_show,
  };
  
  static int xt_target_open(struct inode *inode, struct file *file)
  {
eb132205c   Jan Engelhardt   netfilter: make p...
1140
1141
  	struct seq_file *seq;
  	struct nf_mttg_trav *trav;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1142
  	int ret;
eb132205c   Jan Engelhardt   netfilter: make p...
1143
1144
1145
  	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
  	if (trav == NULL)
  		return -ENOMEM;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1146

eb132205c   Jan Engelhardt   netfilter: make p...
1147
1148
1149
1150
  	ret = seq_open(file, &xt_target_seq_ops);
  	if (ret < 0) {
  		kfree(trav);
  		return ret;
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1151
  	}
eb132205c   Jan Engelhardt   netfilter: make p...
1152
1153
1154
1155
1156
  
  	seq = file->private_data;
  	seq->private = trav;
  	trav->nfproto = (unsigned long)PDE(inode)->data;
  	return 0;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1157
  }
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1158
  static const struct file_operations xt_target_ops = {
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1159
  	.owner	 = THIS_MODULE,
025d93d14   Alexey Dobriyan   [NETFILTER]: x_ta...
1160
  	.open	 = xt_target_open,
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1161
1162
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
eb132205c   Jan Engelhardt   netfilter: make p...
1163
  	.release = seq_release_private,
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1164
1165
1166
1167
1168
1169
1170
  };
  
  #define FORMAT_TABLES	"_tables_names"
  #define	FORMAT_MATCHES	"_tables_matches"
  #define FORMAT_TARGETS 	"_tables_targets"
  
  #endif /* CONFIG_PROC_FS */
2b95efe7f   Jan Engelhardt   netfilter: xtable...
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  /**
   * xt_hook_link - set up hooks for a new table
   * @table:	table with metadata needed to set up hooks
   * @fn:		Hook function
   *
   * This function will take care of creating and registering the necessary
   * Netfilter hooks for XT tables.
   */
  struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
  {
  	unsigned int hook_mask = table->valid_hooks;
  	uint8_t i, num_hooks = hweight32(hook_mask);
  	uint8_t hooknum;
  	struct nf_hook_ops *ops;
  	int ret;
  
  	ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
  	if (ops == NULL)
  		return ERR_PTR(-ENOMEM);
  
  	for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
  	     hook_mask >>= 1, ++hooknum) {
  		if (!(hook_mask & 1))
  			continue;
  		ops[i].hook     = fn;
  		ops[i].owner    = table->me;
  		ops[i].pf       = table->af;
  		ops[i].hooknum  = hooknum;
  		ops[i].priority = table->priority;
  		++i;
  	}
  
  	ret = nf_register_hooks(ops, num_hooks);
  	if (ret < 0) {
  		kfree(ops);
  		return ERR_PTR(ret);
  	}
  
  	return ops;
  }
  EXPORT_SYMBOL_GPL(xt_hook_link);
  
  /**
   * xt_hook_unlink - remove hooks for a table
   * @ops:	nf_hook_ops array as returned by nf_hook_link
   * @hook_mask:	the very same mask that was passed to nf_hook_link
   */
  void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
  {
  	nf_unregister_hooks(ops, hweight32(table->valid_hooks));
  	kfree(ops);
  }
  EXPORT_SYMBOL_GPL(xt_hook_unlink);
76108cea0   Jan Engelhardt   netfilter: Use un...
1224
  int xt_proto_init(struct net *net, u_int8_t af)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1225
1226
1227
1228
1229
  {
  #ifdef CONFIG_PROC_FS
  	char buf[XT_FUNCTION_MAXNAMELEN];
  	struct proc_dir_entry *proc;
  #endif
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
1230
  	if (af >= ARRAY_SIZE(xt_prefix))
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1231
1232
1233
1234
  		return -EINVAL;
  
  
  #ifdef CONFIG_PROC_FS
ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1235
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1236
  	strlcat(buf, FORMAT_TABLES, sizeof(buf));
8b169240e   Denis V. Lunev   netfilter: assign...
1237
1238
  	proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops,
  				(void *)(unsigned long)af);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1239
1240
  	if (!proc)
  		goto out;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1241

ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1242
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1243
  	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
8b169240e   Denis V. Lunev   netfilter: assign...
1244
1245
  	proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops,
  				(void *)(unsigned long)af);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1246
1247
  	if (!proc)
  		goto out_remove_tables;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1248

ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1249
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1250
  	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
8b169240e   Denis V. Lunev   netfilter: assign...
1251
1252
  	proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops,
  				(void *)(unsigned long)af);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1253
1254
  	if (!proc)
  		goto out_remove_matches;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1255
1256
1257
1258
1259
1260
  #endif
  
  	return 0;
  
  #ifdef CONFIG_PROC_FS
  out_remove_matches:
ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1261
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1262
  	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
3cb609d57   Alexey Dobriyan   [NETFILTER]: x_ta...
1263
  	proc_net_remove(net, buf);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1264
1265
  
  out_remove_tables:
ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1266
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1267
  	strlcat(buf, FORMAT_TABLES, sizeof(buf));
3cb609d57   Alexey Dobriyan   [NETFILTER]: x_ta...
1268
  	proc_net_remove(net, buf);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1269
1270
1271
1272
1273
  out:
  	return -1;
  #endif
  }
  EXPORT_SYMBOL_GPL(xt_proto_init);
76108cea0   Jan Engelhardt   netfilter: Use un...
1274
  void xt_proto_fini(struct net *net, u_int8_t af)
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1275
1276
1277
  {
  #ifdef CONFIG_PROC_FS
  	char buf[XT_FUNCTION_MAXNAMELEN];
ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1278
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1279
  	strlcat(buf, FORMAT_TABLES, sizeof(buf));
3cb609d57   Alexey Dobriyan   [NETFILTER]: x_ta...
1280
  	proc_net_remove(net, buf);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1281

ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1282
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1283
  	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
3cb609d57   Alexey Dobriyan   [NETFILTER]: x_ta...
1284
  	proc_net_remove(net, buf);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1285

ce18afe57   Tobias Klauser   [NETFILTER]: x_ta...
1286
  	strlcpy(buf, xt_prefix[af], sizeof(buf));
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1287
  	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
3cb609d57   Alexey Dobriyan   [NETFILTER]: x_ta...
1288
  	proc_net_remove(net, buf);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1289
1290
1291
  #endif /*CONFIG_PROC_FS*/
  }
  EXPORT_SYMBOL_GPL(xt_proto_fini);
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
1292
1293
1294
  static int __net_init xt_net_init(struct net *net)
  {
  	int i;
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
1295
  	for (i = 0; i < NFPROTO_NUMPROTO; i++)
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
1296
1297
1298
1299
1300
1301
1302
  		INIT_LIST_HEAD(&net->xt.tables[i]);
  	return 0;
  }
  
  static struct pernet_operations xt_net_ops = {
  	.init = xt_net_init,
  };
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1303
1304
1305
  
  static int __init xt_init(void)
  {
942e4a2bd   Stephen Hemminger   netfilter: revise...
1306
1307
1308
1309
  	unsigned int i;
  	int rv;
  
  	for_each_possible_cpu(i) {
7f5c6d4f6   Eric Dumazet   netfilter: get ri...
1310
  		seqcount_init(&per_cpu(xt_recseq, i));
942e4a2bd   Stephen Hemminger   netfilter: revise...
1311
  	}
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1312

7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
1313
  	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1314
1315
  	if (!xt)
  		return -ENOMEM;
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
1316
  	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
9e19bb6d7   Ingo Molnar   [NETFILTER] x_tab...
1317
  		mutex_init(&xt[i].mutex);
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
1318
1319
  #ifdef CONFIG_COMPAT
  		mutex_init(&xt[i].compat_mutex);
255d0dc34   Eric Dumazet   netfilter: x_tabl...
1320
  		xt[i].compat_tab = NULL;
2722971cb   Dmitry Mishin   [NETFILTER]: ipta...
1321
  #endif
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1322
1323
  		INIT_LIST_HEAD(&xt[i].target);
  		INIT_LIST_HEAD(&xt[i].match);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1324
  	}
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
1325
1326
1327
1328
  	rv = register_pernet_subsys(&xt_net_ops);
  	if (rv < 0)
  		kfree(xt);
  	return rv;
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1329
1330
1331
1332
  }
  
  static void __exit xt_fini(void)
  {
8d8700520   Alexey Dobriyan   [NETFILTER]: x_ta...
1333
  	unregister_pernet_subsys(&xt_net_ops);
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
1334
1335
1336
1337
1338
  	kfree(xt);
  }
  
  module_init(xt_init);
  module_exit(xt_fini);