blob: 5818d70b8e8d3bec53c5d6696beed715439d770d [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 */
19#include <linux/sched.h>
20#include <linux/tty.h>
21
22#include <linux/kmod.h>
23#include <linux/module.h>
24#include <linux/vmalloc.h>
25#include <linux/netfilter_bridge/ebtables.h>
26#include <linux/spinlock.h>
Patrick McHardydf0933d2006-09-20 11:57:53 -070027#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/uaccess.h>
29#include <linux/smp.h>
David S. Millerc8923c62005-10-13 14:41:23 -070030#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <net/sock.h>
32/* needed for logical [in,out]-dev filtering */
33#include "../br_private.h"
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090036 "report to author: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/* #define BUGPRINT(format, args...) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090039 ": out of memory: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040/* #define MEMPRINT(format, args...) */
41
42
43
44/*
45 * Each cpu has its own set of counters, so there is no need for write_lock in
46 * the softirq
47 * For reading or updating the counters, the user context needs to
48 * get a write_lock
49 */
50
51/* The size of each set of counters is altered to get cache alignment */
52#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
53#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
54#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
55 COUNTER_OFFSET(n) * cpu))
56
57
58
Ingo Molnar57b47a52006-03-20 22:35:41 -080059static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060static LIST_HEAD(ebt_tables);
61static LIST_HEAD(ebt_targets);
62static LIST_HEAD(ebt_matches);
63static LIST_HEAD(ebt_watchers);
64
65static struct ebt_target ebt_standard_target =
66{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
67
68static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
69 const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
70 const struct net_device *out)
71{
72 w->u.watcher->watcher(skb, hooknr, in, out, w->data,
73 w->watcher_size);
74 /* watchers don't give a verdict */
75 return 0;
76}
77
78static inline int ebt_do_match (struct ebt_entry_match *m,
79 const struct sk_buff *skb, const struct net_device *in,
80 const struct net_device *out)
81{
82 return m->u.match->match(skb, in, out, m->data,
83 m->match_size);
84}
85
86static inline int ebt_dev_check(char *entry, const struct net_device *device)
87{
88 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080089 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91 if (*entry == '\0')
92 return 0;
93 if (!device)
94 return 1;
95 /* 1 is the wildcard token */
96 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
97 i++;
98 return (devname[i] != entry[i] && entry[i] != 1);
99}
100
101#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
102/* process standard matches */
103static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
104 const struct net_device *in, const struct net_device *out)
105{
106 int verdict, i;
107
108 if (e->bitmask & EBT_802_3) {
109 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
110 return 1;
111 } else if (!(e->bitmask & EBT_NOPROTO) &&
112 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
113 return 1;
114
115 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
116 return 1;
117 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
118 return 1;
119 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
121 return 1;
122 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
123 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
124 return 1;
125
126 if (e->bitmask & EBT_SOURCEMAC) {
127 verdict = 0;
128 for (i = 0; i < 6; i++)
129 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
130 e->sourcemsk[i];
131 if (FWINV2(verdict != 0, EBT_ISOURCE) )
132 return 1;
133 }
134 if (e->bitmask & EBT_DESTMAC) {
135 verdict = 0;
136 for (i = 0; i < 6; i++)
137 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
138 e->destmsk[i];
139 if (FWINV2(verdict != 0, EBT_IDEST) )
140 return 1;
141 }
142 return 0;
143}
144
145/* Do some firewalling */
146unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
147 const struct net_device *in, const struct net_device *out,
148 struct ebt_table *table)
149{
150 int i, nentries;
151 struct ebt_entry *point;
152 struct ebt_counter *counter_base, *cb_base;
153 struct ebt_entry_target *t;
154 int verdict, sp = 0;
155 struct ebt_chainstack *cs;
156 struct ebt_entries *chaininfo;
157 char *base;
158 struct ebt_table_info *private;
159
160 read_lock_bh(&table->lock);
161 private = table->private;
162 cb_base = COUNTER_BASE(private->counters, private->nentries,
163 smp_processor_id());
164 if (private->chainstack)
165 cs = private->chainstack[smp_processor_id()];
166 else
167 cs = NULL;
168 chaininfo = private->hook_entry[hook];
169 nentries = private->hook_entry[hook]->nentries;
170 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
171 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
172 /* base for chain jumps */
173 base = private->entries;
174 i = 0;
175 while (i < nentries) {
176 if (ebt_basic_match(point, eth_hdr(*pskb), in, out))
177 goto letscontinue;
178
179 if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)
180 goto letscontinue;
181
182 /* increase counter */
183 (*(counter_base + i)).pcnt++;
184 (*(counter_base + i)).bcnt+=(**pskb).len;
185
186 /* these should only watch: not modify, nor tell us
187 what to do with the packet */
188 EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, hook, in,
189 out);
190
191 t = (struct ebt_entry_target *)
192 (((char *)point) + point->target_offset);
193 /* standard target */
194 if (!t->u.target->target)
195 verdict = ((struct ebt_standard_target *)t)->verdict;
196 else
197 verdict = t->u.target->target(pskb, hook,
198 in, out, t->data, t->target_size);
199 if (verdict == EBT_ACCEPT) {
200 read_unlock_bh(&table->lock);
201 return NF_ACCEPT;
202 }
203 if (verdict == EBT_DROP) {
204 read_unlock_bh(&table->lock);
205 return NF_DROP;
206 }
207 if (verdict == EBT_RETURN) {
208letsreturn:
209#ifdef CONFIG_NETFILTER_DEBUG
210 if (sp == 0) {
211 BUGPRINT("RETURN on base chain");
212 /* act like this is EBT_CONTINUE */
213 goto letscontinue;
214 }
215#endif
216 sp--;
217 /* put all the local variables right */
218 i = cs[sp].n;
219 chaininfo = cs[sp].chaininfo;
220 nentries = chaininfo->nentries;
221 point = cs[sp].e;
222 counter_base = cb_base +
223 chaininfo->counter_offset;
224 continue;
225 }
226 if (verdict == EBT_CONTINUE)
227 goto letscontinue;
228#ifdef CONFIG_NETFILTER_DEBUG
229 if (verdict < 0) {
230 BUGPRINT("bogus standard verdict\n");
231 read_unlock_bh(&table->lock);
232 return NF_DROP;
233 }
234#endif
235 /* jump to a udc */
236 cs[sp].n = i + 1;
237 cs[sp].chaininfo = chaininfo;
238 cs[sp].e = (struct ebt_entry *)
239 (((char *)point) + point->next_offset);
240 i = 0;
241 chaininfo = (struct ebt_entries *) (base + verdict);
242#ifdef CONFIG_NETFILTER_DEBUG
243 if (chaininfo->distinguisher) {
244 BUGPRINT("jump to non-chain\n");
245 read_unlock_bh(&table->lock);
246 return NF_DROP;
247 }
248#endif
249 nentries = chaininfo->nentries;
250 point = (struct ebt_entry *)chaininfo->data;
251 counter_base = cb_base + chaininfo->counter_offset;
252 sp++;
253 continue;
254letscontinue:
255 point = (struct ebt_entry *)
256 (((char *)point) + point->next_offset);
257 i++;
258 }
259
260 /* I actually like this :) */
261 if (chaininfo->policy == EBT_RETURN)
262 goto letsreturn;
263 if (chaininfo->policy == EBT_ACCEPT) {
264 read_unlock_bh(&table->lock);
265 return NF_ACCEPT;
266 }
267 read_unlock_bh(&table->lock);
268 return NF_DROP;
269}
270
271/* If it succeeds, returns element and locks mutex */
272static inline void *
273find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800274 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700276 struct {
277 struct list_head list;
278 char name[EBT_FUNCTION_MAXNAMELEN];
279 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Ingo Molnar57b47a52006-03-20 22:35:41 -0800281 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (*error != 0)
283 return NULL;
284
Patrick McHardydf0933d2006-09-20 11:57:53 -0700285 list_for_each_entry(e, head, list) {
286 if (strcmp(e->name, name) == 0)
287 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700289 *error = -ENOENT;
290 mutex_unlock(mutex);
291 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
294#ifndef CONFIG_KMOD
295#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
296#else
297static void *
298find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800299 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 void *ret;
302
303 ret = find_inlist_lock_noload(head, name, error, mutex);
304 if (!ret) {
305 request_module("%s%s", prefix, name);
306 ret = find_inlist_lock_noload(head, name, error, mutex);
307 }
308 return ret;
309}
310#endif
311
312static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800313find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
315 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
316}
317
318static inline struct ebt_match *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800319find_match_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
322}
323
324static inline struct ebt_watcher *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800325find_watcher_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327 return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
328}
329
330static inline struct ebt_target *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800331find_target_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
334}
335
336static inline int
337ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
338 const char *name, unsigned int hookmask, unsigned int *cnt)
339{
340 struct ebt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800341 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 int ret;
343
Al Viro14197d52006-11-30 19:25:21 -0800344 if (left < sizeof(struct ebt_entry_match) ||
345 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return -EINVAL;
347 match = find_match_lock(m->u.name, &ret, &ebt_mutex);
348 if (!match)
349 return ret;
350 m->u.match = match;
351 if (!try_module_get(match->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800352 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return -ENOENT;
354 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800355 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (match->check &&
357 match->check(name, hookmask, e, m->data, m->match_size) != 0) {
358 BUGPRINT("match->check failed\n");
359 module_put(match->me);
360 return -EINVAL;
361 }
362 (*cnt)++;
363 return 0;
364}
365
366static inline int
367ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
368 const char *name, unsigned int hookmask, unsigned int *cnt)
369{
370 struct ebt_watcher *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800371 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int ret;
373
Al Viro14197d52006-11-30 19:25:21 -0800374 if (left < sizeof(struct ebt_entry_watcher) ||
375 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return -EINVAL;
377 watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
378 if (!watcher)
379 return ret;
380 w->u.watcher = watcher;
381 if (!try_module_get(watcher->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800382 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 return -ENOENT;
384 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800385 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 if (watcher->check &&
387 watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
388 BUGPRINT("watcher->check failed\n");
389 module_put(watcher->me);
390 return -EINVAL;
391 }
392 (*cnt)++;
393 return 0;
394}
395
Al Viro70fe9af2006-11-30 19:26:14 -0800396static int ebt_verify_pointers(struct ebt_replace *repl,
397 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
Al Viro70fe9af2006-11-30 19:26:14 -0800399 unsigned int limit = repl->entries_size;
400 unsigned int valid_hooks = repl->valid_hooks;
401 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 int i;
403
Al Viroe4fd77d2006-11-30 19:26:35 -0800404 for (i = 0; i < NF_BR_NUMHOOKS; i++)
405 newinfo->hook_entry[i] = NULL;
406
407 newinfo->entries_size = repl->entries_size;
408 newinfo->nentries = repl->nentries;
409
Al Viro70fe9af2006-11-30 19:26:14 -0800410 while (offset < limit) {
411 size_t left = limit - offset;
412 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
Al Viro22b440b2006-11-30 19:25:51 -0800416
Al Viro70fe9af2006-11-30 19:26:14 -0800417 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
418 if ((valid_hooks & (1 << i)) == 0)
419 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800420 if ((char __user *)repl->hook_entry[i] ==
421 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800422 break;
423 }
424
425 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
426 if (e->bitmask != 0) {
427 /* we make userspace set this right,
428 so there is no misunderstanding */
429 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
430 "in distinguisher\n");
431 return -EINVAL;
432 }
433 if (i != NF_BR_NUMHOOKS)
434 newinfo->hook_entry[i] = (struct ebt_entries *)e;
435 if (left < sizeof(struct ebt_entries))
436 break;
437 offset += sizeof(struct ebt_entries);
438 } else {
439 if (left < sizeof(struct ebt_entry))
440 break;
441 if (left < e->next_offset)
442 break;
443 offset += e->next_offset;
444 }
445 }
446 if (offset != limit) {
447 BUGPRINT("entries_size too small\n");
448 return -EINVAL;
449 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800450
451 /* check if all valid hooks have a chain */
452 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
453 if (!newinfo->hook_entry[i] &&
454 (valid_hooks & (1 << i))) {
455 BUGPRINT("Valid hook without chain\n");
456 return -EINVAL;
457 }
458 }
Al Viro70fe9af2006-11-30 19:26:14 -0800459 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800460}
461
462/*
463 * this one is very careful, as it is the first function
464 * to parse the userspace data
465 */
466static inline int
467ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800468 struct ebt_table_info *newinfo,
469 unsigned int *n, unsigned int *cnt,
470 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800471{
Al Viro22b440b2006-11-30 19:25:51 -0800472 int i;
473
474 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800475 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800476 break;
477 }
478 /* beginning of a new chain
479 if i == NF_BR_NUMHOOKS it must be a user defined chain */
480 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 /* this checks if the previous chain has as many entries
482 as it said it has */
483 if (*n != *cnt) {
484 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900485 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return -EINVAL;
487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
489 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
490 /* only RETURN from udc */
491 if (i != NF_BR_NUMHOOKS ||
492 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
493 BUGPRINT("bad policy\n");
494 return -EINVAL;
495 }
496 }
497 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
498 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
500 BUGPRINT("counter_offset != totalcnt");
501 return -EINVAL;
502 }
503 *n = ((struct ebt_entries *)e)->nentries;
504 *cnt = 0;
505 return 0;
506 }
507 /* a plain old entry, heh */
508 if (sizeof(struct ebt_entry) > e->watchers_offset ||
509 e->watchers_offset > e->target_offset ||
510 e->target_offset >= e->next_offset) {
511 BUGPRINT("entry offsets not in right order\n");
512 return -EINVAL;
513 }
514 /* this is not checked anywhere else */
515 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
516 BUGPRINT("target size too small\n");
517 return -EINVAL;
518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 (*cnt)++;
520 (*totalcnt)++;
521 return 0;
522}
523
524struct ebt_cl_stack
525{
526 struct ebt_chainstack cs;
527 int from;
528 unsigned int hookmask;
529};
530
531/*
532 * we need these positions to check that the jumps to a different part of the
533 * entries is a jump to the beginning of a new chain.
534 */
535static inline int
536ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800537 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
539 int i;
540
541 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800542 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return 0;
544 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
546 break;
547 }
548 /* only care about udc */
549 if (i != NF_BR_NUMHOOKS)
550 return 0;
551
552 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
553 /* these initialisations are depended on later in check_chainloops() */
554 udc[*n].cs.n = 0;
555 udc[*n].hookmask = 0;
556
557 (*n)++;
558 return 0;
559}
560
561static inline int
562ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
563{
564 if (i && (*i)-- == 0)
565 return 1;
566 if (m->u.match->destroy)
567 m->u.match->destroy(m->data, m->match_size);
568 module_put(m->u.match->me);
569
570 return 0;
571}
572
573static inline int
574ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
575{
576 if (i && (*i)-- == 0)
577 return 1;
578 if (w->u.watcher->destroy)
579 w->u.watcher->destroy(w->data, w->watcher_size);
580 module_put(w->u.watcher->me);
581
582 return 0;
583}
584
585static inline int
586ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
587{
588 struct ebt_entry_target *t;
589
Al Viro40642f92006-11-30 19:24:12 -0800590 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 return 0;
592 /* we're done */
593 if (cnt && (*cnt)-- == 0)
594 return 1;
595 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
596 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
597 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
598 if (t->u.target->destroy)
599 t->u.target->destroy(t->data, t->target_size);
600 module_put(t->u.target->me);
601
602 return 0;
603}
604
605static inline int
606ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800607 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
609{
610 struct ebt_entry_target *t;
611 struct ebt_target *target;
612 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800613 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 int ret;
615
616 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800617 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return 0;
619
620 if (e->bitmask & ~EBT_F_MASK) {
621 BUGPRINT("Unknown flag for bitmask\n");
622 return -EINVAL;
623 }
624 if (e->invflags & ~EBT_INV_MASK) {
625 BUGPRINT("Unknown flag for inv bitmask\n");
626 return -EINVAL;
627 }
628 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
629 BUGPRINT("NOPROTO & 802_3 not allowed\n");
630 return -EINVAL;
631 }
632 /* what hook do we belong to? */
633 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800634 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 continue;
636 if ((char *)newinfo->hook_entry[i] < (char *)e)
637 hook = i;
638 else
639 break;
640 }
641 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
642 a base chain */
643 if (i < NF_BR_NUMHOOKS)
644 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
645 else {
646 for (i = 0; i < udc_cnt; i++)
647 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
648 break;
649 if (i == 0)
650 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
651 else
652 hookmask = cl_s[i - 1].hookmask;
653 }
654 i = 0;
655 ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
656 if (ret != 0)
657 goto cleanup_matches;
658 j = 0;
659 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
660 if (ret != 0)
661 goto cleanup_watchers;
662 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800663 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 target = find_target_lock(t->u.name, &ret, &ebt_mutex);
665 if (!target)
666 goto cleanup_watchers;
667 if (!try_module_get(target->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800668 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 ret = -ENOENT;
670 goto cleanup_watchers;
671 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800672 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 t->u.target = target;
675 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800676 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 BUGPRINT("Standard target size too big\n");
678 ret = -EFAULT;
679 goto cleanup_watchers;
680 }
681 if (((struct ebt_standard_target *)t)->verdict <
682 -NUM_STANDARD_TARGETS) {
683 BUGPRINT("Invalid standard target\n");
684 ret = -EFAULT;
685 goto cleanup_watchers;
686 }
Al Viro14197d52006-11-30 19:25:21 -0800687 } else if (t->target_size > gap - sizeof(struct ebt_entry_target) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 (t->u.target->check &&
689 t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
690 module_put(t->u.target->me);
691 ret = -EFAULT;
692 goto cleanup_watchers;
693 }
694 (*cnt)++;
695 return 0;
696cleanup_watchers:
697 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
698cleanup_matches:
699 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
700 return ret;
701}
702
703/*
704 * checks for loops and sets the hook mask for udc
705 * the hook mask for udc tells us from which base chains the udc can be
706 * accessed. This mask is a parameter to the check() functions of the extensions
707 */
708static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
709 unsigned int udc_cnt, unsigned int hooknr, char *base)
710{
711 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
712 struct ebt_entry *e = (struct ebt_entry *)chain->data;
713 struct ebt_entry_target *t;
714
715 while (pos < nentries || chain_nr != -1) {
716 /* end of udc, go back one 'recursion' step */
717 if (pos == nentries) {
718 /* put back values of the time when this chain was called */
719 e = cl_s[chain_nr].cs.e;
720 if (cl_s[chain_nr].from != -1)
721 nentries =
722 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
723 else
724 nentries = chain->nentries;
725 pos = cl_s[chain_nr].cs.n;
726 /* make sure we won't see a loop that isn't one */
727 cl_s[chain_nr].cs.n = 0;
728 chain_nr = cl_s[chain_nr].from;
729 if (pos == nentries)
730 continue;
731 }
732 t = (struct ebt_entry_target *)
733 (((char *)e) + e->target_offset);
734 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
735 goto letscontinue;
736 if (e->target_offset + sizeof(struct ebt_standard_target) >
737 e->next_offset) {
738 BUGPRINT("Standard target size too big\n");
739 return -1;
740 }
741 verdict = ((struct ebt_standard_target *)t)->verdict;
742 if (verdict >= 0) { /* jump to another chain */
743 struct ebt_entries *hlp2 =
744 (struct ebt_entries *)(base + verdict);
745 for (i = 0; i < udc_cnt; i++)
746 if (hlp2 == cl_s[i].cs.chaininfo)
747 break;
748 /* bad destination or loop */
749 if (i == udc_cnt) {
750 BUGPRINT("bad destination\n");
751 return -1;
752 }
753 if (cl_s[i].cs.n) {
754 BUGPRINT("loop\n");
755 return -1;
756 }
Al Viro98a08242006-11-30 19:24:49 -0800757 if (cl_s[i].hookmask & (1 << hooknr))
758 goto letscontinue;
759 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 cl_s[i].cs.n = pos + 1;
761 pos = 0;
762 cl_s[i].cs.e = ((void *)e + e->next_offset);
763 e = (struct ebt_entry *)(hlp2->data);
764 nentries = hlp2->nentries;
765 cl_s[i].from = chain_nr;
766 chain_nr = i;
767 /* this udc is accessible from the base chain for hooknr */
768 cl_s[i].hookmask |= (1 << hooknr);
769 continue;
770 }
771letscontinue:
772 e = (void *)e + e->next_offset;
773 pos++;
774 }
775 return 0;
776}
777
778/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800779static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 unsigned int i, j, k, udc_cnt;
782 int ret;
783 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
784
785 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800786 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 i++;
788 if (i == NF_BR_NUMHOOKS) {
789 BUGPRINT("No valid hooks specified\n");
790 return -EINVAL;
791 }
Al Viro1f072c92006-11-30 19:26:53 -0800792 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 BUGPRINT("Chains don't start at beginning\n");
794 return -EINVAL;
795 }
796 /* make sure chains are ordered after each other in same order
797 as their corresponding hooks */
798 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800799 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800801 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 BUGPRINT("Hook order must be followed\n");
803 return -EINVAL;
804 }
805 i = j;
806 }
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 /* do some early checkings and initialize some things */
809 i = 0; /* holds the expected nr. of entries for the chain */
810 j = 0; /* holds the up to now counted entries for the chain */
811 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900812 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
814 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800815 ebt_check_entry_size_and_hooks, newinfo,
816 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 if (ret != 0)
819 return ret;
820
821 if (i != j) {
822 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900823 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return -EINVAL;
825 }
826 if (k != newinfo->nentries) {
827 BUGPRINT("Total nentries is wrong\n");
828 return -EINVAL;
829 }
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 /* get the location of the udc, put them in an array
832 while we're at it, allocate the chainstack */
833 if (udc_cnt) {
834 /* this will get free'd in do_replace()/ebt_register_table()
835 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700836 newinfo->chainstack =
837 vmalloc((highest_possible_processor_id()+1)
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900838 * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (!newinfo->chainstack)
840 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700841 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700843 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 if (!newinfo->chainstack[i]) {
845 while (i)
846 vfree(newinfo->chainstack[--i]);
847 vfree(newinfo->chainstack);
848 newinfo->chainstack = NULL;
849 return -ENOMEM;
850 }
851 }
852
Jayachandran C18bc89a2006-04-20 00:14:49 -0700853 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 if (!cl_s)
855 return -ENOMEM;
856 i = 0; /* the i'th udc */
857 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800858 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* sanity check */
860 if (i != udc_cnt) {
861 BUGPRINT("i != udc_cnt\n");
862 vfree(cl_s);
863 return -EFAULT;
864 }
865 }
866
867 /* Check for loops */
868 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800869 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (check_chainloops(newinfo->hook_entry[i],
871 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700872 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return -EINVAL;
874 }
875
876 /* we now know the following (along with E=mc²):
877 - the nr of entries in each chain is right
878 - the size of the allocated space is right
879 - all valid hooks have a corresponding chain
880 - there are no loops
881 - wrong data can still be on the level of a single entry
882 - could be there are jumps to places that are not the
883 beginning of a chain. This can only occur in chains that
884 are not accessible from any base chains, so we don't care. */
885
886 /* used to know what we need to clean up if something goes wrong */
887 i = 0;
888 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800889 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (ret != 0) {
891 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
892 ebt_cleanup_entry, &i);
893 }
James Lamanna68d31872005-06-22 22:12:57 -0700894 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 return ret;
896}
897
898/* called under write_lock */
899static void get_counters(struct ebt_counter *oldcounters,
900 struct ebt_counter *counters, unsigned int nentries)
901{
902 int i, cpu;
903 struct ebt_counter *counter_base;
904
905 /* counters of cpu 0 */
906 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700907 sizeof(struct ebt_counter) * nentries);
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700910 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700911 if (cpu == 0)
912 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
914 for (i = 0; i < nentries; i++) {
915 counters[i].pcnt += counter_base[i].pcnt;
916 counters[i].bcnt += counter_base[i].bcnt;
917 }
918 }
919}
920
921/* replace the table */
922static int do_replace(void __user *user, unsigned int len)
923{
924 int ret, i, countersize;
925 struct ebt_table_info *newinfo;
926 struct ebt_replace tmp;
927 struct ebt_table *t;
928 struct ebt_counter *counterstmp = NULL;
929 /* used to be able to unlock earlier */
930 struct ebt_table_info *table;
931
932 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
933 return -EFAULT;
934
935 if (len != sizeof(tmp) + tmp.entries_size) {
936 BUGPRINT("Wrong len argument\n");
937 return -EINVAL;
938 }
939
940 if (tmp.entries_size == 0) {
941 BUGPRINT("Entries_size never zero\n");
942 return -EINVAL;
943 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800944 /* overflow check */
945 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
946 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
947 return -ENOMEM;
948 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
949 return -ENOMEM;
950
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900951 countersize = COUNTER_OFFSET(tmp.nentries) *
David S. Millerc8923c62005-10-13 14:41:23 -0700952 (highest_possible_processor_id()+1);
Jayachandran C18bc89a2006-04-20 00:14:49 -0700953 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 if (!newinfo)
955 return -ENOMEM;
956
957 if (countersize)
958 memset(newinfo->counters, 0, countersize);
959
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800960 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if (!newinfo->entries) {
962 ret = -ENOMEM;
963 goto free_newinfo;
964 }
965 if (copy_from_user(
966 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
967 BUGPRINT("Couldn't copy entries from userspace\n");
968 ret = -EFAULT;
969 goto free_entries;
970 }
971
972 /* the user wants counters back
973 the check on the size is done later, when we have the lock */
974 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700975 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (!counterstmp) {
977 ret = -ENOMEM;
978 goto free_entries;
979 }
980 }
981 else
982 counterstmp = NULL;
983
984 /* this can get initialized by translate_table() */
985 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -0800986 ret = ebt_verify_pointers(&tmp, newinfo);
987 if (ret != 0)
988 goto free_counterstmp;
989
990 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 if (ret != 0)
993 goto free_counterstmp;
994
995 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
996 if (!t) {
997 ret = -ENOENT;
998 goto free_iterate;
999 }
1000
1001 /* the table doesn't like it */
1002 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1003 goto free_unlock;
1004
1005 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1006 BUGPRINT("Wrong nr. of counters requested\n");
1007 ret = -EINVAL;
1008 goto free_unlock;
1009 }
1010
1011 /* we have the mutex lock, so no danger in reading this pointer */
1012 table = t->private;
1013 /* make sure the table can only be rmmod'ed if it contains no rules */
1014 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1015 ret = -ENOENT;
1016 goto free_unlock;
1017 } else if (table->nentries && !newinfo->nentries)
1018 module_put(t->me);
1019 /* we need an atomic snapshot of the counters */
1020 write_lock_bh(&t->lock);
1021 if (tmp.num_counters)
1022 get_counters(t->private->counters, counterstmp,
1023 t->private->nentries);
1024
1025 t->private = newinfo;
1026 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001027 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 /* so, a user can change the chains while having messed up her counter
1029 allocation. Only reason why this is done is because this way the lock
1030 is held only once, while this doesn't bring the kernel into a
1031 dangerous state. */
1032 if (tmp.num_counters &&
1033 copy_to_user(tmp.counters, counterstmp,
1034 tmp.num_counters * sizeof(struct ebt_counter))) {
1035 BUGPRINT("Couldn't copy counters to userspace\n");
1036 ret = -EFAULT;
1037 }
1038 else
1039 ret = 0;
1040
1041 /* decrease module count and free resources */
1042 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1043 ebt_cleanup_entry, NULL);
1044
1045 vfree(table->entries);
1046 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001047 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 vfree(table->chainstack[i]);
1049 vfree(table->chainstack);
1050 }
1051 vfree(table);
1052
James Lamanna68d31872005-06-22 22:12:57 -07001053 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return ret;
1055
1056free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001057 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058free_iterate:
1059 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1060 ebt_cleanup_entry, NULL);
1061free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001062 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 /* can be initialized in translate_table() */
1064 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001065 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 vfree(newinfo->chainstack[i]);
1067 vfree(newinfo->chainstack);
1068 }
1069free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001070 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001072 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 return ret;
1074}
1075
1076int ebt_register_target(struct ebt_target *target)
1077{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001078 struct ebt_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 int ret;
1080
Ingo Molnar57b47a52006-03-20 22:35:41 -08001081 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (ret != 0)
1083 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001084 list_for_each_entry(t, &ebt_targets, list) {
1085 if (strcmp(t->name, target->name) == 0) {
1086 mutex_unlock(&ebt_mutex);
1087 return -EEXIST;
1088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001090 list_add(&target->list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001091 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093 return 0;
1094}
1095
1096void ebt_unregister_target(struct ebt_target *target)
1097{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001098 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001099 list_del(&target->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001100 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101}
1102
1103int ebt_register_match(struct ebt_match *match)
1104{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001105 struct ebt_match *m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 int ret;
1107
Ingo Molnar57b47a52006-03-20 22:35:41 -08001108 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if (ret != 0)
1110 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001111 list_for_each_entry(m, &ebt_matches, list) {
1112 if (strcmp(m->name, match->name) == 0) {
1113 mutex_unlock(&ebt_mutex);
1114 return -EEXIST;
1115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001117 list_add(&match->list, &ebt_matches);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001118 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120 return 0;
1121}
1122
1123void ebt_unregister_match(struct ebt_match *match)
1124{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001125 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001126 list_del(&match->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001127 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128}
1129
1130int ebt_register_watcher(struct ebt_watcher *watcher)
1131{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001132 struct ebt_watcher *w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 int ret;
1134
Ingo Molnar57b47a52006-03-20 22:35:41 -08001135 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 if (ret != 0)
1137 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001138 list_for_each_entry(w, &ebt_watchers, list) {
1139 if (strcmp(w->name, watcher->name) == 0) {
1140 mutex_unlock(&ebt_mutex);
1141 return -EEXIST;
1142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001144 list_add(&watcher->list, &ebt_watchers);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001145 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 return 0;
1148}
1149
1150void ebt_unregister_watcher(struct ebt_watcher *watcher)
1151{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001152 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001153 list_del(&watcher->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001154 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155}
1156
1157int ebt_register_table(struct ebt_table *table)
1158{
1159 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001160 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001161 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001163 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Al Virodf07a812006-11-30 19:28:25 -08001165 if (!table || !(repl = table->table) || !repl->entries ||
1166 repl->entries_size == 0 ||
1167 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1169 return -EINVAL;
1170 }
1171
Al Virodf07a812006-11-30 19:28:25 -08001172 countersize = COUNTER_OFFSET(repl->nentries) *
David S. Millerc8923c62005-10-13 14:41:23 -07001173 (highest_possible_processor_id()+1);
Jayachandran C18bc89a2006-04-20 00:14:49 -07001174 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 ret = -ENOMEM;
1176 if (!newinfo)
1177 return -ENOMEM;
1178
Al Virodf07a812006-11-30 19:28:25 -08001179 p = vmalloc(repl->entries_size);
1180 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 goto free_newinfo;
1182
Al Virodf07a812006-11-30 19:28:25 -08001183 memcpy(p, repl->entries, repl->entries_size);
1184 newinfo->entries = p;
1185
1186 newinfo->entries_size = repl->entries_size;
1187 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 if (countersize)
1190 memset(newinfo->counters, 0, countersize);
1191
1192 /* fill in newinfo and parse the entries */
1193 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001194 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1195 if ((repl->valid_hooks & (1 << i)) == 0)
1196 newinfo->hook_entry[i] = NULL;
1197 else
1198 newinfo->hook_entry[i] = p +
1199 ((char *)repl->hook_entry[i] - repl->entries);
1200 }
1201 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (ret != 0) {
1203 BUGPRINT("Translate_table failed\n");
1204 goto free_chainstack;
1205 }
1206
1207 if (table->check && table->check(newinfo, table->valid_hooks)) {
1208 BUGPRINT("The table doesn't like its own initial data, lol\n");
1209 return -EINVAL;
1210 }
1211
1212 table->private = newinfo;
1213 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001214 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 if (ret != 0)
1216 goto free_chainstack;
1217
Patrick McHardydf0933d2006-09-20 11:57:53 -07001218 list_for_each_entry(t, &ebt_tables, list) {
1219 if (strcmp(t->name, table->name) == 0) {
1220 ret = -EEXIST;
1221 BUGPRINT("Table name already exists\n");
1222 goto free_unlock;
1223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 }
1225
1226 /* Hold a reference count if the chains aren't empty */
1227 if (newinfo->nentries && !try_module_get(table->me)) {
1228 ret = -ENOENT;
1229 goto free_unlock;
1230 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001231 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001232 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 return 0;
1234free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001235 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236free_chainstack:
1237 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001238 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 vfree(newinfo->chainstack[i]);
1240 vfree(newinfo->chainstack);
1241 }
1242 vfree(newinfo->entries);
1243free_newinfo:
1244 vfree(newinfo);
1245 return ret;
1246}
1247
1248void ebt_unregister_table(struct ebt_table *table)
1249{
1250 int i;
1251
1252 if (!table) {
1253 BUGPRINT("Request to unregister NULL table!!!\n");
1254 return;
1255 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001256 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001257 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001258 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001259 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001261 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 vfree(table->private->chainstack[i]);
1263 vfree(table->private->chainstack);
1264 }
1265 vfree(table->private);
1266}
1267
1268/* userspace just supplied us with counters */
1269static int update_counters(void __user *user, unsigned int len)
1270{
1271 int i, ret;
1272 struct ebt_counter *tmp;
1273 struct ebt_replace hlp;
1274 struct ebt_table *t;
1275
1276 if (copy_from_user(&hlp, user, sizeof(hlp)))
1277 return -EFAULT;
1278
1279 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1280 return -EINVAL;
1281 if (hlp.num_counters == 0)
1282 return -EINVAL;
1283
Jayachandran C18bc89a2006-04-20 00:14:49 -07001284 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 MEMPRINT("Update_counters && nomemory\n");
1286 return -ENOMEM;
1287 }
1288
1289 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1290 if (!t)
1291 goto free_tmp;
1292
1293 if (hlp.num_counters != t->private->nentries) {
1294 BUGPRINT("Wrong nr of counters\n");
1295 ret = -EINVAL;
1296 goto unlock_mutex;
1297 }
1298
1299 if ( copy_from_user(tmp, hlp.counters,
1300 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1301 BUGPRINT("Updata_counters && !cfu\n");
1302 ret = -EFAULT;
1303 goto unlock_mutex;
1304 }
1305
1306 /* we want an atomic add of the counters */
1307 write_lock_bh(&t->lock);
1308
1309 /* we add to the counters of the first cpu */
1310 for (i = 0; i < hlp.num_counters; i++) {
1311 t->private->counters[i].pcnt += tmp[i].pcnt;
1312 t->private->counters[i].bcnt += tmp[i].bcnt;
1313 }
1314
1315 write_unlock_bh(&t->lock);
1316 ret = 0;
1317unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001318 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319free_tmp:
1320 vfree(tmp);
1321 return ret;
1322}
1323
1324static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001325 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
Al Viro1e419cd2006-11-30 19:28:48 -08001327 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1329 return -EFAULT;
1330 return 0;
1331}
1332
1333static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001334 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335{
Al Viro1e419cd2006-11-30 19:28:48 -08001336 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1338 return -EFAULT;
1339 return 0;
1340}
1341
Al Viro1e419cd2006-11-30 19:28:48 -08001342static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
1344 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001345 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 struct ebt_entry_target *t;
1347
Al Viro40642f92006-11-30 19:24:12 -08001348 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return 0;
1350
Al Viro1e419cd2006-11-30 19:28:48 -08001351 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1355 if (ret != 0)
1356 return ret;
1357 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1358 if (ret != 0)
1359 return ret;
1360 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1361 return -EFAULT;
1362 return 0;
1363}
1364
Ingo Molnar57b47a52006-03-20 22:35:41 -08001365/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1367 int *len, int cmd)
1368{
1369 struct ebt_replace tmp;
1370 struct ebt_counter *counterstmp, *oldcounters;
1371 unsigned int entries_size, nentries;
1372 char *entries;
1373
1374 if (cmd == EBT_SO_GET_ENTRIES) {
1375 entries_size = t->private->entries_size;
1376 nentries = t->private->nentries;
1377 entries = t->private->entries;
1378 oldcounters = t->private->counters;
1379 } else {
1380 entries_size = t->table->entries_size;
1381 nentries = t->table->nentries;
1382 entries = t->table->entries;
1383 oldcounters = t->table->counters;
1384 }
1385
1386 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1387 BUGPRINT("Cfu didn't work\n");
1388 return -EFAULT;
1389 }
1390
1391 if (*len != sizeof(struct ebt_replace) + entries_size +
1392 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1393 BUGPRINT("Wrong size\n");
1394 return -EINVAL;
1395 }
1396
1397 if (tmp.nentries != nentries) {
1398 BUGPRINT("Nentries wrong\n");
1399 return -EINVAL;
1400 }
1401
1402 if (tmp.entries_size != entries_size) {
1403 BUGPRINT("Wrong size\n");
1404 return -EINVAL;
1405 }
1406
1407 /* userspace might not need the counters */
1408 if (tmp.num_counters) {
1409 if (tmp.num_counters != nentries) {
1410 BUGPRINT("Num_counters wrong\n");
1411 return -EINVAL;
1412 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001413 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 if (!counterstmp) {
1415 MEMPRINT("Couldn't copy counters, out of memory\n");
1416 return -ENOMEM;
1417 }
1418 write_lock_bh(&t->lock);
1419 get_counters(oldcounters, counterstmp, nentries);
1420 write_unlock_bh(&t->lock);
1421
1422 if (copy_to_user(tmp.counters, counterstmp,
1423 nentries * sizeof(struct ebt_counter))) {
1424 BUGPRINT("Couldn't copy counters to userspace\n");
1425 vfree(counterstmp);
1426 return -EFAULT;
1427 }
1428 vfree(counterstmp);
1429 }
1430
1431 if (copy_to_user(tmp.entries, entries, entries_size)) {
1432 BUGPRINT("Couldn't copy entries to userspace\n");
1433 return -EFAULT;
1434 }
1435 /* set the match/watcher/target names right */
1436 return EBT_ENTRY_ITERATE(entries, entries_size,
1437 ebt_make_names, entries, tmp.entries);
1438}
1439
1440static int do_ebt_set_ctl(struct sock *sk,
1441 int cmd, void __user *user, unsigned int len)
1442{
1443 int ret;
1444
1445 switch(cmd) {
1446 case EBT_SO_SET_ENTRIES:
1447 ret = do_replace(user, len);
1448 break;
1449 case EBT_SO_SET_COUNTERS:
1450 ret = update_counters(user, len);
1451 break;
1452 default:
1453 ret = -EINVAL;
1454 }
1455 return ret;
1456}
1457
1458static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1459{
1460 int ret;
1461 struct ebt_replace tmp;
1462 struct ebt_table *t;
1463
1464 if (copy_from_user(&tmp, user, sizeof(tmp)))
1465 return -EFAULT;
1466
1467 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1468 if (!t)
1469 return ret;
1470
1471 switch(cmd) {
1472 case EBT_SO_GET_INFO:
1473 case EBT_SO_GET_INIT_INFO:
1474 if (*len != sizeof(struct ebt_replace)){
1475 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001476 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 break;
1478 }
1479 if (cmd == EBT_SO_GET_INFO) {
1480 tmp.nentries = t->private->nentries;
1481 tmp.entries_size = t->private->entries_size;
1482 tmp.valid_hooks = t->valid_hooks;
1483 } else {
1484 tmp.nentries = t->table->nentries;
1485 tmp.entries_size = t->table->entries_size;
1486 tmp.valid_hooks = t->table->valid_hooks;
1487 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001488 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (copy_to_user(user, &tmp, *len) != 0){
1490 BUGPRINT("c2u Didn't work\n");
1491 ret = -EFAULT;
1492 break;
1493 }
1494 ret = 0;
1495 break;
1496
1497 case EBT_SO_GET_ENTRIES:
1498 case EBT_SO_GET_INIT_ENTRIES:
1499 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001500 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 break;
1502
1503 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001504 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 ret = -EINVAL;
1506 }
1507
1508 return ret;
1509}
1510
1511static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001512{
1513 .pf = PF_INET,
1514 .set_optmin = EBT_BASE_CTL,
1515 .set_optmax = EBT_SO_SET_MAX + 1,
1516 .set = do_ebt_set_ctl,
1517 .get_optmin = EBT_BASE_CTL,
1518 .get_optmax = EBT_SO_GET_MAX + 1,
1519 .get = do_ebt_get_ctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520};
1521
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001522static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
1524 int ret;
1525
Ingo Molnar57b47a52006-03-20 22:35:41 -08001526 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001527 list_add(&ebt_standard_target.list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001528 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
1530 return ret;
1531
1532 printk(KERN_NOTICE "Ebtables v2.0 registered\n");
1533 return 0;
1534}
1535
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001536static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
1538 nf_unregister_sockopt(&ebt_sockopts);
1539 printk(KERN_NOTICE "Ebtables v2.0 unregistered\n");
1540}
1541
1542EXPORT_SYMBOL(ebt_register_table);
1543EXPORT_SYMBOL(ebt_unregister_table);
1544EXPORT_SYMBOL(ebt_register_match);
1545EXPORT_SYMBOL(ebt_unregister_match);
1546EXPORT_SYMBOL(ebt_register_watcher);
1547EXPORT_SYMBOL(ebt_unregister_watcher);
1548EXPORT_SYMBOL(ebt_register_target);
1549EXPORT_SYMBOL(ebt_unregister_target);
1550EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001551module_init(ebtables_init);
1552module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553MODULE_LICENSE("GPL");