blob: 0320b52036248e7f3ef3beee5df41e691f36f4f7 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19#include <linux/kmod.h>
20#include <linux/module.h>
21#include <linux/vmalloc.h>
Jan Engelhardt18219d32008-10-08 11:35:13 +020022#include <linux/netfilter/x_tables.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netfilter_bridge/ebtables.h>
24#include <linux/spinlock.h>
Patrick McHardydf0933d2006-09-20 11:57:53 -070025#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/uaccess.h>
27#include <linux/smp.h>
David S. Millerc8923c62005-10-13 14:41:23 -070028#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/sock.h>
30/* needed for logical [in,out]-dev filtering */
31#include "../br_private.h"
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090034 "report to author: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* #define BUGPRINT(format, args...) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090037 ": out of memory: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/* #define MEMPRINT(format, args...) */
39
40
41
42/*
43 * Each cpu has its own set of counters, so there is no need for write_lock in
44 * the softirq
45 * For reading or updating the counters, the user context needs to
46 * get a write_lock
47 */
48
49/* The size of each set of counters is altered to get cache alignment */
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
Ingo Molnar57b47a52006-03-20 22:35:41 -080057static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static LIST_HEAD(ebt_tables);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Jan Engelhardt043ef462008-10-08 11:35:15 +020060static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020061 .name = "standard",
62 .revision = 0,
63 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020064 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020065};
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +020068 struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 const struct net_device *out)
70{
Jan Engelhardt043ef462008-10-08 11:35:15 +020071 w->u.watcher->target(skb, in, out, hooknr, w->u.watcher, w->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 /* watchers don't give a verdict */
73 return 0;
74}
75
76static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020077 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020079 par->match = m->u.match;
80 par->matchinfo = m->data;
81 return m->u.match->match(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
84static inline int ebt_dev_check(char *entry, const struct net_device *device)
85{
86 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080087 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89 if (*entry == '\0')
90 return 0;
91 if (!device)
92 return 1;
93 /* 1 is the wildcard token */
94 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
95 i++;
96 return (devname[i] != entry[i] && entry[i] != 1);
97}
98
99#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
100/* process standard matches */
101static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
102 const struct net_device *in, const struct net_device *out)
103{
104 int verdict, i;
105
106 if (e->bitmask & EBT_802_3) {
107 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
108 return 1;
109 } else if (!(e->bitmask & EBT_NOPROTO) &&
110 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
111 return 1;
112
113 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
114 return 1;
115 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
116 return 1;
117 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
118 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
119 return 1;
120 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
121 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
122 return 1;
123
124 if (e->bitmask & EBT_SOURCEMAC) {
125 verdict = 0;
126 for (i = 0; i < 6; i++)
127 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
128 e->sourcemsk[i];
129 if (FWINV2(verdict != 0, EBT_ISOURCE) )
130 return 1;
131 }
132 if (e->bitmask & EBT_DESTMAC) {
133 verdict = 0;
134 for (i = 0; i < 6; i++)
135 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
136 e->destmsk[i];
137 if (FWINV2(verdict != 0, EBT_IDEST) )
138 return 1;
139 }
140 return 0;
141}
142
143/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700144unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 const struct net_device *in, const struct net_device *out,
146 struct ebt_table *table)
147{
148 int i, nentries;
149 struct ebt_entry *point;
150 struct ebt_counter *counter_base, *cb_base;
151 struct ebt_entry_target *t;
152 int verdict, sp = 0;
153 struct ebt_chainstack *cs;
154 struct ebt_entries *chaininfo;
155 char *base;
156 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200157 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200158 struct xt_match_param mtpar;
159
160 mtpar.in = in;
161 mtpar.out = out;
162 mtpar.hotdrop = &hotdrop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 read_lock_bh(&table->lock);
165 private = table->private;
166 cb_base = COUNTER_BASE(private->counters, private->nentries,
167 smp_processor_id());
168 if (private->chainstack)
169 cs = private->chainstack[smp_processor_id()];
170 else
171 cs = NULL;
172 chaininfo = private->hook_entry[hook];
173 nentries = private->hook_entry[hook]->nentries;
174 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
175 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
176 /* base for chain jumps */
177 base = private->entries;
178 i = 0;
179 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700180 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 goto letscontinue;
182
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200183 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200185 if (hotdrop) {
186 read_unlock_bh(&table->lock);
187 return NF_DROP;
188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 /* increase counter */
191 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700192 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 /* these should only watch: not modify, nor tell us
195 what to do with the packet */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700196 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 out);
198
199 t = (struct ebt_entry_target *)
200 (((char *)point) + point->target_offset);
201 /* standard target */
202 if (!t->u.target->target)
203 verdict = ((struct ebt_standard_target *)t)->verdict;
204 else
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200205 verdict = t->u.target->target(skb, in, out, hook,
Jan Engelhardt043ef462008-10-08 11:35:15 +0200206 t->u.target, t->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (verdict == EBT_ACCEPT) {
208 read_unlock_bh(&table->lock);
209 return NF_ACCEPT;
210 }
211 if (verdict == EBT_DROP) {
212 read_unlock_bh(&table->lock);
213 return NF_DROP;
214 }
215 if (verdict == EBT_RETURN) {
216letsreturn:
217#ifdef CONFIG_NETFILTER_DEBUG
218 if (sp == 0) {
219 BUGPRINT("RETURN on base chain");
220 /* act like this is EBT_CONTINUE */
221 goto letscontinue;
222 }
223#endif
224 sp--;
225 /* put all the local variables right */
226 i = cs[sp].n;
227 chaininfo = cs[sp].chaininfo;
228 nentries = chaininfo->nentries;
229 point = cs[sp].e;
230 counter_base = cb_base +
231 chaininfo->counter_offset;
232 continue;
233 }
234 if (verdict == EBT_CONTINUE)
235 goto letscontinue;
236#ifdef CONFIG_NETFILTER_DEBUG
237 if (verdict < 0) {
238 BUGPRINT("bogus standard verdict\n");
239 read_unlock_bh(&table->lock);
240 return NF_DROP;
241 }
242#endif
243 /* jump to a udc */
244 cs[sp].n = i + 1;
245 cs[sp].chaininfo = chaininfo;
246 cs[sp].e = (struct ebt_entry *)
247 (((char *)point) + point->next_offset);
248 i = 0;
249 chaininfo = (struct ebt_entries *) (base + verdict);
250#ifdef CONFIG_NETFILTER_DEBUG
251 if (chaininfo->distinguisher) {
252 BUGPRINT("jump to non-chain\n");
253 read_unlock_bh(&table->lock);
254 return NF_DROP;
255 }
256#endif
257 nentries = chaininfo->nentries;
258 point = (struct ebt_entry *)chaininfo->data;
259 counter_base = cb_base + chaininfo->counter_offset;
260 sp++;
261 continue;
262letscontinue:
263 point = (struct ebt_entry *)
264 (((char *)point) + point->next_offset);
265 i++;
266 }
267
268 /* I actually like this :) */
269 if (chaininfo->policy == EBT_RETURN)
270 goto letsreturn;
271 if (chaininfo->policy == EBT_ACCEPT) {
272 read_unlock_bh(&table->lock);
273 return NF_ACCEPT;
274 }
275 read_unlock_bh(&table->lock);
276 return NF_DROP;
277}
278
279/* If it succeeds, returns element and locks mutex */
280static inline void *
281find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800282 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700284 struct {
285 struct list_head list;
286 char name[EBT_FUNCTION_MAXNAMELEN];
287 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Ingo Molnar57b47a52006-03-20 22:35:41 -0800289 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 if (*error != 0)
291 return NULL;
292
Patrick McHardydf0933d2006-09-20 11:57:53 -0700293 list_for_each_entry(e, head, list) {
294 if (strcmp(e->name, name) == 0)
295 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700297 *error = -ENOENT;
298 mutex_unlock(mutex);
299 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
302#ifndef CONFIG_KMOD
303#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
304#else
305static void *
306find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800307 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
309 void *ret;
310
311 ret = find_inlist_lock_noload(head, name, error, mutex);
312 if (!ret) {
313 request_module("%s%s", prefix, name);
314 ret = find_inlist_lock_noload(head, name, error, mutex);
315 }
316 return ret;
317}
318#endif
319
320static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800321find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
324}
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200327ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
328 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200330 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200331 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800332 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 int ret;
334
Al Viro14197d52006-11-30 19:25:21 -0800335 if (left < sizeof(struct ebt_entry_match) ||
336 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200338
339 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
340 m->u.name, 0), "ebt_%s", m->u.name);
341 if (IS_ERR(match))
342 return PTR_ERR(match);
343 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200345 m->u.match = match;
346
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200347 par->match = match;
348 par->matchinfo = m->data;
349 ret = xt_check_match(par, NFPROTO_BRIDGE, m->match_size,
350 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200351 if (ret < 0) {
352 module_put(match->me);
353 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 (*cnt)++;
357 return 0;
358}
359
360static inline int
361ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
362 const char *name, unsigned int hookmask, unsigned int *cnt)
363{
Jan Engelhardt043ef462008-10-08 11:35:15 +0200364 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800365 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 int ret;
367
Al Viro14197d52006-11-30 19:25:21 -0800368 if (left < sizeof(struct ebt_entry_watcher) ||
369 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200371
372 watcher = try_then_request_module(
373 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
374 "ebt_%s", w->u.name);
375 if (IS_ERR(watcher))
376 return PTR_ERR(watcher);
377 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200379 w->u.watcher = watcher;
380
381 ret = xt_check_target(watcher, NFPROTO_BRIDGE, w->watcher_size,
Jan Engelhardt367c6792008-10-08 11:35:17 +0200382 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO,
383 e, w->data);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200384 if (ret < 0) {
385 module_put(watcher->me);
386 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 (*cnt)++;
390 return 0;
391}
392
Al Viro70fe9af2006-11-30 19:26:14 -0800393static int ebt_verify_pointers(struct ebt_replace *repl,
394 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
Al Viro70fe9af2006-11-30 19:26:14 -0800396 unsigned int limit = repl->entries_size;
397 unsigned int valid_hooks = repl->valid_hooks;
398 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 int i;
400
Al Viroe4fd77d2006-11-30 19:26:35 -0800401 for (i = 0; i < NF_BR_NUMHOOKS; i++)
402 newinfo->hook_entry[i] = NULL;
403
404 newinfo->entries_size = repl->entries_size;
405 newinfo->nentries = repl->nentries;
406
Al Viro70fe9af2006-11-30 19:26:14 -0800407 while (offset < limit) {
408 size_t left = limit - offset;
409 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800410
Al Viro70fe9af2006-11-30 19:26:14 -0800411 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 break;
Al Viro22b440b2006-11-30 19:25:51 -0800413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
415 if ((valid_hooks & (1 << i)) == 0)
416 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800417 if ((char __user *)repl->hook_entry[i] ==
418 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800419 break;
420 }
421
422 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
423 if (e->bitmask != 0) {
424 /* we make userspace set this right,
425 so there is no misunderstanding */
426 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
427 "in distinguisher\n");
428 return -EINVAL;
429 }
430 if (i != NF_BR_NUMHOOKS)
431 newinfo->hook_entry[i] = (struct ebt_entries *)e;
432 if (left < sizeof(struct ebt_entries))
433 break;
434 offset += sizeof(struct ebt_entries);
435 } else {
436 if (left < sizeof(struct ebt_entry))
437 break;
438 if (left < e->next_offset)
439 break;
440 offset += e->next_offset;
441 }
442 }
443 if (offset != limit) {
444 BUGPRINT("entries_size too small\n");
445 return -EINVAL;
446 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800447
448 /* check if all valid hooks have a chain */
449 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
450 if (!newinfo->hook_entry[i] &&
451 (valid_hooks & (1 << i))) {
452 BUGPRINT("Valid hook without chain\n");
453 return -EINVAL;
454 }
455 }
Al Viro70fe9af2006-11-30 19:26:14 -0800456 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800457}
458
459/*
460 * this one is very careful, as it is the first function
461 * to parse the userspace data
462 */
463static inline int
464ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800465 struct ebt_table_info *newinfo,
466 unsigned int *n, unsigned int *cnt,
467 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800468{
Al Viro22b440b2006-11-30 19:25:51 -0800469 int i;
470
471 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800472 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800473 break;
474 }
475 /* beginning of a new chain
476 if i == NF_BR_NUMHOOKS it must be a user defined chain */
477 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* this checks if the previous chain has as many entries
479 as it said it has */
480 if (*n != *cnt) {
481 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900482 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return -EINVAL;
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
486 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
487 /* only RETURN from udc */
488 if (i != NF_BR_NUMHOOKS ||
489 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
490 BUGPRINT("bad policy\n");
491 return -EINVAL;
492 }
493 }
494 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
495 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
497 BUGPRINT("counter_offset != totalcnt");
498 return -EINVAL;
499 }
500 *n = ((struct ebt_entries *)e)->nentries;
501 *cnt = 0;
502 return 0;
503 }
504 /* a plain old entry, heh */
505 if (sizeof(struct ebt_entry) > e->watchers_offset ||
506 e->watchers_offset > e->target_offset ||
507 e->target_offset >= e->next_offset) {
508 BUGPRINT("entry offsets not in right order\n");
509 return -EINVAL;
510 }
511 /* this is not checked anywhere else */
512 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
513 BUGPRINT("target size too small\n");
514 return -EINVAL;
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 (*cnt)++;
517 (*totalcnt)++;
518 return 0;
519}
520
521struct ebt_cl_stack
522{
523 struct ebt_chainstack cs;
524 int from;
525 unsigned int hookmask;
526};
527
528/*
529 * we need these positions to check that the jumps to a different part of the
530 * entries is a jump to the beginning of a new chain.
531 */
532static inline int
533ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800534 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
536 int i;
537
538 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800539 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return 0;
541 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
543 break;
544 }
545 /* only care about udc */
546 if (i != NF_BR_NUMHOOKS)
547 return 0;
548
549 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
550 /* these initialisations are depended on later in check_chainloops() */
551 udc[*n].cs.n = 0;
552 udc[*n].hookmask = 0;
553
554 (*n)++;
555 return 0;
556}
557
558static inline int
559ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
560{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200561 struct xt_mtdtor_param par;
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (i && (*i)-- == 0)
564 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200566 par.match = m->u.match;
567 par.matchinfo = m->data;
568 if (par.match->destroy != NULL)
569 par.match->destroy(&par);
570 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return 0;
572}
573
574static inline int
575ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
576{
577 if (i && (*i)-- == 0)
578 return 1;
579 if (w->u.watcher->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200580 w->u.watcher->destroy(w->u.watcher, w->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 module_put(w->u.watcher->me);
582
583 return 0;
584}
585
586static inline int
587ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
588{
589 struct ebt_entry_target *t;
590
Al Viro40642f92006-11-30 19:24:12 -0800591 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 return 0;
593 /* we're done */
594 if (cnt && (*cnt)-- == 0)
595 return 1;
596 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
597 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
598 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
599 if (t->u.target->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200600 t->u.target->destroy(t->u.target, t->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 module_put(t->u.target->me);
602
603 return 0;
604}
605
606static inline int
607ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800608 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
610{
611 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200612 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800614 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200616 struct xt_mtchk_param mtpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800619 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return 0;
621
622 if (e->bitmask & ~EBT_F_MASK) {
623 BUGPRINT("Unknown flag for bitmask\n");
624 return -EINVAL;
625 }
626 if (e->invflags & ~EBT_INV_MASK) {
627 BUGPRINT("Unknown flag for inv bitmask\n");
628 return -EINVAL;
629 }
630 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
631 BUGPRINT("NOPROTO & 802_3 not allowed\n");
632 return -EINVAL;
633 }
634 /* what hook do we belong to? */
635 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800636 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 continue;
638 if ((char *)newinfo->hook_entry[i] < (char *)e)
639 hook = i;
640 else
641 break;
642 }
643 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
644 a base chain */
645 if (i < NF_BR_NUMHOOKS)
646 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
647 else {
648 for (i = 0; i < udc_cnt; i++)
649 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
650 break;
651 if (i == 0)
652 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
653 else
654 hookmask = cl_s[i - 1].hookmask;
655 }
656 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200657
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200658 mtpar.table = name;
659 mtpar.entryinfo = e;
660 mtpar.hook_mask = hookmask;
661 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if (ret != 0)
663 goto cleanup_matches;
664 j = 0;
665 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
666 if (ret != 0)
667 goto cleanup_watchers;
668 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800669 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Jan Engelhardt043ef462008-10-08 11:35:15 +0200671 target = try_then_request_module(
672 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
673 "ebt_%s", t->u.name);
674 if (IS_ERR(target)) {
675 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200676 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200677 } else if (target == NULL) {
678 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200679 goto cleanup_watchers;
680 }
681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 t->u.target = target;
683 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800684 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 BUGPRINT("Standard target size too big\n");
686 ret = -EFAULT;
687 goto cleanup_watchers;
688 }
689 if (((struct ebt_standard_target *)t)->verdict <
690 -NUM_STANDARD_TARGETS) {
691 BUGPRINT("Invalid standard target\n");
692 ret = -EFAULT;
693 goto cleanup_watchers;
694 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200695 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
696 module_put(t->u.target->me);
697 ret = -EFAULT;
698 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200699 }
700
701 ret = xt_check_target(target, NFPROTO_BRIDGE, t->target_size,
Jan Engelhardt367c6792008-10-08 11:35:17 +0200702 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO,
703 e, t->data);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200704 if (ret < 0) {
705 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200706 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 }
708 (*cnt)++;
709 return 0;
710cleanup_watchers:
711 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
712cleanup_matches:
713 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
714 return ret;
715}
716
717/*
718 * checks for loops and sets the hook mask for udc
719 * the hook mask for udc tells us from which base chains the udc can be
720 * accessed. This mask is a parameter to the check() functions of the extensions
721 */
722static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
723 unsigned int udc_cnt, unsigned int hooknr, char *base)
724{
725 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
726 struct ebt_entry *e = (struct ebt_entry *)chain->data;
727 struct ebt_entry_target *t;
728
729 while (pos < nentries || chain_nr != -1) {
730 /* end of udc, go back one 'recursion' step */
731 if (pos == nentries) {
732 /* put back values of the time when this chain was called */
733 e = cl_s[chain_nr].cs.e;
734 if (cl_s[chain_nr].from != -1)
735 nentries =
736 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
737 else
738 nentries = chain->nentries;
739 pos = cl_s[chain_nr].cs.n;
740 /* make sure we won't see a loop that isn't one */
741 cl_s[chain_nr].cs.n = 0;
742 chain_nr = cl_s[chain_nr].from;
743 if (pos == nentries)
744 continue;
745 }
746 t = (struct ebt_entry_target *)
747 (((char *)e) + e->target_offset);
748 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
749 goto letscontinue;
750 if (e->target_offset + sizeof(struct ebt_standard_target) >
751 e->next_offset) {
752 BUGPRINT("Standard target size too big\n");
753 return -1;
754 }
755 verdict = ((struct ebt_standard_target *)t)->verdict;
756 if (verdict >= 0) { /* jump to another chain */
757 struct ebt_entries *hlp2 =
758 (struct ebt_entries *)(base + verdict);
759 for (i = 0; i < udc_cnt; i++)
760 if (hlp2 == cl_s[i].cs.chaininfo)
761 break;
762 /* bad destination or loop */
763 if (i == udc_cnt) {
764 BUGPRINT("bad destination\n");
765 return -1;
766 }
767 if (cl_s[i].cs.n) {
768 BUGPRINT("loop\n");
769 return -1;
770 }
Al Viro98a08242006-11-30 19:24:49 -0800771 if (cl_s[i].hookmask & (1 << hooknr))
772 goto letscontinue;
773 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 cl_s[i].cs.n = pos + 1;
775 pos = 0;
776 cl_s[i].cs.e = ((void *)e + e->next_offset);
777 e = (struct ebt_entry *)(hlp2->data);
778 nentries = hlp2->nentries;
779 cl_s[i].from = chain_nr;
780 chain_nr = i;
781 /* this udc is accessible from the base chain for hooknr */
782 cl_s[i].hookmask |= (1 << hooknr);
783 continue;
784 }
785letscontinue:
786 e = (void *)e + e->next_offset;
787 pos++;
788 }
789 return 0;
790}
791
792/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800793static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
795 unsigned int i, j, k, udc_cnt;
796 int ret;
797 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
798
799 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800800 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 i++;
802 if (i == NF_BR_NUMHOOKS) {
803 BUGPRINT("No valid hooks specified\n");
804 return -EINVAL;
805 }
Al Viro1f072c92006-11-30 19:26:53 -0800806 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 BUGPRINT("Chains don't start at beginning\n");
808 return -EINVAL;
809 }
810 /* make sure chains are ordered after each other in same order
811 as their corresponding hooks */
812 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800813 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800815 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 BUGPRINT("Hook order must be followed\n");
817 return -EINVAL;
818 }
819 i = j;
820 }
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* do some early checkings and initialize some things */
823 i = 0; /* holds the expected nr. of entries for the chain */
824 j = 0; /* holds the up to now counted entries for the chain */
825 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900826 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
828 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800829 ebt_check_entry_size_and_hooks, newinfo,
830 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 if (ret != 0)
833 return ret;
834
835 if (i != j) {
836 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900837 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 return -EINVAL;
839 }
840 if (k != newinfo->nentries) {
841 BUGPRINT("Total nentries is wrong\n");
842 return -EINVAL;
843 }
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 /* get the location of the udc, put them in an array
846 while we're at it, allocate the chainstack */
847 if (udc_cnt) {
848 /* this will get free'd in do_replace()/ebt_register_table()
849 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700850 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800851 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (!newinfo->chainstack)
853 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700854 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700856 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (!newinfo->chainstack[i]) {
858 while (i)
859 vfree(newinfo->chainstack[--i]);
860 vfree(newinfo->chainstack);
861 newinfo->chainstack = NULL;
862 return -ENOMEM;
863 }
864 }
865
Jayachandran C18bc89a2006-04-20 00:14:49 -0700866 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 if (!cl_s)
868 return -ENOMEM;
869 i = 0; /* the i'th udc */
870 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800871 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 /* sanity check */
873 if (i != udc_cnt) {
874 BUGPRINT("i != udc_cnt\n");
875 vfree(cl_s);
876 return -EFAULT;
877 }
878 }
879
880 /* Check for loops */
881 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800882 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (check_chainloops(newinfo->hook_entry[i],
884 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700885 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return -EINVAL;
887 }
888
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200889 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 - the nr of entries in each chain is right
891 - the size of the allocated space is right
892 - all valid hooks have a corresponding chain
893 - there are no loops
894 - wrong data can still be on the level of a single entry
895 - could be there are jumps to places that are not the
896 beginning of a chain. This can only occur in chains that
897 are not accessible from any base chains, so we don't care. */
898
899 /* used to know what we need to clean up if something goes wrong */
900 i = 0;
901 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800902 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 if (ret != 0) {
904 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
905 ebt_cleanup_entry, &i);
906 }
James Lamanna68d31872005-06-22 22:12:57 -0700907 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 return ret;
909}
910
911/* called under write_lock */
912static void get_counters(struct ebt_counter *oldcounters,
913 struct ebt_counter *counters, unsigned int nentries)
914{
915 int i, cpu;
916 struct ebt_counter *counter_base;
917
918 /* counters of cpu 0 */
919 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700920 sizeof(struct ebt_counter) * nentries);
921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700923 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700924 if (cpu == 0)
925 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
927 for (i = 0; i < nentries; i++) {
928 counters[i].pcnt += counter_base[i].pcnt;
929 counters[i].bcnt += counter_base[i].bcnt;
930 }
931 }
932}
933
934/* replace the table */
935static int do_replace(void __user *user, unsigned int len)
936{
937 int ret, i, countersize;
938 struct ebt_table_info *newinfo;
939 struct ebt_replace tmp;
940 struct ebt_table *t;
941 struct ebt_counter *counterstmp = NULL;
942 /* used to be able to unlock earlier */
943 struct ebt_table_info *table;
944
945 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
946 return -EFAULT;
947
948 if (len != sizeof(tmp) + tmp.entries_size) {
949 BUGPRINT("Wrong len argument\n");
950 return -EINVAL;
951 }
952
953 if (tmp.entries_size == 0) {
954 BUGPRINT("Entries_size never zero\n");
955 return -EINVAL;
956 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800957 /* overflow check */
958 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
959 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
960 return -ENOMEM;
961 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
962 return -ENOMEM;
963
Christoph Lameter53b8a312007-02-20 13:57:51 -0800964 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700965 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 if (!newinfo)
967 return -ENOMEM;
968
969 if (countersize)
970 memset(newinfo->counters, 0, countersize);
971
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800972 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 if (!newinfo->entries) {
974 ret = -ENOMEM;
975 goto free_newinfo;
976 }
977 if (copy_from_user(
978 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
979 BUGPRINT("Couldn't copy entries from userspace\n");
980 ret = -EFAULT;
981 goto free_entries;
982 }
983
984 /* the user wants counters back
985 the check on the size is done later, when we have the lock */
986 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700987 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (!counterstmp) {
989 ret = -ENOMEM;
990 goto free_entries;
991 }
992 }
993 else
994 counterstmp = NULL;
995
996 /* this can get initialized by translate_table() */
997 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -0800998 ret = ebt_verify_pointers(&tmp, newinfo);
999 if (ret != 0)
1000 goto free_counterstmp;
1001
1002 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 if (ret != 0)
1005 goto free_counterstmp;
1006
1007 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1008 if (!t) {
1009 ret = -ENOENT;
1010 goto free_iterate;
1011 }
1012
1013 /* the table doesn't like it */
1014 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1015 goto free_unlock;
1016
1017 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1018 BUGPRINT("Wrong nr. of counters requested\n");
1019 ret = -EINVAL;
1020 goto free_unlock;
1021 }
1022
1023 /* we have the mutex lock, so no danger in reading this pointer */
1024 table = t->private;
1025 /* make sure the table can only be rmmod'ed if it contains no rules */
1026 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1027 ret = -ENOENT;
1028 goto free_unlock;
1029 } else if (table->nentries && !newinfo->nentries)
1030 module_put(t->me);
1031 /* we need an atomic snapshot of the counters */
1032 write_lock_bh(&t->lock);
1033 if (tmp.num_counters)
1034 get_counters(t->private->counters, counterstmp,
1035 t->private->nentries);
1036
1037 t->private = newinfo;
1038 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001039 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 /* so, a user can change the chains while having messed up her counter
1041 allocation. Only reason why this is done is because this way the lock
1042 is held only once, while this doesn't bring the kernel into a
1043 dangerous state. */
1044 if (tmp.num_counters &&
1045 copy_to_user(tmp.counters, counterstmp,
1046 tmp.num_counters * sizeof(struct ebt_counter))) {
1047 BUGPRINT("Couldn't copy counters to userspace\n");
1048 ret = -EFAULT;
1049 }
1050 else
1051 ret = 0;
1052
1053 /* decrease module count and free resources */
1054 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1055 ebt_cleanup_entry, NULL);
1056
1057 vfree(table->entries);
1058 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001059 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 vfree(table->chainstack[i]);
1061 vfree(table->chainstack);
1062 }
1063 vfree(table);
1064
James Lamanna68d31872005-06-22 22:12:57 -07001065 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return ret;
1067
1068free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001069 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070free_iterate:
1071 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1072 ebt_cleanup_entry, NULL);
1073free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001074 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 /* can be initialized in translate_table() */
1076 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001077 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 vfree(newinfo->chainstack[i]);
1079 vfree(newinfo->chainstack);
1080 }
1081free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001082 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001084 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 return ret;
1086}
1087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088int ebt_register_table(struct ebt_table *table)
1089{
1090 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001091 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001092 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001094 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Al Virodf07a812006-11-30 19:28:25 -08001096 if (!table || !(repl = table->table) || !repl->entries ||
1097 repl->entries_size == 0 ||
1098 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1100 return -EINVAL;
1101 }
1102
Christoph Lameter53b8a312007-02-20 13:57:51 -08001103 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001104 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 ret = -ENOMEM;
1106 if (!newinfo)
1107 return -ENOMEM;
1108
Al Virodf07a812006-11-30 19:28:25 -08001109 p = vmalloc(repl->entries_size);
1110 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 goto free_newinfo;
1112
Al Virodf07a812006-11-30 19:28:25 -08001113 memcpy(p, repl->entries, repl->entries_size);
1114 newinfo->entries = p;
1115
1116 newinfo->entries_size = repl->entries_size;
1117 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 if (countersize)
1120 memset(newinfo->counters, 0, countersize);
1121
1122 /* fill in newinfo and parse the entries */
1123 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001124 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1125 if ((repl->valid_hooks & (1 << i)) == 0)
1126 newinfo->hook_entry[i] = NULL;
1127 else
1128 newinfo->hook_entry[i] = p +
1129 ((char *)repl->hook_entry[i] - repl->entries);
1130 }
1131 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 if (ret != 0) {
1133 BUGPRINT("Translate_table failed\n");
1134 goto free_chainstack;
1135 }
1136
1137 if (table->check && table->check(newinfo, table->valid_hooks)) {
1138 BUGPRINT("The table doesn't like its own initial data, lol\n");
1139 return -EINVAL;
1140 }
1141
1142 table->private = newinfo;
1143 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001144 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 if (ret != 0)
1146 goto free_chainstack;
1147
Patrick McHardydf0933d2006-09-20 11:57:53 -07001148 list_for_each_entry(t, &ebt_tables, list) {
1149 if (strcmp(t->name, table->name) == 0) {
1150 ret = -EEXIST;
1151 BUGPRINT("Table name already exists\n");
1152 goto free_unlock;
1153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155
1156 /* Hold a reference count if the chains aren't empty */
1157 if (newinfo->nentries && !try_module_get(table->me)) {
1158 ret = -ENOENT;
1159 goto free_unlock;
1160 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001161 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001162 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 return 0;
1164free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001165 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166free_chainstack:
1167 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001168 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 vfree(newinfo->chainstack[i]);
1170 vfree(newinfo->chainstack);
1171 }
1172 vfree(newinfo->entries);
1173free_newinfo:
1174 vfree(newinfo);
1175 return ret;
1176}
1177
1178void ebt_unregister_table(struct ebt_table *table)
1179{
1180 int i;
1181
1182 if (!table) {
1183 BUGPRINT("Request to unregister NULL table!!!\n");
1184 return;
1185 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001186 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001187 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001188 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001189 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001191 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 vfree(table->private->chainstack[i]);
1193 vfree(table->private->chainstack);
1194 }
1195 vfree(table->private);
1196}
1197
1198/* userspace just supplied us with counters */
1199static int update_counters(void __user *user, unsigned int len)
1200{
1201 int i, ret;
1202 struct ebt_counter *tmp;
1203 struct ebt_replace hlp;
1204 struct ebt_table *t;
1205
1206 if (copy_from_user(&hlp, user, sizeof(hlp)))
1207 return -EFAULT;
1208
1209 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1210 return -EINVAL;
1211 if (hlp.num_counters == 0)
1212 return -EINVAL;
1213
Jayachandran C18bc89a2006-04-20 00:14:49 -07001214 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 MEMPRINT("Update_counters && nomemory\n");
1216 return -ENOMEM;
1217 }
1218
1219 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1220 if (!t)
1221 goto free_tmp;
1222
1223 if (hlp.num_counters != t->private->nentries) {
1224 BUGPRINT("Wrong nr of counters\n");
1225 ret = -EINVAL;
1226 goto unlock_mutex;
1227 }
1228
1229 if ( copy_from_user(tmp, hlp.counters,
1230 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1231 BUGPRINT("Updata_counters && !cfu\n");
1232 ret = -EFAULT;
1233 goto unlock_mutex;
1234 }
1235
1236 /* we want an atomic add of the counters */
1237 write_lock_bh(&t->lock);
1238
1239 /* we add to the counters of the first cpu */
1240 for (i = 0; i < hlp.num_counters; i++) {
1241 t->private->counters[i].pcnt += tmp[i].pcnt;
1242 t->private->counters[i].bcnt += tmp[i].bcnt;
1243 }
1244
1245 write_unlock_bh(&t->lock);
1246 ret = 0;
1247unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001248 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249free_tmp:
1250 vfree(tmp);
1251 return ret;
1252}
1253
1254static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001255 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256{
Al Viro1e419cd2006-11-30 19:28:48 -08001257 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1259 return -EFAULT;
1260 return 0;
1261}
1262
1263static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001264 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265{
Al Viro1e419cd2006-11-30 19:28:48 -08001266 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1268 return -EFAULT;
1269 return 0;
1270}
1271
Al Viro1e419cd2006-11-30 19:28:48 -08001272static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
1274 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001275 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 struct ebt_entry_target *t;
1277
Al Viro40642f92006-11-30 19:24:12 -08001278 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 return 0;
1280
Al Viro1e419cd2006-11-30 19:28:48 -08001281 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1285 if (ret != 0)
1286 return ret;
1287 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1288 if (ret != 0)
1289 return ret;
1290 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1291 return -EFAULT;
1292 return 0;
1293}
1294
Ingo Molnar57b47a52006-03-20 22:35:41 -08001295/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1297 int *len, int cmd)
1298{
1299 struct ebt_replace tmp;
1300 struct ebt_counter *counterstmp, *oldcounters;
1301 unsigned int entries_size, nentries;
1302 char *entries;
1303
1304 if (cmd == EBT_SO_GET_ENTRIES) {
1305 entries_size = t->private->entries_size;
1306 nentries = t->private->nentries;
1307 entries = t->private->entries;
1308 oldcounters = t->private->counters;
1309 } else {
1310 entries_size = t->table->entries_size;
1311 nentries = t->table->nentries;
1312 entries = t->table->entries;
1313 oldcounters = t->table->counters;
1314 }
1315
1316 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1317 BUGPRINT("Cfu didn't work\n");
1318 return -EFAULT;
1319 }
1320
1321 if (*len != sizeof(struct ebt_replace) + entries_size +
1322 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1323 BUGPRINT("Wrong size\n");
1324 return -EINVAL;
1325 }
1326
1327 if (tmp.nentries != nentries) {
1328 BUGPRINT("Nentries wrong\n");
1329 return -EINVAL;
1330 }
1331
1332 if (tmp.entries_size != entries_size) {
1333 BUGPRINT("Wrong size\n");
1334 return -EINVAL;
1335 }
1336
1337 /* userspace might not need the counters */
1338 if (tmp.num_counters) {
1339 if (tmp.num_counters != nentries) {
1340 BUGPRINT("Num_counters wrong\n");
1341 return -EINVAL;
1342 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001343 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 if (!counterstmp) {
1345 MEMPRINT("Couldn't copy counters, out of memory\n");
1346 return -ENOMEM;
1347 }
1348 write_lock_bh(&t->lock);
1349 get_counters(oldcounters, counterstmp, nentries);
1350 write_unlock_bh(&t->lock);
1351
1352 if (copy_to_user(tmp.counters, counterstmp,
1353 nentries * sizeof(struct ebt_counter))) {
1354 BUGPRINT("Couldn't copy counters to userspace\n");
1355 vfree(counterstmp);
1356 return -EFAULT;
1357 }
1358 vfree(counterstmp);
1359 }
1360
1361 if (copy_to_user(tmp.entries, entries, entries_size)) {
1362 BUGPRINT("Couldn't copy entries to userspace\n");
1363 return -EFAULT;
1364 }
1365 /* set the match/watcher/target names right */
1366 return EBT_ENTRY_ITERATE(entries, entries_size,
1367 ebt_make_names, entries, tmp.entries);
1368}
1369
1370static int do_ebt_set_ctl(struct sock *sk,
1371 int cmd, void __user *user, unsigned int len)
1372{
1373 int ret;
1374
1375 switch(cmd) {
1376 case EBT_SO_SET_ENTRIES:
1377 ret = do_replace(user, len);
1378 break;
1379 case EBT_SO_SET_COUNTERS:
1380 ret = update_counters(user, len);
1381 break;
1382 default:
1383 ret = -EINVAL;
1384 }
1385 return ret;
1386}
1387
1388static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1389{
1390 int ret;
1391 struct ebt_replace tmp;
1392 struct ebt_table *t;
1393
1394 if (copy_from_user(&tmp, user, sizeof(tmp)))
1395 return -EFAULT;
1396
1397 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1398 if (!t)
1399 return ret;
1400
1401 switch(cmd) {
1402 case EBT_SO_GET_INFO:
1403 case EBT_SO_GET_INIT_INFO:
1404 if (*len != sizeof(struct ebt_replace)){
1405 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001406 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 break;
1408 }
1409 if (cmd == EBT_SO_GET_INFO) {
1410 tmp.nentries = t->private->nentries;
1411 tmp.entries_size = t->private->entries_size;
1412 tmp.valid_hooks = t->valid_hooks;
1413 } else {
1414 tmp.nentries = t->table->nentries;
1415 tmp.entries_size = t->table->entries_size;
1416 tmp.valid_hooks = t->table->valid_hooks;
1417 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001418 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 if (copy_to_user(user, &tmp, *len) != 0){
1420 BUGPRINT("c2u Didn't work\n");
1421 ret = -EFAULT;
1422 break;
1423 }
1424 ret = 0;
1425 break;
1426
1427 case EBT_SO_GET_ENTRIES:
1428 case EBT_SO_GET_INIT_ENTRIES:
1429 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001430 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 break;
1432
1433 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001434 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 ret = -EINVAL;
1436 }
1437
1438 return ret;
1439}
1440
1441static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001442{
1443 .pf = PF_INET,
1444 .set_optmin = EBT_BASE_CTL,
1445 .set_optmax = EBT_SO_SET_MAX + 1,
1446 .set = do_ebt_set_ctl,
1447 .get_optmin = EBT_BASE_CTL,
1448 .get_optmax = EBT_SO_GET_MAX + 1,
1449 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001450 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451};
1452
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001453static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
1455 int ret;
1456
Jan Engelhardt043ef462008-10-08 11:35:15 +02001457 ret = xt_register_target(&ebt_standard_target);
1458 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001460 ret = nf_register_sockopt(&ebt_sockopts);
1461 if (ret < 0) {
1462 xt_unregister_target(&ebt_standard_target);
1463 return ret;
1464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Patrick McHardya887c1c2007-07-14 20:46:15 -07001466 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 return 0;
1468}
1469
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001470static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
1472 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001473 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001474 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475}
1476
1477EXPORT_SYMBOL(ebt_register_table);
1478EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001480module_init(ebtables_init);
1481module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482MODULE_LICENSE("GPL");