blob: 29d8061fa15355bee99e7fe485dc94b018fac0bb [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
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200366ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
367 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200369 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200370 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800371 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int ret;
373
Al Viro14197d52006-11-30 19:25:21 -0800374 if (left < sizeof(struct ebt_entry_watcher) ||
375 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200377
378 watcher = try_then_request_module(
379 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
380 "ebt_%s", w->u.name);
381 if (IS_ERR(watcher))
382 return PTR_ERR(watcher);
383 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200385 w->u.watcher = watcher;
386
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200387 par->target = watcher;
388 par->targinfo = w->data;
389 ret = xt_check_target(par, NFPROTO_BRIDGE, w->watcher_size,
390 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200391 if (ret < 0) {
392 module_put(watcher->me);
393 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 (*cnt)++;
397 return 0;
398}
399
Al Viro70fe9af2006-11-30 19:26:14 -0800400static int ebt_verify_pointers(struct ebt_replace *repl,
401 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Al Viro70fe9af2006-11-30 19:26:14 -0800403 unsigned int limit = repl->entries_size;
404 unsigned int valid_hooks = repl->valid_hooks;
405 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 int i;
407
Al Viroe4fd77d2006-11-30 19:26:35 -0800408 for (i = 0; i < NF_BR_NUMHOOKS; i++)
409 newinfo->hook_entry[i] = NULL;
410
411 newinfo->entries_size = repl->entries_size;
412 newinfo->nentries = repl->nentries;
413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 while (offset < limit) {
415 size_t left = limit - offset;
416 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800417
Al Viro70fe9af2006-11-30 19:26:14 -0800418 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
Al Viro22b440b2006-11-30 19:25:51 -0800420
Al Viro70fe9af2006-11-30 19:26:14 -0800421 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
422 if ((valid_hooks & (1 << i)) == 0)
423 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800424 if ((char __user *)repl->hook_entry[i] ==
425 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800426 break;
427 }
428
429 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
430 if (e->bitmask != 0) {
431 /* we make userspace set this right,
432 so there is no misunderstanding */
433 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
434 "in distinguisher\n");
435 return -EINVAL;
436 }
437 if (i != NF_BR_NUMHOOKS)
438 newinfo->hook_entry[i] = (struct ebt_entries *)e;
439 if (left < sizeof(struct ebt_entries))
440 break;
441 offset += sizeof(struct ebt_entries);
442 } else {
443 if (left < sizeof(struct ebt_entry))
444 break;
445 if (left < e->next_offset)
446 break;
447 offset += e->next_offset;
448 }
449 }
450 if (offset != limit) {
451 BUGPRINT("entries_size too small\n");
452 return -EINVAL;
453 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800454
455 /* check if all valid hooks have a chain */
456 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
457 if (!newinfo->hook_entry[i] &&
458 (valid_hooks & (1 << i))) {
459 BUGPRINT("Valid hook without chain\n");
460 return -EINVAL;
461 }
462 }
Al Viro70fe9af2006-11-30 19:26:14 -0800463 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800464}
465
466/*
467 * this one is very careful, as it is the first function
468 * to parse the userspace data
469 */
470static inline int
471ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800472 struct ebt_table_info *newinfo,
473 unsigned int *n, unsigned int *cnt,
474 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800475{
Al Viro22b440b2006-11-30 19:25:51 -0800476 int i;
477
478 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800479 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800480 break;
481 }
482 /* beginning of a new chain
483 if i == NF_BR_NUMHOOKS it must be a user defined chain */
484 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 /* this checks if the previous chain has as many entries
486 as it said it has */
487 if (*n != *cnt) {
488 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900489 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return -EINVAL;
491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
493 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
494 /* only RETURN from udc */
495 if (i != NF_BR_NUMHOOKS ||
496 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
497 BUGPRINT("bad policy\n");
498 return -EINVAL;
499 }
500 }
501 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
502 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
504 BUGPRINT("counter_offset != totalcnt");
505 return -EINVAL;
506 }
507 *n = ((struct ebt_entries *)e)->nentries;
508 *cnt = 0;
509 return 0;
510 }
511 /* a plain old entry, heh */
512 if (sizeof(struct ebt_entry) > e->watchers_offset ||
513 e->watchers_offset > e->target_offset ||
514 e->target_offset >= e->next_offset) {
515 BUGPRINT("entry offsets not in right order\n");
516 return -EINVAL;
517 }
518 /* this is not checked anywhere else */
519 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
520 BUGPRINT("target size too small\n");
521 return -EINVAL;
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 (*cnt)++;
524 (*totalcnt)++;
525 return 0;
526}
527
528struct ebt_cl_stack
529{
530 struct ebt_chainstack cs;
531 int from;
532 unsigned int hookmask;
533};
534
535/*
536 * we need these positions to check that the jumps to a different part of the
537 * entries is a jump to the beginning of a new chain.
538 */
539static inline int
540ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800541 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 int i;
544
545 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800546 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return 0;
548 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
550 break;
551 }
552 /* only care about udc */
553 if (i != NF_BR_NUMHOOKS)
554 return 0;
555
556 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
557 /* these initialisations are depended on later in check_chainloops() */
558 udc[*n].cs.n = 0;
559 udc[*n].hookmask = 0;
560
561 (*n)++;
562 return 0;
563}
564
565static inline int
566ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
567{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200568 struct xt_mtdtor_param par;
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (i && (*i)-- == 0)
571 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200573 par.match = m->u.match;
574 par.matchinfo = m->data;
575 if (par.match->destroy != NULL)
576 par.match->destroy(&par);
577 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return 0;
579}
580
581static inline int
582ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
583{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200584 struct xt_tgdtor_param par;
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (i && (*i)-- == 0)
587 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Jan Engelhardta2df1642008-10-08 11:35:19 +0200589 par.target = w->u.watcher;
590 par.targinfo = w->data;
591 if (par.target->destroy != NULL)
592 par.target->destroy(&par);
593 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 0;
595}
596
597static inline int
598ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
599{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200600 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 struct ebt_entry_target *t;
602
Al Viro40642f92006-11-30 19:24:12 -0800603 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 return 0;
605 /* we're done */
606 if (cnt && (*cnt)-- == 0)
607 return 1;
608 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
609 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
610 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Jan Engelhardta2df1642008-10-08 11:35:19 +0200612 par.target = t->u.target;
613 par.targinfo = t->data;
614 if (par.target->destroy != NULL)
615 par.target->destroy(&par);
616 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return 0;
618}
619
620static inline int
621ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800622 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
624{
625 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200626 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800628 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200630 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200631 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800634 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return 0;
636
637 if (e->bitmask & ~EBT_F_MASK) {
638 BUGPRINT("Unknown flag for bitmask\n");
639 return -EINVAL;
640 }
641 if (e->invflags & ~EBT_INV_MASK) {
642 BUGPRINT("Unknown flag for inv bitmask\n");
643 return -EINVAL;
644 }
645 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
646 BUGPRINT("NOPROTO & 802_3 not allowed\n");
647 return -EINVAL;
648 }
649 /* what hook do we belong to? */
650 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800651 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 continue;
653 if ((char *)newinfo->hook_entry[i] < (char *)e)
654 hook = i;
655 else
656 break;
657 }
658 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
659 a base chain */
660 if (i < NF_BR_NUMHOOKS)
661 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
662 else {
663 for (i = 0; i < udc_cnt; i++)
664 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
665 break;
666 if (i == 0)
667 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
668 else
669 hookmask = cl_s[i - 1].hookmask;
670 }
671 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200672
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200673 mtpar.table = tgpar.table = name;
674 mtpar.entryinfo = tgpar.entryinfo = e;
675 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200676 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (ret != 0)
678 goto cleanup_matches;
679 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200680 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (ret != 0)
682 goto cleanup_watchers;
683 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800684 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Jan Engelhardt043ef462008-10-08 11:35:15 +0200686 target = try_then_request_module(
687 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
688 "ebt_%s", t->u.name);
689 if (IS_ERR(target)) {
690 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200691 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200692 } else if (target == NULL) {
693 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200694 goto cleanup_watchers;
695 }
696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 t->u.target = target;
698 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800699 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 BUGPRINT("Standard target size too big\n");
701 ret = -EFAULT;
702 goto cleanup_watchers;
703 }
704 if (((struct ebt_standard_target *)t)->verdict <
705 -NUM_STANDARD_TARGETS) {
706 BUGPRINT("Invalid standard target\n");
707 ret = -EFAULT;
708 goto cleanup_watchers;
709 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200710 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
711 module_put(t->u.target->me);
712 ret = -EFAULT;
713 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200714 }
715
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200716 tgpar.target = target;
717 tgpar.targinfo = t->data;
718 ret = xt_check_target(&tgpar, NFPROTO_BRIDGE, t->target_size,
719 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200720 if (ret < 0) {
721 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200722 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 (*cnt)++;
725 return 0;
726cleanup_watchers:
727 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
728cleanup_matches:
729 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
730 return ret;
731}
732
733/*
734 * checks for loops and sets the hook mask for udc
735 * the hook mask for udc tells us from which base chains the udc can be
736 * accessed. This mask is a parameter to the check() functions of the extensions
737 */
738static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
739 unsigned int udc_cnt, unsigned int hooknr, char *base)
740{
741 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
742 struct ebt_entry *e = (struct ebt_entry *)chain->data;
743 struct ebt_entry_target *t;
744
745 while (pos < nentries || chain_nr != -1) {
746 /* end of udc, go back one 'recursion' step */
747 if (pos == nentries) {
748 /* put back values of the time when this chain was called */
749 e = cl_s[chain_nr].cs.e;
750 if (cl_s[chain_nr].from != -1)
751 nentries =
752 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
753 else
754 nentries = chain->nentries;
755 pos = cl_s[chain_nr].cs.n;
756 /* make sure we won't see a loop that isn't one */
757 cl_s[chain_nr].cs.n = 0;
758 chain_nr = cl_s[chain_nr].from;
759 if (pos == nentries)
760 continue;
761 }
762 t = (struct ebt_entry_target *)
763 (((char *)e) + e->target_offset);
764 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
765 goto letscontinue;
766 if (e->target_offset + sizeof(struct ebt_standard_target) >
767 e->next_offset) {
768 BUGPRINT("Standard target size too big\n");
769 return -1;
770 }
771 verdict = ((struct ebt_standard_target *)t)->verdict;
772 if (verdict >= 0) { /* jump to another chain */
773 struct ebt_entries *hlp2 =
774 (struct ebt_entries *)(base + verdict);
775 for (i = 0; i < udc_cnt; i++)
776 if (hlp2 == cl_s[i].cs.chaininfo)
777 break;
778 /* bad destination or loop */
779 if (i == udc_cnt) {
780 BUGPRINT("bad destination\n");
781 return -1;
782 }
783 if (cl_s[i].cs.n) {
784 BUGPRINT("loop\n");
785 return -1;
786 }
Al Viro98a08242006-11-30 19:24:49 -0800787 if (cl_s[i].hookmask & (1 << hooknr))
788 goto letscontinue;
789 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 cl_s[i].cs.n = pos + 1;
791 pos = 0;
792 cl_s[i].cs.e = ((void *)e + e->next_offset);
793 e = (struct ebt_entry *)(hlp2->data);
794 nentries = hlp2->nentries;
795 cl_s[i].from = chain_nr;
796 chain_nr = i;
797 /* this udc is accessible from the base chain for hooknr */
798 cl_s[i].hookmask |= (1 << hooknr);
799 continue;
800 }
801letscontinue:
802 e = (void *)e + e->next_offset;
803 pos++;
804 }
805 return 0;
806}
807
808/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800809static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
811 unsigned int i, j, k, udc_cnt;
812 int ret;
813 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
814
815 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800816 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 i++;
818 if (i == NF_BR_NUMHOOKS) {
819 BUGPRINT("No valid hooks specified\n");
820 return -EINVAL;
821 }
Al Viro1f072c92006-11-30 19:26:53 -0800822 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 BUGPRINT("Chains don't start at beginning\n");
824 return -EINVAL;
825 }
826 /* make sure chains are ordered after each other in same order
827 as their corresponding hooks */
828 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800829 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800831 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 BUGPRINT("Hook order must be followed\n");
833 return -EINVAL;
834 }
835 i = j;
836 }
837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 /* do some early checkings and initialize some things */
839 i = 0; /* holds the expected nr. of entries for the chain */
840 j = 0; /* holds the up to now counted entries for the chain */
841 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900842 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
844 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800845 ebt_check_entry_size_and_hooks, newinfo,
846 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 if (ret != 0)
849 return ret;
850
851 if (i != j) {
852 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900853 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return -EINVAL;
855 }
856 if (k != newinfo->nentries) {
857 BUGPRINT("Total nentries is wrong\n");
858 return -EINVAL;
859 }
860
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 /* get the location of the udc, put them in an array
862 while we're at it, allocate the chainstack */
863 if (udc_cnt) {
864 /* this will get free'd in do_replace()/ebt_register_table()
865 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700866 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800867 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (!newinfo->chainstack)
869 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700870 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700872 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (!newinfo->chainstack[i]) {
874 while (i)
875 vfree(newinfo->chainstack[--i]);
876 vfree(newinfo->chainstack);
877 newinfo->chainstack = NULL;
878 return -ENOMEM;
879 }
880 }
881
Jayachandran C18bc89a2006-04-20 00:14:49 -0700882 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (!cl_s)
884 return -ENOMEM;
885 i = 0; /* the i'th udc */
886 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800887 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 /* sanity check */
889 if (i != udc_cnt) {
890 BUGPRINT("i != udc_cnt\n");
891 vfree(cl_s);
892 return -EFAULT;
893 }
894 }
895
896 /* Check for loops */
897 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800898 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 if (check_chainloops(newinfo->hook_entry[i],
900 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700901 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return -EINVAL;
903 }
904
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200905 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 - the nr of entries in each chain is right
907 - the size of the allocated space is right
908 - all valid hooks have a corresponding chain
909 - there are no loops
910 - wrong data can still be on the level of a single entry
911 - could be there are jumps to places that are not the
912 beginning of a chain. This can only occur in chains that
913 are not accessible from any base chains, so we don't care. */
914
915 /* used to know what we need to clean up if something goes wrong */
916 i = 0;
917 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800918 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 if (ret != 0) {
920 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
921 ebt_cleanup_entry, &i);
922 }
James Lamanna68d31872005-06-22 22:12:57 -0700923 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return ret;
925}
926
927/* called under write_lock */
928static void get_counters(struct ebt_counter *oldcounters,
929 struct ebt_counter *counters, unsigned int nentries)
930{
931 int i, cpu;
932 struct ebt_counter *counter_base;
933
934 /* counters of cpu 0 */
935 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700936 sizeof(struct ebt_counter) * nentries);
937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700939 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700940 if (cpu == 0)
941 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
943 for (i = 0; i < nentries; i++) {
944 counters[i].pcnt += counter_base[i].pcnt;
945 counters[i].bcnt += counter_base[i].bcnt;
946 }
947 }
948}
949
950/* replace the table */
951static int do_replace(void __user *user, unsigned int len)
952{
953 int ret, i, countersize;
954 struct ebt_table_info *newinfo;
955 struct ebt_replace tmp;
956 struct ebt_table *t;
957 struct ebt_counter *counterstmp = NULL;
958 /* used to be able to unlock earlier */
959 struct ebt_table_info *table;
960
961 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
962 return -EFAULT;
963
964 if (len != sizeof(tmp) + tmp.entries_size) {
965 BUGPRINT("Wrong len argument\n");
966 return -EINVAL;
967 }
968
969 if (tmp.entries_size == 0) {
970 BUGPRINT("Entries_size never zero\n");
971 return -EINVAL;
972 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800973 /* overflow check */
974 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
975 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
976 return -ENOMEM;
977 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
978 return -ENOMEM;
979
Christoph Lameter53b8a312007-02-20 13:57:51 -0800980 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700981 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (!newinfo)
983 return -ENOMEM;
984
985 if (countersize)
986 memset(newinfo->counters, 0, countersize);
987
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800988 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (!newinfo->entries) {
990 ret = -ENOMEM;
991 goto free_newinfo;
992 }
993 if (copy_from_user(
994 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
995 BUGPRINT("Couldn't copy entries from userspace\n");
996 ret = -EFAULT;
997 goto free_entries;
998 }
999
1000 /* the user wants counters back
1001 the check on the size is done later, when we have the lock */
1002 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001003 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (!counterstmp) {
1005 ret = -ENOMEM;
1006 goto free_entries;
1007 }
1008 }
1009 else
1010 counterstmp = NULL;
1011
1012 /* this can get initialized by translate_table() */
1013 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001014 ret = ebt_verify_pointers(&tmp, newinfo);
1015 if (ret != 0)
1016 goto free_counterstmp;
1017
1018 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 if (ret != 0)
1021 goto free_counterstmp;
1022
1023 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1024 if (!t) {
1025 ret = -ENOENT;
1026 goto free_iterate;
1027 }
1028
1029 /* the table doesn't like it */
1030 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1031 goto free_unlock;
1032
1033 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1034 BUGPRINT("Wrong nr. of counters requested\n");
1035 ret = -EINVAL;
1036 goto free_unlock;
1037 }
1038
1039 /* we have the mutex lock, so no danger in reading this pointer */
1040 table = t->private;
1041 /* make sure the table can only be rmmod'ed if it contains no rules */
1042 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1043 ret = -ENOENT;
1044 goto free_unlock;
1045 } else if (table->nentries && !newinfo->nentries)
1046 module_put(t->me);
1047 /* we need an atomic snapshot of the counters */
1048 write_lock_bh(&t->lock);
1049 if (tmp.num_counters)
1050 get_counters(t->private->counters, counterstmp,
1051 t->private->nentries);
1052
1053 t->private = newinfo;
1054 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001055 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* so, a user can change the chains while having messed up her counter
1057 allocation. Only reason why this is done is because this way the lock
1058 is held only once, while this doesn't bring the kernel into a
1059 dangerous state. */
1060 if (tmp.num_counters &&
1061 copy_to_user(tmp.counters, counterstmp,
1062 tmp.num_counters * sizeof(struct ebt_counter))) {
1063 BUGPRINT("Couldn't copy counters to userspace\n");
1064 ret = -EFAULT;
1065 }
1066 else
1067 ret = 0;
1068
1069 /* decrease module count and free resources */
1070 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1071 ebt_cleanup_entry, NULL);
1072
1073 vfree(table->entries);
1074 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001075 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 vfree(table->chainstack[i]);
1077 vfree(table->chainstack);
1078 }
1079 vfree(table);
1080
James Lamanna68d31872005-06-22 22:12:57 -07001081 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return ret;
1083
1084free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001085 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086free_iterate:
1087 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1088 ebt_cleanup_entry, NULL);
1089free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001090 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 /* can be initialized in translate_table() */
1092 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001093 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 vfree(newinfo->chainstack[i]);
1095 vfree(newinfo->chainstack);
1096 }
1097free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001098 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001100 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return ret;
1102}
1103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104int ebt_register_table(struct ebt_table *table)
1105{
1106 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001107 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001108 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001110 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Al Virodf07a812006-11-30 19:28:25 -08001112 if (!table || !(repl = table->table) || !repl->entries ||
1113 repl->entries_size == 0 ||
1114 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1116 return -EINVAL;
1117 }
1118
Christoph Lameter53b8a312007-02-20 13:57:51 -08001119 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001120 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 ret = -ENOMEM;
1122 if (!newinfo)
1123 return -ENOMEM;
1124
Al Virodf07a812006-11-30 19:28:25 -08001125 p = vmalloc(repl->entries_size);
1126 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 goto free_newinfo;
1128
Al Virodf07a812006-11-30 19:28:25 -08001129 memcpy(p, repl->entries, repl->entries_size);
1130 newinfo->entries = p;
1131
1132 newinfo->entries_size = repl->entries_size;
1133 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 if (countersize)
1136 memset(newinfo->counters, 0, countersize);
1137
1138 /* fill in newinfo and parse the entries */
1139 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001140 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1141 if ((repl->valid_hooks & (1 << i)) == 0)
1142 newinfo->hook_entry[i] = NULL;
1143 else
1144 newinfo->hook_entry[i] = p +
1145 ((char *)repl->hook_entry[i] - repl->entries);
1146 }
1147 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 if (ret != 0) {
1149 BUGPRINT("Translate_table failed\n");
1150 goto free_chainstack;
1151 }
1152
1153 if (table->check && table->check(newinfo, table->valid_hooks)) {
1154 BUGPRINT("The table doesn't like its own initial data, lol\n");
1155 return -EINVAL;
1156 }
1157
1158 table->private = newinfo;
1159 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001160 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (ret != 0)
1162 goto free_chainstack;
1163
Patrick McHardydf0933d2006-09-20 11:57:53 -07001164 list_for_each_entry(t, &ebt_tables, list) {
1165 if (strcmp(t->name, table->name) == 0) {
1166 ret = -EEXIST;
1167 BUGPRINT("Table name already exists\n");
1168 goto free_unlock;
1169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171
1172 /* Hold a reference count if the chains aren't empty */
1173 if (newinfo->nentries && !try_module_get(table->me)) {
1174 ret = -ENOENT;
1175 goto free_unlock;
1176 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001177 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001178 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return 0;
1180free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001181 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182free_chainstack:
1183 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001184 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 vfree(newinfo->chainstack[i]);
1186 vfree(newinfo->chainstack);
1187 }
1188 vfree(newinfo->entries);
1189free_newinfo:
1190 vfree(newinfo);
1191 return ret;
1192}
1193
1194void ebt_unregister_table(struct ebt_table *table)
1195{
1196 int i;
1197
1198 if (!table) {
1199 BUGPRINT("Request to unregister NULL table!!!\n");
1200 return;
1201 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001202 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001203 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001204 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001205 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001207 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 vfree(table->private->chainstack[i]);
1209 vfree(table->private->chainstack);
1210 }
1211 vfree(table->private);
1212}
1213
1214/* userspace just supplied us with counters */
1215static int update_counters(void __user *user, unsigned int len)
1216{
1217 int i, ret;
1218 struct ebt_counter *tmp;
1219 struct ebt_replace hlp;
1220 struct ebt_table *t;
1221
1222 if (copy_from_user(&hlp, user, sizeof(hlp)))
1223 return -EFAULT;
1224
1225 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1226 return -EINVAL;
1227 if (hlp.num_counters == 0)
1228 return -EINVAL;
1229
Jayachandran C18bc89a2006-04-20 00:14:49 -07001230 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 MEMPRINT("Update_counters && nomemory\n");
1232 return -ENOMEM;
1233 }
1234
1235 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1236 if (!t)
1237 goto free_tmp;
1238
1239 if (hlp.num_counters != t->private->nentries) {
1240 BUGPRINT("Wrong nr of counters\n");
1241 ret = -EINVAL;
1242 goto unlock_mutex;
1243 }
1244
1245 if ( copy_from_user(tmp, hlp.counters,
1246 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1247 BUGPRINT("Updata_counters && !cfu\n");
1248 ret = -EFAULT;
1249 goto unlock_mutex;
1250 }
1251
1252 /* we want an atomic add of the counters */
1253 write_lock_bh(&t->lock);
1254
1255 /* we add to the counters of the first cpu */
1256 for (i = 0; i < hlp.num_counters; i++) {
1257 t->private->counters[i].pcnt += tmp[i].pcnt;
1258 t->private->counters[i].bcnt += tmp[i].bcnt;
1259 }
1260
1261 write_unlock_bh(&t->lock);
1262 ret = 0;
1263unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001264 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265free_tmp:
1266 vfree(tmp);
1267 return ret;
1268}
1269
1270static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001271 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272{
Al Viro1e419cd2006-11-30 19:28:48 -08001273 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1275 return -EFAULT;
1276 return 0;
1277}
1278
1279static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001280 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281{
Al Viro1e419cd2006-11-30 19:28:48 -08001282 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1284 return -EFAULT;
1285 return 0;
1286}
1287
Al Viro1e419cd2006-11-30 19:28:48 -08001288static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
1290 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001291 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 struct ebt_entry_target *t;
1293
Al Viro40642f92006-11-30 19:24:12 -08001294 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 return 0;
1296
Al Viro1e419cd2006-11-30 19:28:48 -08001297 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1301 if (ret != 0)
1302 return ret;
1303 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1304 if (ret != 0)
1305 return ret;
1306 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1307 return -EFAULT;
1308 return 0;
1309}
1310
Ingo Molnar57b47a52006-03-20 22:35:41 -08001311/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1313 int *len, int cmd)
1314{
1315 struct ebt_replace tmp;
1316 struct ebt_counter *counterstmp, *oldcounters;
1317 unsigned int entries_size, nentries;
1318 char *entries;
1319
1320 if (cmd == EBT_SO_GET_ENTRIES) {
1321 entries_size = t->private->entries_size;
1322 nentries = t->private->nentries;
1323 entries = t->private->entries;
1324 oldcounters = t->private->counters;
1325 } else {
1326 entries_size = t->table->entries_size;
1327 nentries = t->table->nentries;
1328 entries = t->table->entries;
1329 oldcounters = t->table->counters;
1330 }
1331
1332 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1333 BUGPRINT("Cfu didn't work\n");
1334 return -EFAULT;
1335 }
1336
1337 if (*len != sizeof(struct ebt_replace) + entries_size +
1338 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1339 BUGPRINT("Wrong size\n");
1340 return -EINVAL;
1341 }
1342
1343 if (tmp.nentries != nentries) {
1344 BUGPRINT("Nentries wrong\n");
1345 return -EINVAL;
1346 }
1347
1348 if (tmp.entries_size != entries_size) {
1349 BUGPRINT("Wrong size\n");
1350 return -EINVAL;
1351 }
1352
1353 /* userspace might not need the counters */
1354 if (tmp.num_counters) {
1355 if (tmp.num_counters != nentries) {
1356 BUGPRINT("Num_counters wrong\n");
1357 return -EINVAL;
1358 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001359 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (!counterstmp) {
1361 MEMPRINT("Couldn't copy counters, out of memory\n");
1362 return -ENOMEM;
1363 }
1364 write_lock_bh(&t->lock);
1365 get_counters(oldcounters, counterstmp, nentries);
1366 write_unlock_bh(&t->lock);
1367
1368 if (copy_to_user(tmp.counters, counterstmp,
1369 nentries * sizeof(struct ebt_counter))) {
1370 BUGPRINT("Couldn't copy counters to userspace\n");
1371 vfree(counterstmp);
1372 return -EFAULT;
1373 }
1374 vfree(counterstmp);
1375 }
1376
1377 if (copy_to_user(tmp.entries, entries, entries_size)) {
1378 BUGPRINT("Couldn't copy entries to userspace\n");
1379 return -EFAULT;
1380 }
1381 /* set the match/watcher/target names right */
1382 return EBT_ENTRY_ITERATE(entries, entries_size,
1383 ebt_make_names, entries, tmp.entries);
1384}
1385
1386static int do_ebt_set_ctl(struct sock *sk,
1387 int cmd, void __user *user, unsigned int len)
1388{
1389 int ret;
1390
1391 switch(cmd) {
1392 case EBT_SO_SET_ENTRIES:
1393 ret = do_replace(user, len);
1394 break;
1395 case EBT_SO_SET_COUNTERS:
1396 ret = update_counters(user, len);
1397 break;
1398 default:
1399 ret = -EINVAL;
1400 }
1401 return ret;
1402}
1403
1404static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1405{
1406 int ret;
1407 struct ebt_replace tmp;
1408 struct ebt_table *t;
1409
1410 if (copy_from_user(&tmp, user, sizeof(tmp)))
1411 return -EFAULT;
1412
1413 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1414 if (!t)
1415 return ret;
1416
1417 switch(cmd) {
1418 case EBT_SO_GET_INFO:
1419 case EBT_SO_GET_INIT_INFO:
1420 if (*len != sizeof(struct ebt_replace)){
1421 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001422 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 break;
1424 }
1425 if (cmd == EBT_SO_GET_INFO) {
1426 tmp.nentries = t->private->nentries;
1427 tmp.entries_size = t->private->entries_size;
1428 tmp.valid_hooks = t->valid_hooks;
1429 } else {
1430 tmp.nentries = t->table->nentries;
1431 tmp.entries_size = t->table->entries_size;
1432 tmp.valid_hooks = t->table->valid_hooks;
1433 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001434 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if (copy_to_user(user, &tmp, *len) != 0){
1436 BUGPRINT("c2u Didn't work\n");
1437 ret = -EFAULT;
1438 break;
1439 }
1440 ret = 0;
1441 break;
1442
1443 case EBT_SO_GET_ENTRIES:
1444 case EBT_SO_GET_INIT_ENTRIES:
1445 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001446 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 break;
1448
1449 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001450 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 ret = -EINVAL;
1452 }
1453
1454 return ret;
1455}
1456
1457static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001458{
1459 .pf = PF_INET,
1460 .set_optmin = EBT_BASE_CTL,
1461 .set_optmax = EBT_SO_SET_MAX + 1,
1462 .set = do_ebt_set_ctl,
1463 .get_optmin = EBT_BASE_CTL,
1464 .get_optmax = EBT_SO_GET_MAX + 1,
1465 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001466 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467};
1468
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001469static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
1471 int ret;
1472
Jan Engelhardt043ef462008-10-08 11:35:15 +02001473 ret = xt_register_target(&ebt_standard_target);
1474 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001476 ret = nf_register_sockopt(&ebt_sockopts);
1477 if (ret < 0) {
1478 xt_unregister_target(&ebt_standard_target);
1479 return ret;
1480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
Patrick McHardya887c1c2007-07-14 20:46:15 -07001482 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 return 0;
1484}
1485
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001486static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
1488 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001489 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001490 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491}
1492
1493EXPORT_SYMBOL(ebt_register_table);
1494EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001496module_init(ebtables_init);
1497module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498MODULE_LICENSE("GPL");