blob: d5a09eaef9153b6858fc3cecf44a777c002902bf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ebtables
3 *
4 * Author:
5 * Bart De Schuymer <bdschuym@pandora.be>
6 *
7 * ebtables.c,v 2.0, July, 2002
8 *
9 * This code is stongly inspired on the iptables code which is
10 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18/* used for print_string */
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/tty.h>
20
21#include <linux/kmod.h>
22#include <linux/module.h>
23#include <linux/vmalloc.h>
24#include <linux/netfilter_bridge/ebtables.h>
25#include <linux/spinlock.h>
Patrick McHardydf0933d2006-09-20 11:57:53 -070026#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/uaccess.h>
28#include <linux/smp.h>
David S. Millerc8923c62005-10-13 14:41:23 -070029#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <net/sock.h>
31/* needed for logical [in,out]-dev filtering */
32#include "../br_private.h"
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090035 "report to author: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/* #define BUGPRINT(format, args...) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090038 ": out of memory: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039/* #define MEMPRINT(format, args...) */
40
41
42
43/*
44 * Each cpu has its own set of counters, so there is no need for write_lock in
45 * the softirq
46 * For reading or updating the counters, the user context needs to
47 * get a write_lock
48 */
49
50/* The size of each set of counters is altered to get cache alignment */
51#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
52#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
53#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
54 COUNTER_OFFSET(n) * cpu))
55
56
57
Ingo Molnar57b47a52006-03-20 22:35:41 -080058static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059static LIST_HEAD(ebt_tables);
60static LIST_HEAD(ebt_targets);
61static LIST_HEAD(ebt_matches);
62static LIST_HEAD(ebt_watchers);
63
64static struct ebt_target ebt_standard_target =
65{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
66
67static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
68 const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
69 const struct net_device *out)
70{
71 w->u.watcher->watcher(skb, hooknr, in, out, w->data,
72 w->watcher_size);
73 /* watchers don't give a verdict */
74 return 0;
75}
76
77static inline int ebt_do_match (struct ebt_entry_match *m,
78 const struct sk_buff *skb, const struct net_device *in,
79 const struct net_device *out)
80{
81 return m->u.match->match(skb, in, out, m->data,
82 m->match_size);
83}
84
85static inline int ebt_dev_check(char *entry, const struct net_device *device)
86{
87 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080088 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 if (*entry == '\0')
91 return 0;
92 if (!device)
93 return 1;
94 /* 1 is the wildcard token */
95 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
96 i++;
97 return (devname[i] != entry[i] && entry[i] != 1);
98}
99
100#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
101/* process standard matches */
102static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
103 const struct net_device *in, const struct net_device *out)
104{
105 int verdict, i;
106
107 if (e->bitmask & EBT_802_3) {
108 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
109 return 1;
110 } else if (!(e->bitmask & EBT_NOPROTO) &&
111 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
112 return 1;
113
114 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
115 return 1;
116 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
117 return 1;
118 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
119 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
120 return 1;
121 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
122 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
123 return 1;
124
125 if (e->bitmask & EBT_SOURCEMAC) {
126 verdict = 0;
127 for (i = 0; i < 6; i++)
128 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
129 e->sourcemsk[i];
130 if (FWINV2(verdict != 0, EBT_ISOURCE) )
131 return 1;
132 }
133 if (e->bitmask & EBT_DESTMAC) {
134 verdict = 0;
135 for (i = 0; i < 6; i++)
136 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
137 e->destmsk[i];
138 if (FWINV2(verdict != 0, EBT_IDEST) )
139 return 1;
140 }
141 return 0;
142}
143
144/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700145unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 const struct net_device *in, const struct net_device *out,
147 struct ebt_table *table)
148{
149 int i, nentries;
150 struct ebt_entry *point;
151 struct ebt_counter *counter_base, *cb_base;
152 struct ebt_entry_target *t;
153 int verdict, sp = 0;
154 struct ebt_chainstack *cs;
155 struct ebt_entries *chaininfo;
156 char *base;
157 struct ebt_table_info *private;
158
159 read_lock_bh(&table->lock);
160 private = table->private;
161 cb_base = COUNTER_BASE(private->counters, private->nentries,
162 smp_processor_id());
163 if (private->chainstack)
164 cs = private->chainstack[smp_processor_id()];
165 else
166 cs = NULL;
167 chaininfo = private->hook_entry[hook];
168 nentries = private->hook_entry[hook]->nentries;
169 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
170 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
171 /* base for chain jumps */
172 base = private->entries;
173 i = 0;
174 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700175 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 goto letscontinue;
177
Herbert Xu3db05fe2007-10-15 00:53:15 -0700178 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 goto letscontinue;
180
181 /* increase counter */
182 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700183 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 /* these should only watch: not modify, nor tell us
186 what to do with the packet */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700187 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 out);
189
190 t = (struct ebt_entry_target *)
191 (((char *)point) + point->target_offset);
192 /* standard target */
193 if (!t->u.target->target)
194 verdict = ((struct ebt_standard_target *)t)->verdict;
195 else
Herbert Xu3db05fe2007-10-15 00:53:15 -0700196 verdict = t->u.target->target(skb, hook,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 in, out, t->data, t->target_size);
198 if (verdict == EBT_ACCEPT) {
199 read_unlock_bh(&table->lock);
200 return NF_ACCEPT;
201 }
202 if (verdict == EBT_DROP) {
203 read_unlock_bh(&table->lock);
204 return NF_DROP;
205 }
206 if (verdict == EBT_RETURN) {
207letsreturn:
208#ifdef CONFIG_NETFILTER_DEBUG
209 if (sp == 0) {
210 BUGPRINT("RETURN on base chain");
211 /* act like this is EBT_CONTINUE */
212 goto letscontinue;
213 }
214#endif
215 sp--;
216 /* put all the local variables right */
217 i = cs[sp].n;
218 chaininfo = cs[sp].chaininfo;
219 nentries = chaininfo->nentries;
220 point = cs[sp].e;
221 counter_base = cb_base +
222 chaininfo->counter_offset;
223 continue;
224 }
225 if (verdict == EBT_CONTINUE)
226 goto letscontinue;
227#ifdef CONFIG_NETFILTER_DEBUG
228 if (verdict < 0) {
229 BUGPRINT("bogus standard verdict\n");
230 read_unlock_bh(&table->lock);
231 return NF_DROP;
232 }
233#endif
234 /* jump to a udc */
235 cs[sp].n = i + 1;
236 cs[sp].chaininfo = chaininfo;
237 cs[sp].e = (struct ebt_entry *)
238 (((char *)point) + point->next_offset);
239 i = 0;
240 chaininfo = (struct ebt_entries *) (base + verdict);
241#ifdef CONFIG_NETFILTER_DEBUG
242 if (chaininfo->distinguisher) {
243 BUGPRINT("jump to non-chain\n");
244 read_unlock_bh(&table->lock);
245 return NF_DROP;
246 }
247#endif
248 nentries = chaininfo->nentries;
249 point = (struct ebt_entry *)chaininfo->data;
250 counter_base = cb_base + chaininfo->counter_offset;
251 sp++;
252 continue;
253letscontinue:
254 point = (struct ebt_entry *)
255 (((char *)point) + point->next_offset);
256 i++;
257 }
258
259 /* I actually like this :) */
260 if (chaininfo->policy == EBT_RETURN)
261 goto letsreturn;
262 if (chaininfo->policy == EBT_ACCEPT) {
263 read_unlock_bh(&table->lock);
264 return NF_ACCEPT;
265 }
266 read_unlock_bh(&table->lock);
267 return NF_DROP;
268}
269
270/* If it succeeds, returns element and locks mutex */
271static inline void *
272find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800273 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700275 struct {
276 struct list_head list;
277 char name[EBT_FUNCTION_MAXNAMELEN];
278 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Ingo Molnar57b47a52006-03-20 22:35:41 -0800280 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 if (*error != 0)
282 return NULL;
283
Patrick McHardydf0933d2006-09-20 11:57:53 -0700284 list_for_each_entry(e, head, list) {
285 if (strcmp(e->name, name) == 0)
286 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700288 *error = -ENOENT;
289 mutex_unlock(mutex);
290 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291}
292
293#ifndef CONFIG_KMOD
294#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
295#else
296static void *
297find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800298 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 void *ret;
301
302 ret = find_inlist_lock_noload(head, name, error, mutex);
303 if (!ret) {
304 request_module("%s%s", prefix, name);
305 ret = find_inlist_lock_noload(head, name, error, mutex);
306 }
307 return ret;
308}
309#endif
310
311static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800312find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
315}
316
317static inline struct ebt_match *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800318find_match_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
321}
322
323static inline struct ebt_watcher *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800324find_watcher_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
327}
328
329static inline struct ebt_target *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800330find_target_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
332 return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
333}
334
335static inline int
336ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
337 const char *name, unsigned int hookmask, unsigned int *cnt)
338{
339 struct ebt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800340 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 int ret;
342
Al Viro14197d52006-11-30 19:25:21 -0800343 if (left < sizeof(struct ebt_entry_match) ||
344 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 return -EINVAL;
346 match = find_match_lock(m->u.name, &ret, &ebt_mutex);
347 if (!match)
348 return ret;
349 m->u.match = match;
350 if (!try_module_get(match->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800351 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return -ENOENT;
353 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800354 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 if (match->check &&
356 match->check(name, hookmask, e, m->data, m->match_size) != 0) {
357 BUGPRINT("match->check failed\n");
358 module_put(match->me);
359 return -EINVAL;
360 }
361 (*cnt)++;
362 return 0;
363}
364
365static inline int
366ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
367 const char *name, unsigned int hookmask, unsigned int *cnt)
368{
369 struct ebt_watcher *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800370 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 int ret;
372
Al Viro14197d52006-11-30 19:25:21 -0800373 if (left < sizeof(struct ebt_entry_watcher) ||
374 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return -EINVAL;
376 watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
377 if (!watcher)
378 return ret;
379 w->u.watcher = watcher;
380 if (!try_module_get(watcher->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800381 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 return -ENOENT;
383 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800384 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 if (watcher->check &&
386 watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
387 BUGPRINT("watcher->check failed\n");
388 module_put(watcher->me);
389 return -EINVAL;
390 }
391 (*cnt)++;
392 return 0;
393}
394
Al Viro70fe9af2006-11-30 19:26:14 -0800395static int ebt_verify_pointers(struct ebt_replace *repl,
396 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Al Viro70fe9af2006-11-30 19:26:14 -0800398 unsigned int limit = repl->entries_size;
399 unsigned int valid_hooks = repl->valid_hooks;
400 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 int i;
402
Al Viroe4fd77d2006-11-30 19:26:35 -0800403 for (i = 0; i < NF_BR_NUMHOOKS; i++)
404 newinfo->hook_entry[i] = NULL;
405
406 newinfo->entries_size = repl->entries_size;
407 newinfo->nentries = repl->nentries;
408
Al Viro70fe9af2006-11-30 19:26:14 -0800409 while (offset < limit) {
410 size_t left = limit - offset;
411 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800412
Al Viro70fe9af2006-11-30 19:26:14 -0800413 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 break;
Al Viro22b440b2006-11-30 19:25:51 -0800415
Al Viro70fe9af2006-11-30 19:26:14 -0800416 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
417 if ((valid_hooks & (1 << i)) == 0)
418 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800419 if ((char __user *)repl->hook_entry[i] ==
420 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800421 break;
422 }
423
424 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
425 if (e->bitmask != 0) {
426 /* we make userspace set this right,
427 so there is no misunderstanding */
428 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
429 "in distinguisher\n");
430 return -EINVAL;
431 }
432 if (i != NF_BR_NUMHOOKS)
433 newinfo->hook_entry[i] = (struct ebt_entries *)e;
434 if (left < sizeof(struct ebt_entries))
435 break;
436 offset += sizeof(struct ebt_entries);
437 } else {
438 if (left < sizeof(struct ebt_entry))
439 break;
440 if (left < e->next_offset)
441 break;
442 offset += e->next_offset;
443 }
444 }
445 if (offset != limit) {
446 BUGPRINT("entries_size too small\n");
447 return -EINVAL;
448 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800449
450 /* check if all valid hooks have a chain */
451 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
452 if (!newinfo->hook_entry[i] &&
453 (valid_hooks & (1 << i))) {
454 BUGPRINT("Valid hook without chain\n");
455 return -EINVAL;
456 }
457 }
Al Viro70fe9af2006-11-30 19:26:14 -0800458 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800459}
460
461/*
462 * this one is very careful, as it is the first function
463 * to parse the userspace data
464 */
465static inline int
466ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800467 struct ebt_table_info *newinfo,
468 unsigned int *n, unsigned int *cnt,
469 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800470{
Al Viro22b440b2006-11-30 19:25:51 -0800471 int i;
472
473 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800474 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800475 break;
476 }
477 /* beginning of a new chain
478 if i == NF_BR_NUMHOOKS it must be a user defined chain */
479 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 /* this checks if the previous chain has as many entries
481 as it said it has */
482 if (*n != *cnt) {
483 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900484 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 return -EINVAL;
486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
488 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
489 /* only RETURN from udc */
490 if (i != NF_BR_NUMHOOKS ||
491 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
492 BUGPRINT("bad policy\n");
493 return -EINVAL;
494 }
495 }
496 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
497 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
499 BUGPRINT("counter_offset != totalcnt");
500 return -EINVAL;
501 }
502 *n = ((struct ebt_entries *)e)->nentries;
503 *cnt = 0;
504 return 0;
505 }
506 /* a plain old entry, heh */
507 if (sizeof(struct ebt_entry) > e->watchers_offset ||
508 e->watchers_offset > e->target_offset ||
509 e->target_offset >= e->next_offset) {
510 BUGPRINT("entry offsets not in right order\n");
511 return -EINVAL;
512 }
513 /* this is not checked anywhere else */
514 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
515 BUGPRINT("target size too small\n");
516 return -EINVAL;
517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 (*cnt)++;
519 (*totalcnt)++;
520 return 0;
521}
522
523struct ebt_cl_stack
524{
525 struct ebt_chainstack cs;
526 int from;
527 unsigned int hookmask;
528};
529
530/*
531 * we need these positions to check that the jumps to a different part of the
532 * entries is a jump to the beginning of a new chain.
533 */
534static inline int
535ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800536 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 int i;
539
540 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800541 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 return 0;
543 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
545 break;
546 }
547 /* only care about udc */
548 if (i != NF_BR_NUMHOOKS)
549 return 0;
550
551 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
552 /* these initialisations are depended on later in check_chainloops() */
553 udc[*n].cs.n = 0;
554 udc[*n].hookmask = 0;
555
556 (*n)++;
557 return 0;
558}
559
560static inline int
561ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
562{
563 if (i && (*i)-- == 0)
564 return 1;
565 if (m->u.match->destroy)
566 m->u.match->destroy(m->data, m->match_size);
567 module_put(m->u.match->me);
568
569 return 0;
570}
571
572static inline int
573ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
574{
575 if (i && (*i)-- == 0)
576 return 1;
577 if (w->u.watcher->destroy)
578 w->u.watcher->destroy(w->data, w->watcher_size);
579 module_put(w->u.watcher->me);
580
581 return 0;
582}
583
584static inline int
585ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
586{
587 struct ebt_entry_target *t;
588
Al Viro40642f92006-11-30 19:24:12 -0800589 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 return 0;
591 /* we're done */
592 if (cnt && (*cnt)-- == 0)
593 return 1;
594 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
595 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
596 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
597 if (t->u.target->destroy)
598 t->u.target->destroy(t->data, t->target_size);
599 module_put(t->u.target->me);
600
601 return 0;
602}
603
604static inline int
605ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800606 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
608{
609 struct ebt_entry_target *t;
610 struct ebt_target *target;
611 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800612 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 int ret;
614
615 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800616 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return 0;
618
619 if (e->bitmask & ~EBT_F_MASK) {
620 BUGPRINT("Unknown flag for bitmask\n");
621 return -EINVAL;
622 }
623 if (e->invflags & ~EBT_INV_MASK) {
624 BUGPRINT("Unknown flag for inv bitmask\n");
625 return -EINVAL;
626 }
627 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
628 BUGPRINT("NOPROTO & 802_3 not allowed\n");
629 return -EINVAL;
630 }
631 /* what hook do we belong to? */
632 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800633 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 continue;
635 if ((char *)newinfo->hook_entry[i] < (char *)e)
636 hook = i;
637 else
638 break;
639 }
640 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
641 a base chain */
642 if (i < NF_BR_NUMHOOKS)
643 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
644 else {
645 for (i = 0; i < udc_cnt; i++)
646 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
647 break;
648 if (i == 0)
649 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
650 else
651 hookmask = cl_s[i - 1].hookmask;
652 }
653 i = 0;
654 ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
655 if (ret != 0)
656 goto cleanup_matches;
657 j = 0;
658 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
659 if (ret != 0)
660 goto cleanup_watchers;
661 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800662 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 target = find_target_lock(t->u.name, &ret, &ebt_mutex);
664 if (!target)
665 goto cleanup_watchers;
666 if (!try_module_get(target->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800667 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 ret = -ENOENT;
669 goto cleanup_watchers;
670 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800671 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
673 t->u.target = target;
674 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800675 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 BUGPRINT("Standard target size too big\n");
677 ret = -EFAULT;
678 goto cleanup_watchers;
679 }
680 if (((struct ebt_standard_target *)t)->verdict <
681 -NUM_STANDARD_TARGETS) {
682 BUGPRINT("Invalid standard target\n");
683 ret = -EFAULT;
684 goto cleanup_watchers;
685 }
Al Viro14197d52006-11-30 19:25:21 -0800686 } else if (t->target_size > gap - sizeof(struct ebt_entry_target) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 (t->u.target->check &&
688 t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
689 module_put(t->u.target->me);
690 ret = -EFAULT;
691 goto cleanup_watchers;
692 }
693 (*cnt)++;
694 return 0;
695cleanup_watchers:
696 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
697cleanup_matches:
698 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
699 return ret;
700}
701
702/*
703 * checks for loops and sets the hook mask for udc
704 * the hook mask for udc tells us from which base chains the udc can be
705 * accessed. This mask is a parameter to the check() functions of the extensions
706 */
707static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
708 unsigned int udc_cnt, unsigned int hooknr, char *base)
709{
710 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
711 struct ebt_entry *e = (struct ebt_entry *)chain->data;
712 struct ebt_entry_target *t;
713
714 while (pos < nentries || chain_nr != -1) {
715 /* end of udc, go back one 'recursion' step */
716 if (pos == nentries) {
717 /* put back values of the time when this chain was called */
718 e = cl_s[chain_nr].cs.e;
719 if (cl_s[chain_nr].from != -1)
720 nentries =
721 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
722 else
723 nentries = chain->nentries;
724 pos = cl_s[chain_nr].cs.n;
725 /* make sure we won't see a loop that isn't one */
726 cl_s[chain_nr].cs.n = 0;
727 chain_nr = cl_s[chain_nr].from;
728 if (pos == nentries)
729 continue;
730 }
731 t = (struct ebt_entry_target *)
732 (((char *)e) + e->target_offset);
733 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
734 goto letscontinue;
735 if (e->target_offset + sizeof(struct ebt_standard_target) >
736 e->next_offset) {
737 BUGPRINT("Standard target size too big\n");
738 return -1;
739 }
740 verdict = ((struct ebt_standard_target *)t)->verdict;
741 if (verdict >= 0) { /* jump to another chain */
742 struct ebt_entries *hlp2 =
743 (struct ebt_entries *)(base + verdict);
744 for (i = 0; i < udc_cnt; i++)
745 if (hlp2 == cl_s[i].cs.chaininfo)
746 break;
747 /* bad destination or loop */
748 if (i == udc_cnt) {
749 BUGPRINT("bad destination\n");
750 return -1;
751 }
752 if (cl_s[i].cs.n) {
753 BUGPRINT("loop\n");
754 return -1;
755 }
Al Viro98a08242006-11-30 19:24:49 -0800756 if (cl_s[i].hookmask & (1 << hooknr))
757 goto letscontinue;
758 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 cl_s[i].cs.n = pos + 1;
760 pos = 0;
761 cl_s[i].cs.e = ((void *)e + e->next_offset);
762 e = (struct ebt_entry *)(hlp2->data);
763 nentries = hlp2->nentries;
764 cl_s[i].from = chain_nr;
765 chain_nr = i;
766 /* this udc is accessible from the base chain for hooknr */
767 cl_s[i].hookmask |= (1 << hooknr);
768 continue;
769 }
770letscontinue:
771 e = (void *)e + e->next_offset;
772 pos++;
773 }
774 return 0;
775}
776
777/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800778static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
780 unsigned int i, j, k, udc_cnt;
781 int ret;
782 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
783
784 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800785 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 i++;
787 if (i == NF_BR_NUMHOOKS) {
788 BUGPRINT("No valid hooks specified\n");
789 return -EINVAL;
790 }
Al Viro1f072c92006-11-30 19:26:53 -0800791 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 BUGPRINT("Chains don't start at beginning\n");
793 return -EINVAL;
794 }
795 /* make sure chains are ordered after each other in same order
796 as their corresponding hooks */
797 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800798 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800800 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 BUGPRINT("Hook order must be followed\n");
802 return -EINVAL;
803 }
804 i = j;
805 }
806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 /* do some early checkings and initialize some things */
808 i = 0; /* holds the expected nr. of entries for the chain */
809 j = 0; /* holds the up to now counted entries for the chain */
810 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900811 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
813 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800814 ebt_check_entry_size_and_hooks, newinfo,
815 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 if (ret != 0)
818 return ret;
819
820 if (i != j) {
821 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900822 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return -EINVAL;
824 }
825 if (k != newinfo->nentries) {
826 BUGPRINT("Total nentries is wrong\n");
827 return -EINVAL;
828 }
829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 /* get the location of the udc, put them in an array
831 while we're at it, allocate the chainstack */
832 if (udc_cnt) {
833 /* this will get free'd in do_replace()/ebt_register_table()
834 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700835 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800836 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (!newinfo->chainstack)
838 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700839 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700841 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (!newinfo->chainstack[i]) {
843 while (i)
844 vfree(newinfo->chainstack[--i]);
845 vfree(newinfo->chainstack);
846 newinfo->chainstack = NULL;
847 return -ENOMEM;
848 }
849 }
850
Jayachandran C18bc89a2006-04-20 00:14:49 -0700851 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (!cl_s)
853 return -ENOMEM;
854 i = 0; /* the i'th udc */
855 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800856 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 /* sanity check */
858 if (i != udc_cnt) {
859 BUGPRINT("i != udc_cnt\n");
860 vfree(cl_s);
861 return -EFAULT;
862 }
863 }
864
865 /* Check for loops */
866 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800867 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (check_chainloops(newinfo->hook_entry[i],
869 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700870 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return -EINVAL;
872 }
873
874 /* we now know the following (along with E=mc²):
875 - the nr of entries in each chain is right
876 - the size of the allocated space is right
877 - all valid hooks have a corresponding chain
878 - there are no loops
879 - wrong data can still be on the level of a single entry
880 - could be there are jumps to places that are not the
881 beginning of a chain. This can only occur in chains that
882 are not accessible from any base chains, so we don't care. */
883
884 /* used to know what we need to clean up if something goes wrong */
885 i = 0;
886 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800887 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (ret != 0) {
889 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
890 ebt_cleanup_entry, &i);
891 }
James Lamanna68d31872005-06-22 22:12:57 -0700892 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return ret;
894}
895
896/* called under write_lock */
897static void get_counters(struct ebt_counter *oldcounters,
898 struct ebt_counter *counters, unsigned int nentries)
899{
900 int i, cpu;
901 struct ebt_counter *counter_base;
902
903 /* counters of cpu 0 */
904 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700905 sizeof(struct ebt_counter) * nentries);
906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700908 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700909 if (cpu == 0)
910 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
912 for (i = 0; i < nentries; i++) {
913 counters[i].pcnt += counter_base[i].pcnt;
914 counters[i].bcnt += counter_base[i].bcnt;
915 }
916 }
917}
918
919/* replace the table */
920static int do_replace(void __user *user, unsigned int len)
921{
922 int ret, i, countersize;
923 struct ebt_table_info *newinfo;
924 struct ebt_replace tmp;
925 struct ebt_table *t;
926 struct ebt_counter *counterstmp = NULL;
927 /* used to be able to unlock earlier */
928 struct ebt_table_info *table;
929
930 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
931 return -EFAULT;
932
933 if (len != sizeof(tmp) + tmp.entries_size) {
934 BUGPRINT("Wrong len argument\n");
935 return -EINVAL;
936 }
937
938 if (tmp.entries_size == 0) {
939 BUGPRINT("Entries_size never zero\n");
940 return -EINVAL;
941 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800942 /* overflow check */
943 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
944 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
945 return -ENOMEM;
946 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
947 return -ENOMEM;
948
Christoph Lameter53b8a312007-02-20 13:57:51 -0800949 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700950 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 if (!newinfo)
952 return -ENOMEM;
953
954 if (countersize)
955 memset(newinfo->counters, 0, countersize);
956
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800957 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 if (!newinfo->entries) {
959 ret = -ENOMEM;
960 goto free_newinfo;
961 }
962 if (copy_from_user(
963 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
964 BUGPRINT("Couldn't copy entries from userspace\n");
965 ret = -EFAULT;
966 goto free_entries;
967 }
968
969 /* the user wants counters back
970 the check on the size is done later, when we have the lock */
971 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700972 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 if (!counterstmp) {
974 ret = -ENOMEM;
975 goto free_entries;
976 }
977 }
978 else
979 counterstmp = NULL;
980
981 /* this can get initialized by translate_table() */
982 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -0800983 ret = ebt_verify_pointers(&tmp, newinfo);
984 if (ret != 0)
985 goto free_counterstmp;
986
987 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (ret != 0)
990 goto free_counterstmp;
991
992 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
993 if (!t) {
994 ret = -ENOENT;
995 goto free_iterate;
996 }
997
998 /* the table doesn't like it */
999 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1000 goto free_unlock;
1001
1002 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1003 BUGPRINT("Wrong nr. of counters requested\n");
1004 ret = -EINVAL;
1005 goto free_unlock;
1006 }
1007
1008 /* we have the mutex lock, so no danger in reading this pointer */
1009 table = t->private;
1010 /* make sure the table can only be rmmod'ed if it contains no rules */
1011 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1012 ret = -ENOENT;
1013 goto free_unlock;
1014 } else if (table->nentries && !newinfo->nentries)
1015 module_put(t->me);
1016 /* we need an atomic snapshot of the counters */
1017 write_lock_bh(&t->lock);
1018 if (tmp.num_counters)
1019 get_counters(t->private->counters, counterstmp,
1020 t->private->nentries);
1021
1022 t->private = newinfo;
1023 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001024 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 /* so, a user can change the chains while having messed up her counter
1026 allocation. Only reason why this is done is because this way the lock
1027 is held only once, while this doesn't bring the kernel into a
1028 dangerous state. */
1029 if (tmp.num_counters &&
1030 copy_to_user(tmp.counters, counterstmp,
1031 tmp.num_counters * sizeof(struct ebt_counter))) {
1032 BUGPRINT("Couldn't copy counters to userspace\n");
1033 ret = -EFAULT;
1034 }
1035 else
1036 ret = 0;
1037
1038 /* decrease module count and free resources */
1039 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1040 ebt_cleanup_entry, NULL);
1041
1042 vfree(table->entries);
1043 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001044 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 vfree(table->chainstack[i]);
1046 vfree(table->chainstack);
1047 }
1048 vfree(table);
1049
James Lamanna68d31872005-06-22 22:12:57 -07001050 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 return ret;
1052
1053free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001054 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055free_iterate:
1056 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1057 ebt_cleanup_entry, NULL);
1058free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001059 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 /* can be initialized in translate_table() */
1061 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001062 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 vfree(newinfo->chainstack[i]);
1064 vfree(newinfo->chainstack);
1065 }
1066free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001067 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001069 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 return ret;
1071}
1072
1073int ebt_register_target(struct ebt_target *target)
1074{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001075 struct ebt_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 int ret;
1077
Ingo Molnar57b47a52006-03-20 22:35:41 -08001078 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (ret != 0)
1080 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001081 list_for_each_entry(t, &ebt_targets, list) {
1082 if (strcmp(t->name, target->name) == 0) {
1083 mutex_unlock(&ebt_mutex);
1084 return -EEXIST;
1085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001087 list_add(&target->list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001088 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090 return 0;
1091}
1092
1093void ebt_unregister_target(struct ebt_target *target)
1094{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001095 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001096 list_del(&target->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001097 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100int ebt_register_match(struct ebt_match *match)
1101{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001102 struct ebt_match *m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 int ret;
1104
Ingo Molnar57b47a52006-03-20 22:35:41 -08001105 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 if (ret != 0)
1107 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001108 list_for_each_entry(m, &ebt_matches, list) {
1109 if (strcmp(m->name, match->name) == 0) {
1110 mutex_unlock(&ebt_mutex);
1111 return -EEXIST;
1112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001114 list_add(&match->list, &ebt_matches);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001115 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117 return 0;
1118}
1119
1120void ebt_unregister_match(struct ebt_match *match)
1121{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001122 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001123 list_del(&match->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001124 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125}
1126
1127int ebt_register_watcher(struct ebt_watcher *watcher)
1128{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001129 struct ebt_watcher *w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 int ret;
1131
Ingo Molnar57b47a52006-03-20 22:35:41 -08001132 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (ret != 0)
1134 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001135 list_for_each_entry(w, &ebt_watchers, list) {
1136 if (strcmp(w->name, watcher->name) == 0) {
1137 mutex_unlock(&ebt_mutex);
1138 return -EEXIST;
1139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001141 list_add(&watcher->list, &ebt_watchers);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001142 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 return 0;
1145}
1146
1147void ebt_unregister_watcher(struct ebt_watcher *watcher)
1148{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001149 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001150 list_del(&watcher->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001151 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152}
1153
1154int ebt_register_table(struct ebt_table *table)
1155{
1156 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001157 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001158 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001160 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Al Virodf07a812006-11-30 19:28:25 -08001162 if (!table || !(repl = table->table) || !repl->entries ||
1163 repl->entries_size == 0 ||
1164 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1166 return -EINVAL;
1167 }
1168
Christoph Lameter53b8a312007-02-20 13:57:51 -08001169 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001170 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 ret = -ENOMEM;
1172 if (!newinfo)
1173 return -ENOMEM;
1174
Al Virodf07a812006-11-30 19:28:25 -08001175 p = vmalloc(repl->entries_size);
1176 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 goto free_newinfo;
1178
Al Virodf07a812006-11-30 19:28:25 -08001179 memcpy(p, repl->entries, repl->entries_size);
1180 newinfo->entries = p;
1181
1182 newinfo->entries_size = repl->entries_size;
1183 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
1185 if (countersize)
1186 memset(newinfo->counters, 0, countersize);
1187
1188 /* fill in newinfo and parse the entries */
1189 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001190 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1191 if ((repl->valid_hooks & (1 << i)) == 0)
1192 newinfo->hook_entry[i] = NULL;
1193 else
1194 newinfo->hook_entry[i] = p +
1195 ((char *)repl->hook_entry[i] - repl->entries);
1196 }
1197 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (ret != 0) {
1199 BUGPRINT("Translate_table failed\n");
1200 goto free_chainstack;
1201 }
1202
1203 if (table->check && table->check(newinfo, table->valid_hooks)) {
1204 BUGPRINT("The table doesn't like its own initial data, lol\n");
1205 return -EINVAL;
1206 }
1207
1208 table->private = newinfo;
1209 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001210 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (ret != 0)
1212 goto free_chainstack;
1213
Patrick McHardydf0933d2006-09-20 11:57:53 -07001214 list_for_each_entry(t, &ebt_tables, list) {
1215 if (strcmp(t->name, table->name) == 0) {
1216 ret = -EEXIST;
1217 BUGPRINT("Table name already exists\n");
1218 goto free_unlock;
1219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 }
1221
1222 /* Hold a reference count if the chains aren't empty */
1223 if (newinfo->nentries && !try_module_get(table->me)) {
1224 ret = -ENOENT;
1225 goto free_unlock;
1226 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001227 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001228 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return 0;
1230free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001231 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232free_chainstack:
1233 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001234 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 vfree(newinfo->chainstack[i]);
1236 vfree(newinfo->chainstack);
1237 }
1238 vfree(newinfo->entries);
1239free_newinfo:
1240 vfree(newinfo);
1241 return ret;
1242}
1243
1244void ebt_unregister_table(struct ebt_table *table)
1245{
1246 int i;
1247
1248 if (!table) {
1249 BUGPRINT("Request to unregister NULL table!!!\n");
1250 return;
1251 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001252 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001253 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001254 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001255 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001257 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 vfree(table->private->chainstack[i]);
1259 vfree(table->private->chainstack);
1260 }
1261 vfree(table->private);
1262}
1263
1264/* userspace just supplied us with counters */
1265static int update_counters(void __user *user, unsigned int len)
1266{
1267 int i, ret;
1268 struct ebt_counter *tmp;
1269 struct ebt_replace hlp;
1270 struct ebt_table *t;
1271
1272 if (copy_from_user(&hlp, user, sizeof(hlp)))
1273 return -EFAULT;
1274
1275 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1276 return -EINVAL;
1277 if (hlp.num_counters == 0)
1278 return -EINVAL;
1279
Jayachandran C18bc89a2006-04-20 00:14:49 -07001280 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 MEMPRINT("Update_counters && nomemory\n");
1282 return -ENOMEM;
1283 }
1284
1285 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1286 if (!t)
1287 goto free_tmp;
1288
1289 if (hlp.num_counters != t->private->nentries) {
1290 BUGPRINT("Wrong nr of counters\n");
1291 ret = -EINVAL;
1292 goto unlock_mutex;
1293 }
1294
1295 if ( copy_from_user(tmp, hlp.counters,
1296 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1297 BUGPRINT("Updata_counters && !cfu\n");
1298 ret = -EFAULT;
1299 goto unlock_mutex;
1300 }
1301
1302 /* we want an atomic add of the counters */
1303 write_lock_bh(&t->lock);
1304
1305 /* we add to the counters of the first cpu */
1306 for (i = 0; i < hlp.num_counters; i++) {
1307 t->private->counters[i].pcnt += tmp[i].pcnt;
1308 t->private->counters[i].bcnt += tmp[i].bcnt;
1309 }
1310
1311 write_unlock_bh(&t->lock);
1312 ret = 0;
1313unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001314 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315free_tmp:
1316 vfree(tmp);
1317 return ret;
1318}
1319
1320static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001321 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
Al Viro1e419cd2006-11-30 19:28:48 -08001323 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1325 return -EFAULT;
1326 return 0;
1327}
1328
1329static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001330 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331{
Al Viro1e419cd2006-11-30 19:28:48 -08001332 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1334 return -EFAULT;
1335 return 0;
1336}
1337
Al Viro1e419cd2006-11-30 19:28:48 -08001338static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
1340 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001341 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 struct ebt_entry_target *t;
1343
Al Viro40642f92006-11-30 19:24:12 -08001344 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 return 0;
1346
Al Viro1e419cd2006-11-30 19:28:48 -08001347 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1351 if (ret != 0)
1352 return ret;
1353 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1354 if (ret != 0)
1355 return ret;
1356 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1357 return -EFAULT;
1358 return 0;
1359}
1360
Ingo Molnar57b47a52006-03-20 22:35:41 -08001361/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1363 int *len, int cmd)
1364{
1365 struct ebt_replace tmp;
1366 struct ebt_counter *counterstmp, *oldcounters;
1367 unsigned int entries_size, nentries;
1368 char *entries;
1369
1370 if (cmd == EBT_SO_GET_ENTRIES) {
1371 entries_size = t->private->entries_size;
1372 nentries = t->private->nentries;
1373 entries = t->private->entries;
1374 oldcounters = t->private->counters;
1375 } else {
1376 entries_size = t->table->entries_size;
1377 nentries = t->table->nentries;
1378 entries = t->table->entries;
1379 oldcounters = t->table->counters;
1380 }
1381
1382 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1383 BUGPRINT("Cfu didn't work\n");
1384 return -EFAULT;
1385 }
1386
1387 if (*len != sizeof(struct ebt_replace) + entries_size +
1388 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1389 BUGPRINT("Wrong size\n");
1390 return -EINVAL;
1391 }
1392
1393 if (tmp.nentries != nentries) {
1394 BUGPRINT("Nentries wrong\n");
1395 return -EINVAL;
1396 }
1397
1398 if (tmp.entries_size != entries_size) {
1399 BUGPRINT("Wrong size\n");
1400 return -EINVAL;
1401 }
1402
1403 /* userspace might not need the counters */
1404 if (tmp.num_counters) {
1405 if (tmp.num_counters != nentries) {
1406 BUGPRINT("Num_counters wrong\n");
1407 return -EINVAL;
1408 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001409 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (!counterstmp) {
1411 MEMPRINT("Couldn't copy counters, out of memory\n");
1412 return -ENOMEM;
1413 }
1414 write_lock_bh(&t->lock);
1415 get_counters(oldcounters, counterstmp, nentries);
1416 write_unlock_bh(&t->lock);
1417
1418 if (copy_to_user(tmp.counters, counterstmp,
1419 nentries * sizeof(struct ebt_counter))) {
1420 BUGPRINT("Couldn't copy counters to userspace\n");
1421 vfree(counterstmp);
1422 return -EFAULT;
1423 }
1424 vfree(counterstmp);
1425 }
1426
1427 if (copy_to_user(tmp.entries, entries, entries_size)) {
1428 BUGPRINT("Couldn't copy entries to userspace\n");
1429 return -EFAULT;
1430 }
1431 /* set the match/watcher/target names right */
1432 return EBT_ENTRY_ITERATE(entries, entries_size,
1433 ebt_make_names, entries, tmp.entries);
1434}
1435
1436static int do_ebt_set_ctl(struct sock *sk,
1437 int cmd, void __user *user, unsigned int len)
1438{
1439 int ret;
1440
1441 switch(cmd) {
1442 case EBT_SO_SET_ENTRIES:
1443 ret = do_replace(user, len);
1444 break;
1445 case EBT_SO_SET_COUNTERS:
1446 ret = update_counters(user, len);
1447 break;
1448 default:
1449 ret = -EINVAL;
1450 }
1451 return ret;
1452}
1453
1454static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1455{
1456 int ret;
1457 struct ebt_replace tmp;
1458 struct ebt_table *t;
1459
1460 if (copy_from_user(&tmp, user, sizeof(tmp)))
1461 return -EFAULT;
1462
1463 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1464 if (!t)
1465 return ret;
1466
1467 switch(cmd) {
1468 case EBT_SO_GET_INFO:
1469 case EBT_SO_GET_INIT_INFO:
1470 if (*len != sizeof(struct ebt_replace)){
1471 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001472 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 break;
1474 }
1475 if (cmd == EBT_SO_GET_INFO) {
1476 tmp.nentries = t->private->nentries;
1477 tmp.entries_size = t->private->entries_size;
1478 tmp.valid_hooks = t->valid_hooks;
1479 } else {
1480 tmp.nentries = t->table->nentries;
1481 tmp.entries_size = t->table->entries_size;
1482 tmp.valid_hooks = t->table->valid_hooks;
1483 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001484 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 if (copy_to_user(user, &tmp, *len) != 0){
1486 BUGPRINT("c2u Didn't work\n");
1487 ret = -EFAULT;
1488 break;
1489 }
1490 ret = 0;
1491 break;
1492
1493 case EBT_SO_GET_ENTRIES:
1494 case EBT_SO_GET_INIT_ENTRIES:
1495 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001496 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 break;
1498
1499 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001500 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 ret = -EINVAL;
1502 }
1503
1504 return ret;
1505}
1506
1507static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001508{
1509 .pf = PF_INET,
1510 .set_optmin = EBT_BASE_CTL,
1511 .set_optmax = EBT_SO_SET_MAX + 1,
1512 .set = do_ebt_set_ctl,
1513 .get_optmin = EBT_BASE_CTL,
1514 .get_optmax = EBT_SO_GET_MAX + 1,
1515 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001516 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517};
1518
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001519static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520{
1521 int ret;
1522
Ingo Molnar57b47a52006-03-20 22:35:41 -08001523 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001524 list_add(&ebt_standard_target.list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001525 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
1527 return ret;
1528
Patrick McHardya887c1c2007-07-14 20:46:15 -07001529 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 return 0;
1531}
1532
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001533static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
1535 nf_unregister_sockopt(&ebt_sockopts);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001536 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537}
1538
1539EXPORT_SYMBOL(ebt_register_table);
1540EXPORT_SYMBOL(ebt_unregister_table);
1541EXPORT_SYMBOL(ebt_register_match);
1542EXPORT_SYMBOL(ebt_unregister_match);
1543EXPORT_SYMBOL(ebt_register_watcher);
1544EXPORT_SYMBOL(ebt_unregister_watcher);
1545EXPORT_SYMBOL(ebt_register_target);
1546EXPORT_SYMBOL(ebt_unregister_target);
1547EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001548module_init(ebtables_init);
1549module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550MODULE_LICENSE("GPL");