1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/kmod.h>
20#include <linux/module.h>
21#include <linux/vmalloc.h>
22#include <linux/netfilter/x_tables.h>
23#include <linux/netfilter_bridge/ebtables.h>
24#include <linux/spinlock.h>
25#include <linux/mutex.h>
26#include <asm/uaccess.h>
27#include <linux/smp.h>
28#include <linux/cpumask.h>
29#include <net/sock.h>
30
31#include "../br_private.h"
32
33#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
34 "report to author: "format, ## args)
35
36#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
37 ": out of memory: "format, ## args)
38
39
40
41
42
43
44
45
46
47
48
49
50#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
51#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
52#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
53 COUNTER_OFFSET(n) * cpu))
54
55
56
57static DEFINE_MUTEX(ebt_mutex);
58
59static struct xt_target ebt_standard_target = {
60 .name = "standard",
61 .revision = 0,
62 .family = NFPROTO_BRIDGE,
63 .targetsize = sizeof(int),
64};
65
66static inline int
67ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
68 struct xt_target_param *par)
69{
70 par->target = w->u.watcher;
71 par->targinfo = w->data;
72 w->u.watcher->target(skb, par);
73
74 return 0;
75}
76
77static inline int ebt_do_match (struct ebt_entry_match *m,
78 const struct sk_buff *skb, struct xt_match_param *par)
79{
80 par->match = m->u.match;
81 par->matchinfo = m->data;
82 return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
83}
84
85static inline int ebt_dev_check(char *entry, const struct net_device *device)
86{
87 int i = 0;
88 const char *devname;
89
90 if (*entry == '\0')
91 return 0;
92 if (!device)
93 return 1;
94 devname = device->name;
95
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
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
145static inline __pure
146struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
147{
148 return (void *)entry + entry->next_offset;
149}
150
151
152unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
153 const struct net_device *in, const struct net_device *out,
154 struct ebt_table *table)
155{
156 int i, nentries;
157 struct ebt_entry *point;
158 struct ebt_counter *counter_base, *cb_base;
159 struct ebt_entry_target *t;
160 int verdict, sp = 0;
161 struct ebt_chainstack *cs;
162 struct ebt_entries *chaininfo;
163 char *base;
164 struct ebt_table_info *private;
165 bool hotdrop = false;
166 struct xt_match_param mtpar;
167 struct xt_target_param tgpar;
168
169 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
170 mtpar.in = tgpar.in = in;
171 mtpar.out = tgpar.out = out;
172 mtpar.hotdrop = &hotdrop;
173 mtpar.hooknum = tgpar.hooknum = hook;
174
175 read_lock_bh(&table->lock);
176 private = table->private;
177 cb_base = COUNTER_BASE(private->counters, private->nentries,
178 smp_processor_id());
179 if (private->chainstack)
180 cs = private->chainstack[smp_processor_id()];
181 else
182 cs = NULL;
183 chaininfo = private->hook_entry[hook];
184 nentries = private->hook_entry[hook]->nentries;
185 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
186 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
187
188 base = private->entries;
189 i = 0;
190 while (i < nentries) {
191 if (ebt_basic_match(point, eth_hdr(skb), in, out))
192 goto letscontinue;
193
194 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
195 goto letscontinue;
196 if (hotdrop) {
197 read_unlock_bh(&table->lock);
198 return NF_DROP;
199 }
200
201
202 (*(counter_base + i)).pcnt++;
203 (*(counter_base + i)).bcnt += skb->len;
204
205
206
207 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
208
209 t = (struct ebt_entry_target *)
210 (((char *)point) + point->target_offset);
211
212 if (!t->u.target->target)
213 verdict = ((struct ebt_standard_target *)t)->verdict;
214 else {
215 tgpar.target = t->u.target;
216 tgpar.targinfo = t->data;
217 verdict = t->u.target->target(skb, &tgpar);
218 }
219 if (verdict == EBT_ACCEPT) {
220 read_unlock_bh(&table->lock);
221 return NF_ACCEPT;
222 }
223 if (verdict == EBT_DROP) {
224 read_unlock_bh(&table->lock);
225 return NF_DROP;
226 }
227 if (verdict == EBT_RETURN) {
228letsreturn:
229#ifdef CONFIG_NETFILTER_DEBUG
230 if (sp == 0) {
231 BUGPRINT("RETURN on base chain");
232
233 goto letscontinue;
234 }
235#endif
236 sp--;
237
238 i = cs[sp].n;
239 chaininfo = cs[sp].chaininfo;
240 nentries = chaininfo->nentries;
241 point = cs[sp].e;
242 counter_base = cb_base +
243 chaininfo->counter_offset;
244 continue;
245 }
246 if (verdict == EBT_CONTINUE)
247 goto letscontinue;
248#ifdef CONFIG_NETFILTER_DEBUG
249 if (verdict < 0) {
250 BUGPRINT("bogus standard verdict\n");
251 read_unlock_bh(&table->lock);
252 return NF_DROP;
253 }
254#endif
255
256 cs[sp].n = i + 1;
257 cs[sp].chaininfo = chaininfo;
258 cs[sp].e = ebt_next_entry(point);
259 i = 0;
260 chaininfo = (struct ebt_entries *) (base + verdict);
261#ifdef CONFIG_NETFILTER_DEBUG
262 if (chaininfo->distinguisher) {
263 BUGPRINT("jump to non-chain\n");
264 read_unlock_bh(&table->lock);
265 return NF_DROP;
266 }
267#endif
268 nentries = chaininfo->nentries;
269 point = (struct ebt_entry *)chaininfo->data;
270 counter_base = cb_base + chaininfo->counter_offset;
271 sp++;
272 continue;
273letscontinue:
274 point = ebt_next_entry(point);
275 i++;
276 }
277
278
279 if (chaininfo->policy == EBT_RETURN)
280 goto letsreturn;
281 if (chaininfo->policy == EBT_ACCEPT) {
282 read_unlock_bh(&table->lock);
283 return NF_ACCEPT;
284 }
285 read_unlock_bh(&table->lock);
286 return NF_DROP;
287}
288
289
290static inline void *
291find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
292 struct mutex *mutex)
293{
294 struct {
295 struct list_head list;
296 char name[EBT_FUNCTION_MAXNAMELEN];
297 } *e;
298
299 *error = mutex_lock_interruptible(mutex);
300 if (*error != 0)
301 return NULL;
302
303 list_for_each_entry(e, head, list) {
304 if (strcmp(e->name, name) == 0)
305 return e;
306 }
307 *error = -ENOENT;
308 mutex_unlock(mutex);
309 return NULL;
310}
311
312static void *
313find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
314 int *error, struct mutex *mutex)
315{
316 return try_then_request_module(
317 find_inlist_lock_noload(head, name, error, mutex),
318 "%s%s", prefix, name);
319}
320
321static inline struct ebt_table *
322find_table_lock(struct net *net, const char *name, int *error,
323 struct mutex *mutex)
324{
325 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
326 "ebtable_", error, mutex);
327}
328
329static inline int
330ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
331 unsigned int *cnt)
332{
333 const struct ebt_entry *e = par->entryinfo;
334 struct xt_match *match;
335 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
336 int ret;
337
338 if (left < sizeof(struct ebt_entry_match) ||
339 left - sizeof(struct ebt_entry_match) < m->match_size)
340 return -EINVAL;
341
342 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
343 m->u.name, 0), "ebt_%s", m->u.name);
344 if (IS_ERR(match))
345 return PTR_ERR(match);
346 if (match == NULL)
347 return -ENOENT;
348 m->u.match = match;
349
350 par->match = match;
351 par->matchinfo = m->data;
352 ret = xt_check_match(par, m->match_size,
353 e->ethproto, e->invflags & EBT_IPROTO);
354 if (ret < 0) {
355 module_put(match->me);
356 return ret;
357 }
358
359 (*cnt)++;
360 return 0;
361}
362
363static inline int
364ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
365 unsigned int *cnt)
366{
367 const struct ebt_entry *e = par->entryinfo;
368 struct xt_target *watcher;
369 size_t left = ((char *)e + e->target_offset) - (char *)w;
370 int ret;
371
372 if (left < sizeof(struct ebt_entry_watcher) ||
373 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
374 return -EINVAL;
375
376 watcher = try_then_request_module(
377 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
378 "ebt_%s", w->u.name);
379 if (IS_ERR(watcher))
380 return PTR_ERR(watcher);
381 if (watcher == NULL)
382 return -ENOENT;
383 w->u.watcher = watcher;
384
385 par->target = watcher;
386 par->targinfo = w->data;
387 ret = xt_check_target(par, w->watcher_size,
388 e->ethproto, e->invflags & EBT_IPROTO);
389 if (ret < 0) {
390 module_put(watcher->me);
391 return ret;
392 }
393
394 (*cnt)++;
395 return 0;
396}
397
398static int ebt_verify_pointers(struct ebt_replace *repl,
399 struct ebt_table_info *newinfo)
400{
401 unsigned int limit = repl->entries_size;
402 unsigned int valid_hooks = repl->valid_hooks;
403 unsigned int offset = 0;
404 int i;
405
406 for (i = 0; i < NF_BR_NUMHOOKS; i++)
407 newinfo->hook_entry[i] = NULL;
408
409 newinfo->entries_size = repl->entries_size;
410 newinfo->nentries = repl->nentries;
411
412 while (offset < limit) {
413 size_t left = limit - offset;
414 struct ebt_entry *e = (void *)newinfo->entries + offset;
415
416 if (left < sizeof(unsigned int))
417 break;
418
419 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
420 if ((valid_hooks & (1 << i)) == 0)
421 continue;
422 if ((char __user *)repl->hook_entry[i] ==
423 repl->entries + offset)
424 break;
425 }
426
427 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
428 if (e->bitmask != 0) {
429
430
431 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
432 "in distinguisher\n");
433 return -EINVAL;
434 }
435 if (i != NF_BR_NUMHOOKS)
436 newinfo->hook_entry[i] = (struct ebt_entries *)e;
437 if (left < sizeof(struct ebt_entries))
438 break;
439 offset += sizeof(struct ebt_entries);
440 } else {
441 if (left < sizeof(struct ebt_entry))
442 break;
443 if (left < e->next_offset)
444 break;
445 offset += e->next_offset;
446 }
447 }
448 if (offset != limit) {
449 BUGPRINT("entries_size too small\n");
450 return -EINVAL;
451 }
452
453
454 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
455 if (!newinfo->hook_entry[i] &&
456 (valid_hooks & (1 << i))) {
457 BUGPRINT("Valid hook without chain\n");
458 return -EINVAL;
459 }
460 }
461 return 0;
462}
463
464
465
466
467
468static inline int
469ebt_check_entry_size_and_hooks(struct ebt_entry *e,
470 struct ebt_table_info *newinfo,
471 unsigned int *n, unsigned int *cnt,
472 unsigned int *totalcnt, unsigned int *udc_cnt)
473{
474 int i;
475
476 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
477 if ((void *)e == (void *)newinfo->hook_entry[i])
478 break;
479 }
480
481
482 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
483
484
485 if (*n != *cnt) {
486 BUGPRINT("nentries does not equal the nr of entries "
487 "in the chain\n");
488 return -EINVAL;
489 }
490 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
491 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
492
493 if (i != NF_BR_NUMHOOKS ||
494 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
495 BUGPRINT("bad policy\n");
496 return -EINVAL;
497 }
498 }
499 if (i == NF_BR_NUMHOOKS)
500 (*udc_cnt)++;
501 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
502 BUGPRINT("counter_offset != totalcnt");
503 return -EINVAL;
504 }
505 *n = ((struct ebt_entries *)e)->nentries;
506 *cnt = 0;
507 return 0;
508 }
509
510 if (sizeof(struct ebt_entry) > e->watchers_offset ||
511 e->watchers_offset > e->target_offset ||
512 e->target_offset >= e->next_offset) {
513 BUGPRINT("entry offsets not in right order\n");
514 return -EINVAL;
515 }
516
517 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
518 BUGPRINT("target size too small\n");
519 return -EINVAL;
520 }
521 (*cnt)++;
522 (*totalcnt)++;
523 return 0;
524}
525
526struct ebt_cl_stack
527{
528 struct ebt_chainstack cs;
529 int from;
530 unsigned int hookmask;
531};
532
533
534
535
536
537static inline int
538ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
539 unsigned int *n, struct ebt_cl_stack *udc)
540{
541 int i;
542
543
544 if (e->bitmask)
545 return 0;
546 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
547 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
548 break;
549 }
550
551 if (i != NF_BR_NUMHOOKS)
552 return 0;
553
554 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
555
556 udc[*n].cs.n = 0;
557 udc[*n].hookmask = 0;
558
559 (*n)++;
560 return 0;
561}
562
563static inline int
564ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
565{
566 struct xt_mtdtor_param par;
567
568 if (i && (*i)-- == 0)
569 return 1;
570
571 par.match = m->u.match;
572 par.matchinfo = m->data;
573 par.family = NFPROTO_BRIDGE;
574 if (par.match->destroy != NULL)
575 par.match->destroy(&par);
576 module_put(par.match->me);
577 return 0;
578}
579
580static inline int
581ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
582{
583 struct xt_tgdtor_param par;
584
585 if (i && (*i)-- == 0)
586 return 1;
587
588 par.target = w->u.watcher;
589 par.targinfo = w->data;
590 par.family = NFPROTO_BRIDGE;
591 if (par.target->destroy != NULL)
592 par.target->destroy(&par);
593 module_put(par.target->me);
594 return 0;
595}
596
597static inline int
598ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
599{
600 struct xt_tgdtor_param par;
601 struct ebt_entry_target *t;
602
603 if (e->bitmask == 0)
604 return 0;
605
606 if (cnt && (*cnt)-- == 0)
607 return 1;
608 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
609 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
610 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
611
612 par.target = t->u.target;
613 par.targinfo = t->data;
614 par.family = NFPROTO_BRIDGE;
615 if (par.target->destroy != NULL)
616 par.target->destroy(&par);
617 module_put(par.target->me);
618 return 0;
619}
620
621static inline int
622ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
623 const char *name, unsigned int *cnt,
624 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
625{
626 struct ebt_entry_target *t;
627 struct xt_target *target;
628 unsigned int i, j, hook = 0, hookmask = 0;
629 size_t gap;
630 int ret;
631 struct xt_mtchk_param mtpar;
632 struct xt_tgchk_param tgpar;
633
634
635 if (e->bitmask == 0)
636 return 0;
637
638 if (e->bitmask & ~EBT_F_MASK) {
639 BUGPRINT("Unknown flag for bitmask\n");
640 return -EINVAL;
641 }
642 if (e->invflags & ~EBT_INV_MASK) {
643 BUGPRINT("Unknown flag for inv bitmask\n");
644 return -EINVAL;
645 }
646 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
647 BUGPRINT("NOPROTO & 802_3 not allowed\n");
648 return -EINVAL;
649 }
650
651 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
652 if (!newinfo->hook_entry[i])
653 continue;
654 if ((char *)newinfo->hook_entry[i] < (char *)e)
655 hook = i;
656 else
657 break;
658 }
659
660
661 if (i < NF_BR_NUMHOOKS)
662 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
663 else {
664 for (i = 0; i < udc_cnt; i++)
665 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
666 break;
667 if (i == 0)
668 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
669 else
670 hookmask = cl_s[i - 1].hookmask;
671 }
672 i = 0;
673
674 mtpar.table = tgpar.table = name;
675 mtpar.entryinfo = tgpar.entryinfo = e;
676 mtpar.hook_mask = tgpar.hook_mask = hookmask;
677 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
678 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
679 if (ret != 0)
680 goto cleanup_matches;
681 j = 0;
682 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
683 if (ret != 0)
684 goto cleanup_watchers;
685 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
686 gap = e->next_offset - e->target_offset;
687
688 target = try_then_request_module(
689 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
690 "ebt_%s", t->u.name);
691 if (IS_ERR(target)) {
692 ret = PTR_ERR(target);
693 goto cleanup_watchers;
694 } else if (target == NULL) {
695 ret = -ENOENT;
696 goto cleanup_watchers;
697 }
698
699 t->u.target = target;
700 if (t->u.target == &ebt_standard_target) {
701 if (gap < sizeof(struct ebt_standard_target)) {
702 BUGPRINT("Standard target size too big\n");
703 ret = -EFAULT;
704 goto cleanup_watchers;
705 }
706 if (((struct ebt_standard_target *)t)->verdict <
707 -NUM_STANDARD_TARGETS) {
708 BUGPRINT("Invalid standard target\n");
709 ret = -EFAULT;
710 goto cleanup_watchers;
711 }
712 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
713 module_put(t->u.target->me);
714 ret = -EFAULT;
715 goto cleanup_watchers;
716 }
717
718 tgpar.target = target;
719 tgpar.targinfo = t->data;
720 ret = xt_check_target(&tgpar, t->target_size,
721 e->ethproto, e->invflags & EBT_IPROTO);
722 if (ret < 0) {
723 module_put(target->me);
724 goto cleanup_watchers;
725 }
726 (*cnt)++;
727 return 0;
728cleanup_watchers:
729 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
730cleanup_matches:
731 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
732 return ret;
733}
734
735
736
737
738
739
740static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
741 unsigned int udc_cnt, unsigned int hooknr, char *base)
742{
743 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
744 struct ebt_entry *e = (struct ebt_entry *)chain->data;
745 struct ebt_entry_target *t;
746
747 while (pos < nentries || chain_nr != -1) {
748
749 if (pos == nentries) {
750
751 e = cl_s[chain_nr].cs.e;
752 if (cl_s[chain_nr].from != -1)
753 nentries =
754 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
755 else
756 nentries = chain->nentries;
757 pos = cl_s[chain_nr].cs.n;
758
759 cl_s[chain_nr].cs.n = 0;
760 chain_nr = cl_s[chain_nr].from;
761 if (pos == nentries)
762 continue;
763 }
764 t = (struct ebt_entry_target *)
765 (((char *)e) + e->target_offset);
766 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
767 goto letscontinue;
768 if (e->target_offset + sizeof(struct ebt_standard_target) >
769 e->next_offset) {
770 BUGPRINT("Standard target size too big\n");
771 return -1;
772 }
773 verdict = ((struct ebt_standard_target *)t)->verdict;
774 if (verdict >= 0) {
775 struct ebt_entries *hlp2 =
776 (struct ebt_entries *)(base + verdict);
777 for (i = 0; i < udc_cnt; i++)
778 if (hlp2 == cl_s[i].cs.chaininfo)
779 break;
780
781 if (i == udc_cnt) {
782 BUGPRINT("bad destination\n");
783 return -1;
784 }
785 if (cl_s[i].cs.n) {
786 BUGPRINT("loop\n");
787 return -1;
788 }
789 if (cl_s[i].hookmask & (1 << hooknr))
790 goto letscontinue;
791
792 cl_s[i].cs.n = pos + 1;
793 pos = 0;
794 cl_s[i].cs.e = ebt_next_entry(e);
795 e = (struct ebt_entry *)(hlp2->data);
796 nentries = hlp2->nentries;
797 cl_s[i].from = chain_nr;
798 chain_nr = i;
799
800 cl_s[i].hookmask |= (1 << hooknr);
801 continue;
802 }
803letscontinue:
804 e = ebt_next_entry(e);
805 pos++;
806 }
807 return 0;
808}
809
810
811static int translate_table(char *name, struct ebt_table_info *newinfo)
812{
813 unsigned int i, j, k, udc_cnt;
814 int ret;
815 struct ebt_cl_stack *cl_s = NULL;
816
817 i = 0;
818 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
819 i++;
820 if (i == NF_BR_NUMHOOKS) {
821 BUGPRINT("No valid hooks specified\n");
822 return -EINVAL;
823 }
824 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
825 BUGPRINT("Chains don't start at beginning\n");
826 return -EINVAL;
827 }
828
829
830 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
831 if (!newinfo->hook_entry[j])
832 continue;
833 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
834 BUGPRINT("Hook order must be followed\n");
835 return -EINVAL;
836 }
837 i = j;
838 }
839
840
841 i = 0;
842 j = 0;
843 k = 0;
844
845 udc_cnt = 0;
846 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
847 ebt_check_entry_size_and_hooks, newinfo,
848 &i, &j, &k, &udc_cnt);
849
850 if (ret != 0)
851 return ret;
852
853 if (i != j) {
854 BUGPRINT("nentries does not equal the nr of entries in the "
855 "(last) chain\n");
856 return -EINVAL;
857 }
858 if (k != newinfo->nentries) {
859 BUGPRINT("Total nentries is wrong\n");
860 return -EINVAL;
861 }
862
863
864
865 if (udc_cnt) {
866
867
868 newinfo->chainstack =
869 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
870 if (!newinfo->chainstack)
871 return -ENOMEM;
872 for_each_possible_cpu(i) {
873 newinfo->chainstack[i] =
874 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
875 if (!newinfo->chainstack[i]) {
876 while (i)
877 vfree(newinfo->chainstack[--i]);
878 vfree(newinfo->chainstack);
879 newinfo->chainstack = NULL;
880 return -ENOMEM;
881 }
882 }
883
884 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
885 if (!cl_s)
886 return -ENOMEM;
887 i = 0;
888 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
889 ebt_get_udc_positions, newinfo, &i, cl_s);
890
891 if (i != udc_cnt) {
892 BUGPRINT("i != udc_cnt\n");
893 vfree(cl_s);
894 return -EFAULT;
895 }
896 }
897
898
899 for (i = 0; i < NF_BR_NUMHOOKS; i++)
900 if (newinfo->hook_entry[i])
901 if (check_chainloops(newinfo->hook_entry[i],
902 cl_s, udc_cnt, i, newinfo->entries)) {
903 vfree(cl_s);
904 return -EINVAL;
905 }
906
907
908
909
910
911
912
913
914
915
916
917
918 i = 0;
919 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
920 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
921 if (ret != 0) {
922 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
923 ebt_cleanup_entry, &i);
924 }
925 vfree(cl_s);
926 return ret;
927}
928
929
930static void get_counters(struct ebt_counter *oldcounters,
931 struct ebt_counter *counters, unsigned int nentries)
932{
933 int i, cpu;
934 struct ebt_counter *counter_base;
935
936
937 memcpy(counters, oldcounters,
938 sizeof(struct ebt_counter) * nentries);
939
940
941 for_each_possible_cpu(cpu) {
942 if (cpu == 0)
943 continue;
944 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
945 for (i = 0; i < nentries; i++) {
946 counters[i].pcnt += counter_base[i].pcnt;
947 counters[i].bcnt += counter_base[i].bcnt;
948 }
949 }
950}
951
952
953static int do_replace(struct net *net, void __user *user, unsigned int len)
954{
955 int ret, i, countersize;
956 struct ebt_table_info *newinfo;
957 struct ebt_replace tmp;
958 struct ebt_table *t;
959 struct ebt_counter *counterstmp = NULL;
960
961 struct ebt_table_info *table;
962
963 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
964 return -EFAULT;
965
966 if (len != sizeof(tmp) + tmp.entries_size) {
967 BUGPRINT("Wrong len argument\n");
968 return -EINVAL;
969 }
970
971 if (tmp.entries_size == 0) {
972 BUGPRINT("Entries_size never zero\n");
973 return -EINVAL;
974 }
975
976 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
977 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
978 return -ENOMEM;
979 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
980 return -ENOMEM;
981
982 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
983 newinfo = vmalloc(sizeof(*newinfo) + countersize);
984 if (!newinfo)
985 return -ENOMEM;
986
987 if (countersize)
988 memset(newinfo->counters, 0, countersize);
989
990 newinfo->entries = vmalloc(tmp.entries_size);
991 if (!newinfo->entries) {
992 ret = -ENOMEM;
993 goto free_newinfo;
994 }
995 if (copy_from_user(
996 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
997 BUGPRINT("Couldn't copy entries from userspace\n");
998 ret = -EFAULT;
999 goto free_entries;
1000 }
1001
1002
1003
1004 if (tmp.num_counters) {
1005 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
1006 if (!counterstmp) {
1007 ret = -ENOMEM;
1008 goto free_entries;
1009 }
1010 }
1011 else
1012 counterstmp = NULL;
1013
1014
1015 newinfo->chainstack = NULL;
1016 ret = ebt_verify_pointers(&tmp, newinfo);
1017 if (ret != 0)
1018 goto free_counterstmp;
1019
1020 ret = translate_table(tmp.name, newinfo);
1021
1022 if (ret != 0)
1023 goto free_counterstmp;
1024
1025 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
1026 if (!t) {
1027 ret = -ENOENT;
1028 goto free_iterate;
1029 }
1030
1031
1032 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1033 goto free_unlock;
1034
1035 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1036 BUGPRINT("Wrong nr. of counters requested\n");
1037 ret = -EINVAL;
1038 goto free_unlock;
1039 }
1040
1041
1042 table = t->private;
1043
1044 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1045 ret = -ENOENT;
1046 goto free_unlock;
1047 } else if (table->nentries && !newinfo->nentries)
1048 module_put(t->me);
1049
1050 write_lock_bh(&t->lock);
1051 if (tmp.num_counters)
1052 get_counters(t->private->counters, counterstmp,
1053 t->private->nentries);
1054
1055 t->private = newinfo;
1056 write_unlock_bh(&t->lock);
1057 mutex_unlock(&ebt_mutex);
1058
1059
1060
1061
1062 if (tmp.num_counters &&
1063 copy_to_user(tmp.counters, counterstmp,
1064 tmp.num_counters * sizeof(struct ebt_counter))) {
1065 BUGPRINT("Couldn't copy counters to userspace\n");
1066 ret = -EFAULT;
1067 }
1068 else
1069 ret = 0;
1070
1071
1072 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1073 ebt_cleanup_entry, NULL);
1074
1075 vfree(table->entries);
1076 if (table->chainstack) {
1077 for_each_possible_cpu(i)
1078 vfree(table->chainstack[i]);
1079 vfree(table->chainstack);
1080 }
1081 vfree(table);
1082
1083 vfree(counterstmp);
1084 return ret;
1085
1086free_unlock:
1087 mutex_unlock(&ebt_mutex);
1088free_iterate:
1089 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1090 ebt_cleanup_entry, NULL);
1091free_counterstmp:
1092 vfree(counterstmp);
1093
1094 if (newinfo->chainstack) {
1095 for_each_possible_cpu(i)
1096 vfree(newinfo->chainstack[i]);
1097 vfree(newinfo->chainstack);
1098 }
1099free_entries:
1100 vfree(newinfo->entries);
1101free_newinfo:
1102 vfree(newinfo);
1103 return ret;
1104}
1105
1106struct ebt_table *
1107ebt_register_table(struct net *net, const struct ebt_table *input_table)
1108{
1109 struct ebt_table_info *newinfo;
1110 struct ebt_table *t, *table;
1111 struct ebt_replace_kernel *repl;
1112 int ret, i, countersize;
1113 void *p;
1114
1115 if (input_table == NULL || (repl = input_table->table) == NULL ||
1116 repl->entries == 0 || repl->entries_size == 0 ||
1117 repl->counters != NULL || input_table->private != NULL) {
1118 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1119 return ERR_PTR(-EINVAL);
1120 }
1121
1122
1123 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
1124 if (!table) {
1125 ret = -ENOMEM;
1126 goto out;
1127 }
1128
1129 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
1130 newinfo = vmalloc(sizeof(*newinfo) + countersize);
1131 ret = -ENOMEM;
1132 if (!newinfo)
1133 goto free_table;
1134
1135 p = vmalloc(repl->entries_size);
1136 if (!p)
1137 goto free_newinfo;
1138
1139 memcpy(p, repl->entries, repl->entries_size);
1140 newinfo->entries = p;
1141
1142 newinfo->entries_size = repl->entries_size;
1143 newinfo->nentries = repl->nentries;
1144
1145 if (countersize)
1146 memset(newinfo->counters, 0, countersize);
1147
1148
1149 newinfo->chainstack = NULL;
1150 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1151 if ((repl->valid_hooks & (1 << i)) == 0)
1152 newinfo->hook_entry[i] = NULL;
1153 else
1154 newinfo->hook_entry[i] = p +
1155 ((char *)repl->hook_entry[i] - repl->entries);
1156 }
1157 ret = translate_table(repl->name, newinfo);
1158 if (ret != 0) {
1159 BUGPRINT("Translate_table failed\n");
1160 goto free_chainstack;
1161 }
1162
1163 if (table->check && table->check(newinfo, table->valid_hooks)) {
1164 BUGPRINT("The table doesn't like its own initial data, lol\n");
1165 return ERR_PTR(-EINVAL);
1166 }
1167
1168 table->private = newinfo;
1169 rwlock_init(&table->lock);
1170 ret = mutex_lock_interruptible(&ebt_mutex);
1171 if (ret != 0)
1172 goto free_chainstack;
1173
1174 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
1175 if (strcmp(t->name, table->name) == 0) {
1176 ret = -EEXIST;
1177 BUGPRINT("Table name already exists\n");
1178 goto free_unlock;
1179 }
1180 }
1181
1182
1183 if (newinfo->nentries && !try_module_get(table->me)) {
1184 ret = -ENOENT;
1185 goto free_unlock;
1186 }
1187 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
1188 mutex_unlock(&ebt_mutex);
1189 return table;
1190free_unlock:
1191 mutex_unlock(&ebt_mutex);
1192free_chainstack:
1193 if (newinfo->chainstack) {
1194 for_each_possible_cpu(i)
1195 vfree(newinfo->chainstack[i]);
1196 vfree(newinfo->chainstack);
1197 }
1198 vfree(newinfo->entries);
1199free_newinfo:
1200 vfree(newinfo);
1201free_table:
1202 kfree(table);
1203out:
1204 return ERR_PTR(ret);
1205}
1206
1207void ebt_unregister_table(struct ebt_table *table)
1208{
1209 int i;
1210
1211 if (!table) {
1212 BUGPRINT("Request to unregister NULL table!!!\n");
1213 return;
1214 }
1215 mutex_lock(&ebt_mutex);
1216 list_del(&table->list);
1217 mutex_unlock(&ebt_mutex);
1218 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
1219 ebt_cleanup_entry, NULL);
1220 if (table->private->nentries)
1221 module_put(table->me);
1222 vfree(table->private->entries);
1223 if (table->private->chainstack) {
1224 for_each_possible_cpu(i)
1225 vfree(table->private->chainstack[i]);
1226 vfree(table->private->chainstack);
1227 }
1228 vfree(table->private);
1229 kfree(table);
1230}
1231
1232
1233static int update_counters(struct net *net, void __user *user, unsigned int len)
1234{
1235 int i, ret;
1236 struct ebt_counter *tmp;
1237 struct ebt_replace hlp;
1238 struct ebt_table *t;
1239
1240 if (copy_from_user(&hlp, user, sizeof(hlp)))
1241 return -EFAULT;
1242
1243 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1244 return -EINVAL;
1245 if (hlp.num_counters == 0)
1246 return -EINVAL;
1247
1248 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
1249 MEMPRINT("Update_counters && nomemory\n");
1250 return -ENOMEM;
1251 }
1252
1253 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
1254 if (!t)
1255 goto free_tmp;
1256
1257 if (hlp.num_counters != t->private->nentries) {
1258 BUGPRINT("Wrong nr of counters\n");
1259 ret = -EINVAL;
1260 goto unlock_mutex;
1261 }
1262
1263 if ( copy_from_user(tmp, hlp.counters,
1264 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1265 BUGPRINT("Updata_counters && !cfu\n");
1266 ret = -EFAULT;
1267 goto unlock_mutex;
1268 }
1269
1270
1271 write_lock_bh(&t->lock);
1272
1273
1274 for (i = 0; i < hlp.num_counters; i++) {
1275 t->private->counters[i].pcnt += tmp[i].pcnt;
1276 t->private->counters[i].bcnt += tmp[i].bcnt;
1277 }
1278
1279 write_unlock_bh(&t->lock);
1280 ret = 0;
1281unlock_mutex:
1282 mutex_unlock(&ebt_mutex);
1283free_tmp:
1284 vfree(tmp);
1285 return ret;
1286}
1287
1288static inline int ebt_make_matchname(struct ebt_entry_match *m,
1289 char *base, char __user *ubase)
1290{
1291 char __user *hlp = ubase + ((char *)m - base);
1292 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1293 return -EFAULT;
1294 return 0;
1295}
1296
1297static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
1298 char *base, char __user *ubase)
1299{
1300 char __user *hlp = ubase + ((char *)w - base);
1301 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1302 return -EFAULT;
1303 return 0;
1304}
1305
1306static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
1307{
1308 int ret;
1309 char __user *hlp;
1310 struct ebt_entry_target *t;
1311
1312 if (e->bitmask == 0)
1313 return 0;
1314
1315 hlp = ubase + (((char *)e + e->target_offset) - base);
1316 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
1317
1318 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1319 if (ret != 0)
1320 return ret;
1321 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1322 if (ret != 0)
1323 return ret;
1324 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1325 return -EFAULT;
1326 return 0;
1327}
1328
1329
1330static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1331 int *len, int cmd)
1332{
1333 struct ebt_replace tmp;
1334 struct ebt_counter *counterstmp, *oldcounters;
1335 unsigned int entries_size, nentries;
1336 char *entries;
1337
1338 if (cmd == EBT_SO_GET_ENTRIES) {
1339 entries_size = t->private->entries_size;
1340 nentries = t->private->nentries;
1341 entries = t->private->entries;
1342 oldcounters = t->private->counters;
1343 } else {
1344 entries_size = t->table->entries_size;
1345 nentries = t->table->nentries;
1346 entries = t->table->entries;
1347 oldcounters = t->table->counters;
1348 }
1349
1350 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1351 BUGPRINT("Cfu didn't work\n");
1352 return -EFAULT;
1353 }
1354
1355 if (*len != sizeof(struct ebt_replace) + entries_size +
1356 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1357 BUGPRINT("Wrong size\n");
1358 return -EINVAL;
1359 }
1360
1361 if (tmp.nentries != nentries) {
1362 BUGPRINT("Nentries wrong\n");
1363 return -EINVAL;
1364 }
1365
1366 if (tmp.entries_size != entries_size) {
1367 BUGPRINT("Wrong size\n");
1368 return -EINVAL;
1369 }
1370
1371
1372 if (tmp.num_counters) {
1373 if (tmp.num_counters != nentries) {
1374 BUGPRINT("Num_counters wrong\n");
1375 return -EINVAL;
1376 }
1377 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
1378 if (!counterstmp) {
1379 MEMPRINT("Couldn't copy counters, out of memory\n");
1380 return -ENOMEM;
1381 }
1382 write_lock_bh(&t->lock);
1383 get_counters(oldcounters, counterstmp, nentries);
1384 write_unlock_bh(&t->lock);
1385
1386 if (copy_to_user(tmp.counters, counterstmp,
1387 nentries * sizeof(struct ebt_counter))) {
1388 BUGPRINT("Couldn't copy counters to userspace\n");
1389 vfree(counterstmp);
1390 return -EFAULT;
1391 }
1392 vfree(counterstmp);
1393 }
1394
1395 if (copy_to_user(tmp.entries, entries, entries_size)) {
1396 BUGPRINT("Couldn't copy entries to userspace\n");
1397 return -EFAULT;
1398 }
1399
1400 return EBT_ENTRY_ITERATE(entries, entries_size,
1401 ebt_make_names, entries, tmp.entries);
1402}
1403
1404static int do_ebt_set_ctl(struct sock *sk,
1405 int cmd, void __user *user, unsigned int len)
1406{
1407 int ret;
1408
1409 switch(cmd) {
1410 case EBT_SO_SET_ENTRIES:
1411 ret = do_replace(sock_net(sk), user, len);
1412 break;
1413 case EBT_SO_SET_COUNTERS:
1414 ret = update_counters(sock_net(sk), user, len);
1415 break;
1416 default:
1417 ret = -EINVAL;
1418 }
1419 return ret;
1420}
1421
1422static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1423{
1424 int ret;
1425 struct ebt_replace tmp;
1426 struct ebt_table *t;
1427
1428 if (copy_from_user(&tmp, user, sizeof(tmp)))
1429 return -EFAULT;
1430
1431 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
1432 if (!t)
1433 return ret;
1434
1435 switch(cmd) {
1436 case EBT_SO_GET_INFO:
1437 case EBT_SO_GET_INIT_INFO:
1438 if (*len != sizeof(struct ebt_replace)){
1439 ret = -EINVAL;
1440 mutex_unlock(&ebt_mutex);
1441 break;
1442 }
1443 if (cmd == EBT_SO_GET_INFO) {
1444 tmp.nentries = t->private->nentries;
1445 tmp.entries_size = t->private->entries_size;
1446 tmp.valid_hooks = t->valid_hooks;
1447 } else {
1448 tmp.nentries = t->table->nentries;
1449 tmp.entries_size = t->table->entries_size;
1450 tmp.valid_hooks = t->table->valid_hooks;
1451 }
1452 mutex_unlock(&ebt_mutex);
1453 if (copy_to_user(user, &tmp, *len) != 0){
1454 BUGPRINT("c2u Didn't work\n");
1455 ret = -EFAULT;
1456 break;
1457 }
1458 ret = 0;
1459 break;
1460
1461 case EBT_SO_GET_ENTRIES:
1462 case EBT_SO_GET_INIT_ENTRIES:
1463 ret = copy_everything_to_user(t, user, len, cmd);
1464 mutex_unlock(&ebt_mutex);
1465 break;
1466
1467 default:
1468 mutex_unlock(&ebt_mutex);
1469 ret = -EINVAL;
1470 }
1471
1472 return ret;
1473}
1474
1475static struct nf_sockopt_ops ebt_sockopts =
1476{
1477 .pf = PF_INET,
1478 .set_optmin = EBT_BASE_CTL,
1479 .set_optmax = EBT_SO_SET_MAX + 1,
1480 .set = do_ebt_set_ctl,
1481 .get_optmin = EBT_BASE_CTL,
1482 .get_optmax = EBT_SO_GET_MAX + 1,
1483 .get = do_ebt_get_ctl,
1484 .owner = THIS_MODULE,
1485};
1486
1487static int __init ebtables_init(void)
1488{
1489 int ret;
1490
1491 ret = xt_register_target(&ebt_standard_target);
1492 if (ret < 0)
1493 return ret;
1494 ret = nf_register_sockopt(&ebt_sockopts);
1495 if (ret < 0) {
1496 xt_unregister_target(&ebt_standard_target);
1497 return ret;
1498 }
1499
1500 printk(KERN_INFO "Ebtables v2.0 registered\n");
1501 return 0;
1502}
1503
1504static void __exit ebtables_fini(void)
1505{
1506 nf_unregister_sockopt(&ebt_sockopts);
1507 xt_unregister_target(&ebt_standard_target);
1508 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
1509}
1510
1511EXPORT_SYMBOL(ebt_register_table);
1512EXPORT_SYMBOL(ebt_unregister_table);
1513EXPORT_SYMBOL(ebt_do_table);
1514module_init(ebtables_init);
1515module_exit(ebtables_fini);
1516MODULE_LICENSE("GPL");
1517