blob: a1156bab4a034c8963f44f2b34e513e03b5eff7d [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
Jan Engelhardt7eb35582008-10-08 11:35:19 +020067static inline int
68ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
69 struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020071 par->target = w->u.watcher;
72 par->targinfo = w->data;
73 w->u.watcher->target(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 /* watchers don't give a verdict */
75 return 0;
76}
77
78static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020079 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020081 par->match = m->u.match;
82 par->matchinfo = m->data;
83 return m->u.match->match(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084}
85
86static inline int ebt_dev_check(char *entry, const struct net_device *device)
87{
88 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080089 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91 if (*entry == '\0')
92 return 0;
93 if (!device)
94 return 1;
95 /* 1 is the wildcard token */
96 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
97 i++;
98 return (devname[i] != entry[i] && entry[i] != 1);
99}
100
101#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
102/* process standard matches */
103static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
104 const struct net_device *in, const struct net_device *out)
105{
106 int verdict, i;
107
108 if (e->bitmask & EBT_802_3) {
109 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
110 return 1;
111 } else if (!(e->bitmask & EBT_NOPROTO) &&
112 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
113 return 1;
114
115 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
116 return 1;
117 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
118 return 1;
119 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
121 return 1;
122 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
123 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
124 return 1;
125
126 if (e->bitmask & EBT_SOURCEMAC) {
127 verdict = 0;
128 for (i = 0; i < 6; i++)
129 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
130 e->sourcemsk[i];
131 if (FWINV2(verdict != 0, EBT_ISOURCE) )
132 return 1;
133 }
134 if (e->bitmask & EBT_DESTMAC) {
135 verdict = 0;
136 for (i = 0; i < 6; i++)
137 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
138 e->destmsk[i];
139 if (FWINV2(verdict != 0, EBT_IDEST) )
140 return 1;
141 }
142 return 0;
143}
144
145/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700146unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 const struct net_device *in, const struct net_device *out,
148 struct ebt_table *table)
149{
150 int i, nentries;
151 struct ebt_entry *point;
152 struct ebt_counter *counter_base, *cb_base;
153 struct ebt_entry_target *t;
154 int verdict, sp = 0;
155 struct ebt_chainstack *cs;
156 struct ebt_entries *chaininfo;
157 char *base;
158 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200159 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200160 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200161 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200162
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200163 mtpar.in = tgpar.in = in;
164 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200165 mtpar.hotdrop = &hotdrop;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200166 tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 read_lock_bh(&table->lock);
169 private = table->private;
170 cb_base = COUNTER_BASE(private->counters, private->nentries,
171 smp_processor_id());
172 if (private->chainstack)
173 cs = private->chainstack[smp_processor_id()];
174 else
175 cs = NULL;
176 chaininfo = private->hook_entry[hook];
177 nentries = private->hook_entry[hook]->nentries;
178 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
179 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
180 /* base for chain jumps */
181 base = private->entries;
182 i = 0;
183 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700184 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 goto letscontinue;
186
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200187 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200189 if (hotdrop) {
190 read_unlock_bh(&table->lock);
191 return NF_DROP;
192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 /* increase counter */
195 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700196 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 /* these should only watch: not modify, nor tell us
199 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200200 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 t = (struct ebt_entry_target *)
203 (((char *)point) + point->target_offset);
204 /* standard target */
205 if (!t->u.target->target)
206 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200207 else {
208 tgpar.target = t->u.target;
209 tgpar.targinfo = t->data;
210 verdict = t->u.target->target(skb, &tgpar);
211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (verdict == EBT_ACCEPT) {
213 read_unlock_bh(&table->lock);
214 return NF_ACCEPT;
215 }
216 if (verdict == EBT_DROP) {
217 read_unlock_bh(&table->lock);
218 return NF_DROP;
219 }
220 if (verdict == EBT_RETURN) {
221letsreturn:
222#ifdef CONFIG_NETFILTER_DEBUG
223 if (sp == 0) {
224 BUGPRINT("RETURN on base chain");
225 /* act like this is EBT_CONTINUE */
226 goto letscontinue;
227 }
228#endif
229 sp--;
230 /* put all the local variables right */
231 i = cs[sp].n;
232 chaininfo = cs[sp].chaininfo;
233 nentries = chaininfo->nentries;
234 point = cs[sp].e;
235 counter_base = cb_base +
236 chaininfo->counter_offset;
237 continue;
238 }
239 if (verdict == EBT_CONTINUE)
240 goto letscontinue;
241#ifdef CONFIG_NETFILTER_DEBUG
242 if (verdict < 0) {
243 BUGPRINT("bogus standard verdict\n");
244 read_unlock_bh(&table->lock);
245 return NF_DROP;
246 }
247#endif
248 /* jump to a udc */
249 cs[sp].n = i + 1;
250 cs[sp].chaininfo = chaininfo;
251 cs[sp].e = (struct ebt_entry *)
252 (((char *)point) + point->next_offset);
253 i = 0;
254 chaininfo = (struct ebt_entries *) (base + verdict);
255#ifdef CONFIG_NETFILTER_DEBUG
256 if (chaininfo->distinguisher) {
257 BUGPRINT("jump to non-chain\n");
258 read_unlock_bh(&table->lock);
259 return NF_DROP;
260 }
261#endif
262 nentries = chaininfo->nentries;
263 point = (struct ebt_entry *)chaininfo->data;
264 counter_base = cb_base + chaininfo->counter_offset;
265 sp++;
266 continue;
267letscontinue:
268 point = (struct ebt_entry *)
269 (((char *)point) + point->next_offset);
270 i++;
271 }
272
273 /* I actually like this :) */
274 if (chaininfo->policy == EBT_RETURN)
275 goto letsreturn;
276 if (chaininfo->policy == EBT_ACCEPT) {
277 read_unlock_bh(&table->lock);
278 return NF_ACCEPT;
279 }
280 read_unlock_bh(&table->lock);
281 return NF_DROP;
282}
283
284/* If it succeeds, returns element and locks mutex */
285static inline void *
286find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800287 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700289 struct {
290 struct list_head list;
291 char name[EBT_FUNCTION_MAXNAMELEN];
292 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Ingo Molnar57b47a52006-03-20 22:35:41 -0800294 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 if (*error != 0)
296 return NULL;
297
Patrick McHardydf0933d2006-09-20 11:57:53 -0700298 list_for_each_entry(e, head, list) {
299 if (strcmp(e->name, name) == 0)
300 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700302 *error = -ENOENT;
303 mutex_unlock(mutex);
304 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
307#ifndef CONFIG_KMOD
308#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
309#else
310static void *
311find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800312 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 void *ret;
315
316 ret = find_inlist_lock_noload(head, name, error, mutex);
317 if (!ret) {
318 request_module("%s%s", prefix, name);
319 ret = find_inlist_lock_noload(head, name, error, mutex);
320 }
321 return ret;
322}
323#endif
324
325static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800326find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
329}
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200332ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
333 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200335 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200336 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800337 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 int ret;
339
Al Viro14197d52006-11-30 19:25:21 -0800340 if (left < sizeof(struct ebt_entry_match) ||
341 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200343
344 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
345 m->u.name, 0), "ebt_%s", m->u.name);
346 if (IS_ERR(match))
347 return PTR_ERR(match);
348 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200350 m->u.match = match;
351
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200352 par->match = match;
353 par->matchinfo = m->data;
354 ret = xt_check_match(par, NFPROTO_BRIDGE, m->match_size,
355 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200356 if (ret < 0) {
357 module_put(match->me);
358 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 (*cnt)++;
362 return 0;
363}
364
365static inline int
366ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
367 const char *name, unsigned int hookmask, unsigned int *cnt)
368{
Jan Engelhardt043ef462008-10-08 11:35:15 +0200369 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800370 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 int ret;
372
Al Viro14197d52006-11-30 19:25:21 -0800373 if (left < sizeof(struct ebt_entry_watcher) ||
374 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200376
377 watcher = try_then_request_module(
378 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
379 "ebt_%s", w->u.name);
380 if (IS_ERR(watcher))
381 return PTR_ERR(watcher);
382 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200384 w->u.watcher = watcher;
385
386 ret = xt_check_target(watcher, NFPROTO_BRIDGE, w->watcher_size,
Jan Engelhardt367c6792008-10-08 11:35:17 +0200387 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO,
388 e, w->data);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200389 if (ret < 0) {
390 module_put(watcher->me);
391 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (*cnt)++;
395 return 0;
396}
397
Al Viro70fe9af2006-11-30 19:26:14 -0800398static int ebt_verify_pointers(struct ebt_replace *repl,
399 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Al Viro70fe9af2006-11-30 19:26:14 -0800401 unsigned int limit = repl->entries_size;
402 unsigned int valid_hooks = repl->valid_hooks;
403 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 int i;
405
Al Viroe4fd77d2006-11-30 19:26:35 -0800406 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
Al Viro70fe9af2006-11-30 19:26:14 -0800412 while (offset < limit) {
413 size_t left = limit - offset;
414 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800415
Al Viro70fe9af2006-11-30 19:26:14 -0800416 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 break;
Al Viro22b440b2006-11-30 19:25:51 -0800418
Al Viro70fe9af2006-11-30 19:26:14 -0800419 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
420 if ((valid_hooks & (1 << i)) == 0)
421 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800422 if ((char __user *)repl->hook_entry[i] ==
423 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800424 break;
425 }
426
427 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
428 if (e->bitmask != 0) {
429 /* we make userspace set this right,
430 so there is no misunderstanding */
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 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800452
453 /* check if all valid hooks have a chain */
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 }
Al Viro70fe9af2006-11-30 19:26:14 -0800461 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800462}
463
464/*
465 * this one is very careful, as it is the first function
466 * to parse the userspace data
467 */
468static inline int
469ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800470 struct ebt_table_info *newinfo,
471 unsigned int *n, unsigned int *cnt,
472 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800473{
Al Viro22b440b2006-11-30 19:25:51 -0800474 int i;
475
476 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800477 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800478 break;
479 }
480 /* beginning of a new chain
481 if i == NF_BR_NUMHOOKS it must be a user defined chain */
482 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 /* this checks if the previous chain has as many entries
484 as it said it has */
485 if (*n != *cnt) {
486 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900487 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return -EINVAL;
489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
491 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
492 /* only RETURN from udc */
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) /* it's a user defined chain */
500 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 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 /* a plain old entry, heh */
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 /* this is not checked anywhere else */
517 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
518 BUGPRINT("target size too small\n");
519 return -EINVAL;
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 (*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 * we need these positions to check that the jumps to a different part of the
535 * entries is a jump to the beginning of a new chain.
536 */
537static inline int
538ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800539 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 int i;
542
543 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800544 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return 0;
546 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
548 break;
549 }
550 /* only care about udc */
551 if (i != NF_BR_NUMHOOKS)
552 return 0;
553
554 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
555 /* these initialisations are depended on later in check_chainloops() */
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{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200566 struct xt_mtdtor_param par;
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (i && (*i)-- == 0)
569 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200571 par.match = m->u.match;
572 par.matchinfo = m->data;
573 if (par.match->destroy != NULL)
574 par.match->destroy(&par);
575 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return 0;
577}
578
579static inline int
580ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
581{
582 if (i && (*i)-- == 0)
583 return 1;
584 if (w->u.watcher->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200585 w->u.watcher->destroy(w->u.watcher, w->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 module_put(w->u.watcher->me);
587
588 return 0;
589}
590
591static inline int
592ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
593{
594 struct ebt_entry_target *t;
595
Al Viro40642f92006-11-30 19:24:12 -0800596 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return 0;
598 /* we're done */
599 if (cnt && (*cnt)-- == 0)
600 return 1;
601 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
602 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
603 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
604 if (t->u.target->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200605 t->u.target->destroy(t->u.target, t->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 module_put(t->u.target->me);
607
608 return 0;
609}
610
611static inline int
612ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800613 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
615{
616 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200617 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800619 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200621 struct xt_mtchk_param mtpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800624 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return 0;
626
627 if (e->bitmask & ~EBT_F_MASK) {
628 BUGPRINT("Unknown flag for bitmask\n");
629 return -EINVAL;
630 }
631 if (e->invflags & ~EBT_INV_MASK) {
632 BUGPRINT("Unknown flag for inv bitmask\n");
633 return -EINVAL;
634 }
635 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
636 BUGPRINT("NOPROTO & 802_3 not allowed\n");
637 return -EINVAL;
638 }
639 /* what hook do we belong to? */
640 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800641 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 continue;
643 if ((char *)newinfo->hook_entry[i] < (char *)e)
644 hook = i;
645 else
646 break;
647 }
648 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
649 a base chain */
650 if (i < NF_BR_NUMHOOKS)
651 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
652 else {
653 for (i = 0; i < udc_cnt; i++)
654 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
655 break;
656 if (i == 0)
657 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
658 else
659 hookmask = cl_s[i - 1].hookmask;
660 }
661 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200662
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200663 mtpar.table = name;
664 mtpar.entryinfo = e;
665 mtpar.hook_mask = hookmask;
666 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if (ret != 0)
668 goto cleanup_matches;
669 j = 0;
670 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
671 if (ret != 0)
672 goto cleanup_watchers;
673 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800674 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Jan Engelhardt043ef462008-10-08 11:35:15 +0200676 target = try_then_request_module(
677 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
678 "ebt_%s", t->u.name);
679 if (IS_ERR(target)) {
680 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200681 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200682 } else if (target == NULL) {
683 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200684 goto cleanup_watchers;
685 }
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 t->u.target = target;
688 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800689 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 BUGPRINT("Standard target size too big\n");
691 ret = -EFAULT;
692 goto cleanup_watchers;
693 }
694 if (((struct ebt_standard_target *)t)->verdict <
695 -NUM_STANDARD_TARGETS) {
696 BUGPRINT("Invalid standard target\n");
697 ret = -EFAULT;
698 goto cleanup_watchers;
699 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200700 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
701 module_put(t->u.target->me);
702 ret = -EFAULT;
703 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200704 }
705
706 ret = xt_check_target(target, NFPROTO_BRIDGE, t->target_size,
Jan Engelhardt367c6792008-10-08 11:35:17 +0200707 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO,
708 e, t->data);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200709 if (ret < 0) {
710 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200711 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 }
713 (*cnt)++;
714 return 0;
715cleanup_watchers:
716 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
717cleanup_matches:
718 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
719 return ret;
720}
721
722/*
723 * checks for loops and sets the hook mask for udc
724 * the hook mask for udc tells us from which base chains the udc can be
725 * accessed. This mask is a parameter to the check() functions of the extensions
726 */
727static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
728 unsigned int udc_cnt, unsigned int hooknr, char *base)
729{
730 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
731 struct ebt_entry *e = (struct ebt_entry *)chain->data;
732 struct ebt_entry_target *t;
733
734 while (pos < nentries || chain_nr != -1) {
735 /* end of udc, go back one 'recursion' step */
736 if (pos == nentries) {
737 /* put back values of the time when this chain was called */
738 e = cl_s[chain_nr].cs.e;
739 if (cl_s[chain_nr].from != -1)
740 nentries =
741 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
742 else
743 nentries = chain->nentries;
744 pos = cl_s[chain_nr].cs.n;
745 /* make sure we won't see a loop that isn't one */
746 cl_s[chain_nr].cs.n = 0;
747 chain_nr = cl_s[chain_nr].from;
748 if (pos == nentries)
749 continue;
750 }
751 t = (struct ebt_entry_target *)
752 (((char *)e) + e->target_offset);
753 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
754 goto letscontinue;
755 if (e->target_offset + sizeof(struct ebt_standard_target) >
756 e->next_offset) {
757 BUGPRINT("Standard target size too big\n");
758 return -1;
759 }
760 verdict = ((struct ebt_standard_target *)t)->verdict;
761 if (verdict >= 0) { /* jump to another chain */
762 struct ebt_entries *hlp2 =
763 (struct ebt_entries *)(base + verdict);
764 for (i = 0; i < udc_cnt; i++)
765 if (hlp2 == cl_s[i].cs.chaininfo)
766 break;
767 /* bad destination or loop */
768 if (i == udc_cnt) {
769 BUGPRINT("bad destination\n");
770 return -1;
771 }
772 if (cl_s[i].cs.n) {
773 BUGPRINT("loop\n");
774 return -1;
775 }
Al Viro98a08242006-11-30 19:24:49 -0800776 if (cl_s[i].hookmask & (1 << hooknr))
777 goto letscontinue;
778 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 cl_s[i].cs.n = pos + 1;
780 pos = 0;
781 cl_s[i].cs.e = ((void *)e + e->next_offset);
782 e = (struct ebt_entry *)(hlp2->data);
783 nentries = hlp2->nentries;
784 cl_s[i].from = chain_nr;
785 chain_nr = i;
786 /* this udc is accessible from the base chain for hooknr */
787 cl_s[i].hookmask |= (1 << hooknr);
788 continue;
789 }
790letscontinue:
791 e = (void *)e + e->next_offset;
792 pos++;
793 }
794 return 0;
795}
796
797/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800798static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
800 unsigned int i, j, k, udc_cnt;
801 int ret;
802 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
803
804 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800805 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 i++;
807 if (i == NF_BR_NUMHOOKS) {
808 BUGPRINT("No valid hooks specified\n");
809 return -EINVAL;
810 }
Al Viro1f072c92006-11-30 19:26:53 -0800811 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 BUGPRINT("Chains don't start at beginning\n");
813 return -EINVAL;
814 }
815 /* make sure chains are ordered after each other in same order
816 as their corresponding hooks */
817 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800818 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800820 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 BUGPRINT("Hook order must be followed\n");
822 return -EINVAL;
823 }
824 i = j;
825 }
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 /* do some early checkings and initialize some things */
828 i = 0; /* holds the expected nr. of entries for the chain */
829 j = 0; /* holds the up to now counted entries for the chain */
830 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900831 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
833 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800834 ebt_check_entry_size_and_hooks, newinfo,
835 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 if (ret != 0)
838 return ret;
839
840 if (i != j) {
841 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900842 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 return -EINVAL;
844 }
845 if (k != newinfo->nentries) {
846 BUGPRINT("Total nentries is wrong\n");
847 return -EINVAL;
848 }
849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* get the location of the udc, put them in an array
851 while we're at it, allocate the chainstack */
852 if (udc_cnt) {
853 /* this will get free'd in do_replace()/ebt_register_table()
854 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700855 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800856 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (!newinfo->chainstack)
858 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700859 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700861 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (!newinfo->chainstack[i]) {
863 while (i)
864 vfree(newinfo->chainstack[--i]);
865 vfree(newinfo->chainstack);
866 newinfo->chainstack = NULL;
867 return -ENOMEM;
868 }
869 }
870
Jayachandran C18bc89a2006-04-20 00:14:49 -0700871 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (!cl_s)
873 return -ENOMEM;
874 i = 0; /* the i'th udc */
875 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800876 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* sanity check */
878 if (i != udc_cnt) {
879 BUGPRINT("i != udc_cnt\n");
880 vfree(cl_s);
881 return -EFAULT;
882 }
883 }
884
885 /* Check for loops */
886 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800887 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (check_chainloops(newinfo->hook_entry[i],
889 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700890 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return -EINVAL;
892 }
893
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200894 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 - the nr of entries in each chain is right
896 - the size of the allocated space is right
897 - all valid hooks have a corresponding chain
898 - there are no loops
899 - wrong data can still be on the level of a single entry
900 - could be there are jumps to places that are not the
901 beginning of a chain. This can only occur in chains that
902 are not accessible from any base chains, so we don't care. */
903
904 /* used to know what we need to clean up if something goes wrong */
905 i = 0;
906 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800907 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (ret != 0) {
909 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
910 ebt_cleanup_entry, &i);
911 }
James Lamanna68d31872005-06-22 22:12:57 -0700912 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 return ret;
914}
915
916/* called under write_lock */
917static void get_counters(struct ebt_counter *oldcounters,
918 struct ebt_counter *counters, unsigned int nentries)
919{
920 int i, cpu;
921 struct ebt_counter *counter_base;
922
923 /* counters of cpu 0 */
924 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700925 sizeof(struct ebt_counter) * nentries);
926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700928 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700929 if (cpu == 0)
930 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
932 for (i = 0; i < nentries; i++) {
933 counters[i].pcnt += counter_base[i].pcnt;
934 counters[i].bcnt += counter_base[i].bcnt;
935 }
936 }
937}
938
939/* replace the table */
940static int do_replace(void __user *user, unsigned int len)
941{
942 int ret, i, countersize;
943 struct ebt_table_info *newinfo;
944 struct ebt_replace tmp;
945 struct ebt_table *t;
946 struct ebt_counter *counterstmp = NULL;
947 /* used to be able to unlock earlier */
948 struct ebt_table_info *table;
949
950 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
951 return -EFAULT;
952
953 if (len != sizeof(tmp) + tmp.entries_size) {
954 BUGPRINT("Wrong len argument\n");
955 return -EINVAL;
956 }
957
958 if (tmp.entries_size == 0) {
959 BUGPRINT("Entries_size never zero\n");
960 return -EINVAL;
961 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800962 /* overflow check */
963 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
964 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
965 return -ENOMEM;
966 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
967 return -ENOMEM;
968
Christoph Lameter53b8a312007-02-20 13:57:51 -0800969 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700970 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (!newinfo)
972 return -ENOMEM;
973
974 if (countersize)
975 memset(newinfo->counters, 0, countersize);
976
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800977 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (!newinfo->entries) {
979 ret = -ENOMEM;
980 goto free_newinfo;
981 }
982 if (copy_from_user(
983 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
984 BUGPRINT("Couldn't copy entries from userspace\n");
985 ret = -EFAULT;
986 goto free_entries;
987 }
988
989 /* the user wants counters back
990 the check on the size is done later, when we have the lock */
991 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700992 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (!counterstmp) {
994 ret = -ENOMEM;
995 goto free_entries;
996 }
997 }
998 else
999 counterstmp = NULL;
1000
1001 /* this can get initialized by translate_table() */
1002 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001003 ret = ebt_verify_pointers(&tmp, newinfo);
1004 if (ret != 0)
1005 goto free_counterstmp;
1006
1007 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
1009 if (ret != 0)
1010 goto free_counterstmp;
1011
1012 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1013 if (!t) {
1014 ret = -ENOENT;
1015 goto free_iterate;
1016 }
1017
1018 /* the table doesn't like it */
1019 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1020 goto free_unlock;
1021
1022 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1023 BUGPRINT("Wrong nr. of counters requested\n");
1024 ret = -EINVAL;
1025 goto free_unlock;
1026 }
1027
1028 /* we have the mutex lock, so no danger in reading this pointer */
1029 table = t->private;
1030 /* make sure the table can only be rmmod'ed if it contains no rules */
1031 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1032 ret = -ENOENT;
1033 goto free_unlock;
1034 } else if (table->nentries && !newinfo->nentries)
1035 module_put(t->me);
1036 /* we need an atomic snapshot of the counters */
1037 write_lock_bh(&t->lock);
1038 if (tmp.num_counters)
1039 get_counters(t->private->counters, counterstmp,
1040 t->private->nentries);
1041
1042 t->private = newinfo;
1043 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001044 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 /* so, a user can change the chains while having messed up her counter
1046 allocation. Only reason why this is done is because this way the lock
1047 is held only once, while this doesn't bring the kernel into a
1048 dangerous state. */
1049 if (tmp.num_counters &&
1050 copy_to_user(tmp.counters, counterstmp,
1051 tmp.num_counters * sizeof(struct ebt_counter))) {
1052 BUGPRINT("Couldn't copy counters to userspace\n");
1053 ret = -EFAULT;
1054 }
1055 else
1056 ret = 0;
1057
1058 /* decrease module count and free resources */
1059 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1060 ebt_cleanup_entry, NULL);
1061
1062 vfree(table->entries);
1063 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001064 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 vfree(table->chainstack[i]);
1066 vfree(table->chainstack);
1067 }
1068 vfree(table);
1069
James Lamanna68d31872005-06-22 22:12:57 -07001070 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return ret;
1072
1073free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001074 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075free_iterate:
1076 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1077 ebt_cleanup_entry, NULL);
1078free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001079 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 /* can be initialized in translate_table() */
1081 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001082 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 vfree(newinfo->chainstack[i]);
1084 vfree(newinfo->chainstack);
1085 }
1086free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001087 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001089 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 return ret;
1091}
1092
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093int ebt_register_table(struct ebt_table *table)
1094{
1095 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001096 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001097 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001099 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Al Virodf07a812006-11-30 19:28:25 -08001101 if (!table || !(repl = table->table) || !repl->entries ||
1102 repl->entries_size == 0 ||
1103 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1105 return -EINVAL;
1106 }
1107
Christoph Lameter53b8a312007-02-20 13:57:51 -08001108 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001109 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 ret = -ENOMEM;
1111 if (!newinfo)
1112 return -ENOMEM;
1113
Al Virodf07a812006-11-30 19:28:25 -08001114 p = vmalloc(repl->entries_size);
1115 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 goto free_newinfo;
1117
Al Virodf07a812006-11-30 19:28:25 -08001118 memcpy(p, repl->entries, repl->entries_size);
1119 newinfo->entries = p;
1120
1121 newinfo->entries_size = repl->entries_size;
1122 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 if (countersize)
1125 memset(newinfo->counters, 0, countersize);
1126
1127 /* fill in newinfo and parse the entries */
1128 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001129 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1130 if ((repl->valid_hooks & (1 << i)) == 0)
1131 newinfo->hook_entry[i] = NULL;
1132 else
1133 newinfo->hook_entry[i] = p +
1134 ((char *)repl->hook_entry[i] - repl->entries);
1135 }
1136 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if (ret != 0) {
1138 BUGPRINT("Translate_table failed\n");
1139 goto free_chainstack;
1140 }
1141
1142 if (table->check && table->check(newinfo, table->valid_hooks)) {
1143 BUGPRINT("The table doesn't like its own initial data, lol\n");
1144 return -EINVAL;
1145 }
1146
1147 table->private = newinfo;
1148 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001149 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (ret != 0)
1151 goto free_chainstack;
1152
Patrick McHardydf0933d2006-09-20 11:57:53 -07001153 list_for_each_entry(t, &ebt_tables, list) {
1154 if (strcmp(t->name, table->name) == 0) {
1155 ret = -EEXIST;
1156 BUGPRINT("Table name already exists\n");
1157 goto free_unlock;
1158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160
1161 /* Hold a reference count if the chains aren't empty */
1162 if (newinfo->nentries && !try_module_get(table->me)) {
1163 ret = -ENOENT;
1164 goto free_unlock;
1165 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001166 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001167 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 return 0;
1169free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001170 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171free_chainstack:
1172 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001173 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 vfree(newinfo->chainstack[i]);
1175 vfree(newinfo->chainstack);
1176 }
1177 vfree(newinfo->entries);
1178free_newinfo:
1179 vfree(newinfo);
1180 return ret;
1181}
1182
1183void ebt_unregister_table(struct ebt_table *table)
1184{
1185 int i;
1186
1187 if (!table) {
1188 BUGPRINT("Request to unregister NULL table!!!\n");
1189 return;
1190 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001191 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001192 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001193 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001194 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001196 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 vfree(table->private->chainstack[i]);
1198 vfree(table->private->chainstack);
1199 }
1200 vfree(table->private);
1201}
1202
1203/* userspace just supplied us with counters */
1204static int update_counters(void __user *user, unsigned int len)
1205{
1206 int i, ret;
1207 struct ebt_counter *tmp;
1208 struct ebt_replace hlp;
1209 struct ebt_table *t;
1210
1211 if (copy_from_user(&hlp, user, sizeof(hlp)))
1212 return -EFAULT;
1213
1214 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1215 return -EINVAL;
1216 if (hlp.num_counters == 0)
1217 return -EINVAL;
1218
Jayachandran C18bc89a2006-04-20 00:14:49 -07001219 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 MEMPRINT("Update_counters && nomemory\n");
1221 return -ENOMEM;
1222 }
1223
1224 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1225 if (!t)
1226 goto free_tmp;
1227
1228 if (hlp.num_counters != t->private->nentries) {
1229 BUGPRINT("Wrong nr of counters\n");
1230 ret = -EINVAL;
1231 goto unlock_mutex;
1232 }
1233
1234 if ( copy_from_user(tmp, hlp.counters,
1235 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1236 BUGPRINT("Updata_counters && !cfu\n");
1237 ret = -EFAULT;
1238 goto unlock_mutex;
1239 }
1240
1241 /* we want an atomic add of the counters */
1242 write_lock_bh(&t->lock);
1243
1244 /* we add to the counters of the first cpu */
1245 for (i = 0; i < hlp.num_counters; i++) {
1246 t->private->counters[i].pcnt += tmp[i].pcnt;
1247 t->private->counters[i].bcnt += tmp[i].bcnt;
1248 }
1249
1250 write_unlock_bh(&t->lock);
1251 ret = 0;
1252unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001253 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254free_tmp:
1255 vfree(tmp);
1256 return ret;
1257}
1258
1259static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001260 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261{
Al Viro1e419cd2006-11-30 19:28:48 -08001262 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1264 return -EFAULT;
1265 return 0;
1266}
1267
1268static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001269 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270{
Al Viro1e419cd2006-11-30 19:28:48 -08001271 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1273 return -EFAULT;
1274 return 0;
1275}
1276
Al Viro1e419cd2006-11-30 19:28:48 -08001277static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001280 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 struct ebt_entry_target *t;
1282
Al Viro40642f92006-11-30 19:24:12 -08001283 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 return 0;
1285
Al Viro1e419cd2006-11-30 19:28:48 -08001286 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1290 if (ret != 0)
1291 return ret;
1292 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1293 if (ret != 0)
1294 return ret;
1295 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1296 return -EFAULT;
1297 return 0;
1298}
1299
Ingo Molnar57b47a52006-03-20 22:35:41 -08001300/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1302 int *len, int cmd)
1303{
1304 struct ebt_replace tmp;
1305 struct ebt_counter *counterstmp, *oldcounters;
1306 unsigned int entries_size, nentries;
1307 char *entries;
1308
1309 if (cmd == EBT_SO_GET_ENTRIES) {
1310 entries_size = t->private->entries_size;
1311 nentries = t->private->nentries;
1312 entries = t->private->entries;
1313 oldcounters = t->private->counters;
1314 } else {
1315 entries_size = t->table->entries_size;
1316 nentries = t->table->nentries;
1317 entries = t->table->entries;
1318 oldcounters = t->table->counters;
1319 }
1320
1321 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1322 BUGPRINT("Cfu didn't work\n");
1323 return -EFAULT;
1324 }
1325
1326 if (*len != sizeof(struct ebt_replace) + entries_size +
1327 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1328 BUGPRINT("Wrong size\n");
1329 return -EINVAL;
1330 }
1331
1332 if (tmp.nentries != nentries) {
1333 BUGPRINT("Nentries wrong\n");
1334 return -EINVAL;
1335 }
1336
1337 if (tmp.entries_size != entries_size) {
1338 BUGPRINT("Wrong size\n");
1339 return -EINVAL;
1340 }
1341
1342 /* userspace might not need the counters */
1343 if (tmp.num_counters) {
1344 if (tmp.num_counters != nentries) {
1345 BUGPRINT("Num_counters wrong\n");
1346 return -EINVAL;
1347 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001348 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (!counterstmp) {
1350 MEMPRINT("Couldn't copy counters, out of memory\n");
1351 return -ENOMEM;
1352 }
1353 write_lock_bh(&t->lock);
1354 get_counters(oldcounters, counterstmp, nentries);
1355 write_unlock_bh(&t->lock);
1356
1357 if (copy_to_user(tmp.counters, counterstmp,
1358 nentries * sizeof(struct ebt_counter))) {
1359 BUGPRINT("Couldn't copy counters to userspace\n");
1360 vfree(counterstmp);
1361 return -EFAULT;
1362 }
1363 vfree(counterstmp);
1364 }
1365
1366 if (copy_to_user(tmp.entries, entries, entries_size)) {
1367 BUGPRINT("Couldn't copy entries to userspace\n");
1368 return -EFAULT;
1369 }
1370 /* set the match/watcher/target names right */
1371 return EBT_ENTRY_ITERATE(entries, entries_size,
1372 ebt_make_names, entries, tmp.entries);
1373}
1374
1375static int do_ebt_set_ctl(struct sock *sk,
1376 int cmd, void __user *user, unsigned int len)
1377{
1378 int ret;
1379
1380 switch(cmd) {
1381 case EBT_SO_SET_ENTRIES:
1382 ret = do_replace(user, len);
1383 break;
1384 case EBT_SO_SET_COUNTERS:
1385 ret = update_counters(user, len);
1386 break;
1387 default:
1388 ret = -EINVAL;
1389 }
1390 return ret;
1391}
1392
1393static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1394{
1395 int ret;
1396 struct ebt_replace tmp;
1397 struct ebt_table *t;
1398
1399 if (copy_from_user(&tmp, user, sizeof(tmp)))
1400 return -EFAULT;
1401
1402 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1403 if (!t)
1404 return ret;
1405
1406 switch(cmd) {
1407 case EBT_SO_GET_INFO:
1408 case EBT_SO_GET_INIT_INFO:
1409 if (*len != sizeof(struct ebt_replace)){
1410 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001411 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 break;
1413 }
1414 if (cmd == EBT_SO_GET_INFO) {
1415 tmp.nentries = t->private->nentries;
1416 tmp.entries_size = t->private->entries_size;
1417 tmp.valid_hooks = t->valid_hooks;
1418 } else {
1419 tmp.nentries = t->table->nentries;
1420 tmp.entries_size = t->table->entries_size;
1421 tmp.valid_hooks = t->table->valid_hooks;
1422 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001423 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (copy_to_user(user, &tmp, *len) != 0){
1425 BUGPRINT("c2u Didn't work\n");
1426 ret = -EFAULT;
1427 break;
1428 }
1429 ret = 0;
1430 break;
1431
1432 case EBT_SO_GET_ENTRIES:
1433 case EBT_SO_GET_INIT_ENTRIES:
1434 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001435 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 break;
1437
1438 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001439 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 ret = -EINVAL;
1441 }
1442
1443 return ret;
1444}
1445
1446static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001447{
1448 .pf = PF_INET,
1449 .set_optmin = EBT_BASE_CTL,
1450 .set_optmax = EBT_SO_SET_MAX + 1,
1451 .set = do_ebt_set_ctl,
1452 .get_optmin = EBT_BASE_CTL,
1453 .get_optmax = EBT_SO_GET_MAX + 1,
1454 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001455 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456};
1457
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001458static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
1460 int ret;
1461
Jan Engelhardt043ef462008-10-08 11:35:15 +02001462 ret = xt_register_target(&ebt_standard_target);
1463 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001465 ret = nf_register_sockopt(&ebt_sockopts);
1466 if (ret < 0) {
1467 xt_unregister_target(&ebt_standard_target);
1468 return ret;
1469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
Patrick McHardya887c1c2007-07-14 20:46:15 -07001471 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 return 0;
1473}
1474
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001475static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476{
1477 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001478 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001479 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480}
1481
1482EXPORT_SYMBOL(ebt_register_table);
1483EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001485module_init(ebtables_init);
1486module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487MODULE_LICENSE("GPL");