blob: 0fa208e86405ceab189042dd36e03fd3e6b893fd [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 Engelhardt916a9172008-10-08 11:35:20 +0200163 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200164 mtpar.in = tgpar.in = in;
165 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200166 mtpar.hotdrop = &hotdrop;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200167 tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169 read_lock_bh(&table->lock);
170 private = table->private;
171 cb_base = COUNTER_BASE(private->counters, private->nentries,
172 smp_processor_id());
173 if (private->chainstack)
174 cs = private->chainstack[smp_processor_id()];
175 else
176 cs = NULL;
177 chaininfo = private->hook_entry[hook];
178 nentries = private->hook_entry[hook]->nentries;
179 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
180 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
181 /* base for chain jumps */
182 base = private->entries;
183 i = 0;
184 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700185 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 goto letscontinue;
187
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200188 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200190 if (hotdrop) {
191 read_unlock_bh(&table->lock);
192 return NF_DROP;
193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 /* increase counter */
196 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700197 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 /* these should only watch: not modify, nor tell us
200 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200201 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 t = (struct ebt_entry_target *)
204 (((char *)point) + point->target_offset);
205 /* standard target */
206 if (!t->u.target->target)
207 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200208 else {
209 tgpar.target = t->u.target;
210 tgpar.targinfo = t->data;
211 verdict = t->u.target->target(skb, &tgpar);
212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if (verdict == EBT_ACCEPT) {
214 read_unlock_bh(&table->lock);
215 return NF_ACCEPT;
216 }
217 if (verdict == EBT_DROP) {
218 read_unlock_bh(&table->lock);
219 return NF_DROP;
220 }
221 if (verdict == EBT_RETURN) {
222letsreturn:
223#ifdef CONFIG_NETFILTER_DEBUG
224 if (sp == 0) {
225 BUGPRINT("RETURN on base chain");
226 /* act like this is EBT_CONTINUE */
227 goto letscontinue;
228 }
229#endif
230 sp--;
231 /* put all the local variables right */
232 i = cs[sp].n;
233 chaininfo = cs[sp].chaininfo;
234 nentries = chaininfo->nentries;
235 point = cs[sp].e;
236 counter_base = cb_base +
237 chaininfo->counter_offset;
238 continue;
239 }
240 if (verdict == EBT_CONTINUE)
241 goto letscontinue;
242#ifdef CONFIG_NETFILTER_DEBUG
243 if (verdict < 0) {
244 BUGPRINT("bogus standard verdict\n");
245 read_unlock_bh(&table->lock);
246 return NF_DROP;
247 }
248#endif
249 /* jump to a udc */
250 cs[sp].n = i + 1;
251 cs[sp].chaininfo = chaininfo;
252 cs[sp].e = (struct ebt_entry *)
253 (((char *)point) + point->next_offset);
254 i = 0;
255 chaininfo = (struct ebt_entries *) (base + verdict);
256#ifdef CONFIG_NETFILTER_DEBUG
257 if (chaininfo->distinguisher) {
258 BUGPRINT("jump to non-chain\n");
259 read_unlock_bh(&table->lock);
260 return NF_DROP;
261 }
262#endif
263 nentries = chaininfo->nentries;
264 point = (struct ebt_entry *)chaininfo->data;
265 counter_base = cb_base + chaininfo->counter_offset;
266 sp++;
267 continue;
268letscontinue:
269 point = (struct ebt_entry *)
270 (((char *)point) + point->next_offset);
271 i++;
272 }
273
274 /* I actually like this :) */
275 if (chaininfo->policy == EBT_RETURN)
276 goto letsreturn;
277 if (chaininfo->policy == EBT_ACCEPT) {
278 read_unlock_bh(&table->lock);
279 return NF_ACCEPT;
280 }
281 read_unlock_bh(&table->lock);
282 return NF_DROP;
283}
284
285/* If it succeeds, returns element and locks mutex */
286static inline void *
287find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800288 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700290 struct {
291 struct list_head list;
292 char name[EBT_FUNCTION_MAXNAMELEN];
293 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Ingo Molnar57b47a52006-03-20 22:35:41 -0800295 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if (*error != 0)
297 return NULL;
298
Patrick McHardydf0933d2006-09-20 11:57:53 -0700299 list_for_each_entry(e, head, list) {
300 if (strcmp(e->name, name) == 0)
301 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700303 *error = -ENOENT;
304 mutex_unlock(mutex);
305 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308static void *
309find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800310 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700312 return try_then_request_module(
313 find_inlist_lock_noload(head, name, error, mutex),
314 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800318find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
321}
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200324ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
325 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200327 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200328 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800329 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 int ret;
331
Al Viro14197d52006-11-30 19:25:21 -0800332 if (left < sizeof(struct ebt_entry_match) ||
333 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200335
336 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
337 m->u.name, 0), "ebt_%s", m->u.name);
338 if (IS_ERR(match))
339 return PTR_ERR(match);
340 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200342 m->u.match = match;
343
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200344 par->match = match;
345 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200346 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200347 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200348 if (ret < 0) {
349 module_put(match->me);
350 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 (*cnt)++;
354 return 0;
355}
356
357static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200358ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
359 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200361 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200362 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800363 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 int ret;
365
Al Viro14197d52006-11-30 19:25:21 -0800366 if (left < sizeof(struct ebt_entry_watcher) ||
367 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200369
370 watcher = try_then_request_module(
371 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
372 "ebt_%s", w->u.name);
373 if (IS_ERR(watcher))
374 return PTR_ERR(watcher);
375 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200377 w->u.watcher = watcher;
378
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200379 par->target = watcher;
380 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200381 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200382 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200383 if (ret < 0) {
384 module_put(watcher->me);
385 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (*cnt)++;
389 return 0;
390}
391
Al Viro70fe9af2006-11-30 19:26:14 -0800392static int ebt_verify_pointers(struct ebt_replace *repl,
393 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Al Viro70fe9af2006-11-30 19:26:14 -0800395 unsigned int limit = repl->entries_size;
396 unsigned int valid_hooks = repl->valid_hooks;
397 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 int i;
399
Al Viroe4fd77d2006-11-30 19:26:35 -0800400 for (i = 0; i < NF_BR_NUMHOOKS; i++)
401 newinfo->hook_entry[i] = NULL;
402
403 newinfo->entries_size = repl->entries_size;
404 newinfo->nentries = repl->nentries;
405
Al Viro70fe9af2006-11-30 19:26:14 -0800406 while (offset < limit) {
407 size_t left = limit - offset;
408 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800409
Al Viro70fe9af2006-11-30 19:26:14 -0800410 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 break;
Al Viro22b440b2006-11-30 19:25:51 -0800412
Al Viro70fe9af2006-11-30 19:26:14 -0800413 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
414 if ((valid_hooks & (1 << i)) == 0)
415 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800416 if ((char __user *)repl->hook_entry[i] ==
417 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800418 break;
419 }
420
421 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
422 if (e->bitmask != 0) {
423 /* we make userspace set this right,
424 so there is no misunderstanding */
425 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
426 "in distinguisher\n");
427 return -EINVAL;
428 }
429 if (i != NF_BR_NUMHOOKS)
430 newinfo->hook_entry[i] = (struct ebt_entries *)e;
431 if (left < sizeof(struct ebt_entries))
432 break;
433 offset += sizeof(struct ebt_entries);
434 } else {
435 if (left < sizeof(struct ebt_entry))
436 break;
437 if (left < e->next_offset)
438 break;
439 offset += e->next_offset;
440 }
441 }
442 if (offset != limit) {
443 BUGPRINT("entries_size too small\n");
444 return -EINVAL;
445 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800446
447 /* check if all valid hooks have a chain */
448 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
449 if (!newinfo->hook_entry[i] &&
450 (valid_hooks & (1 << i))) {
451 BUGPRINT("Valid hook without chain\n");
452 return -EINVAL;
453 }
454 }
Al Viro70fe9af2006-11-30 19:26:14 -0800455 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800456}
457
458/*
459 * this one is very careful, as it is the first function
460 * to parse the userspace data
461 */
462static inline int
463ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800464 struct ebt_table_info *newinfo,
465 unsigned int *n, unsigned int *cnt,
466 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800467{
Al Viro22b440b2006-11-30 19:25:51 -0800468 int i;
469
470 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800471 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800472 break;
473 }
474 /* beginning of a new chain
475 if i == NF_BR_NUMHOOKS it must be a user defined chain */
476 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 /* this checks if the previous chain has as many entries
478 as it said it has */
479 if (*n != *cnt) {
480 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900481 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 return -EINVAL;
483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
485 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
486 /* only RETURN from udc */
487 if (i != NF_BR_NUMHOOKS ||
488 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
489 BUGPRINT("bad policy\n");
490 return -EINVAL;
491 }
492 }
493 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
494 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
496 BUGPRINT("counter_offset != totalcnt");
497 return -EINVAL;
498 }
499 *n = ((struct ebt_entries *)e)->nentries;
500 *cnt = 0;
501 return 0;
502 }
503 /* a plain old entry, heh */
504 if (sizeof(struct ebt_entry) > e->watchers_offset ||
505 e->watchers_offset > e->target_offset ||
506 e->target_offset >= e->next_offset) {
507 BUGPRINT("entry offsets not in right order\n");
508 return -EINVAL;
509 }
510 /* this is not checked anywhere else */
511 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
512 BUGPRINT("target size too small\n");
513 return -EINVAL;
514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 (*cnt)++;
516 (*totalcnt)++;
517 return 0;
518}
519
520struct ebt_cl_stack
521{
522 struct ebt_chainstack cs;
523 int from;
524 unsigned int hookmask;
525};
526
527/*
528 * we need these positions to check that the jumps to a different part of the
529 * entries is a jump to the beginning of a new chain.
530 */
531static inline int
532ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800533 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534{
535 int i;
536
537 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800538 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return 0;
540 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
542 break;
543 }
544 /* only care about udc */
545 if (i != NF_BR_NUMHOOKS)
546 return 0;
547
548 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
549 /* these initialisations are depended on later in check_chainloops() */
550 udc[*n].cs.n = 0;
551 udc[*n].hookmask = 0;
552
553 (*n)++;
554 return 0;
555}
556
557static inline int
558ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
559{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200560 struct xt_mtdtor_param par;
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (i && (*i)-- == 0)
563 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200565 par.match = m->u.match;
566 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200567 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200568 if (par.match->destroy != NULL)
569 par.match->destroy(&par);
570 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return 0;
572}
573
574static inline int
575ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
576{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200577 struct xt_tgdtor_param par;
578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 if (i && (*i)-- == 0)
580 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Jan Engelhardta2df1642008-10-08 11:35:19 +0200582 par.target = w->u.watcher;
583 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200584 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200585 if (par.target->destroy != NULL)
586 par.target->destroy(&par);
587 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 return 0;
589}
590
591static inline int
592ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
593{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200594 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 struct ebt_entry_target *t;
596
Al Viro40642f92006-11-30 19:24:12 -0800597 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return 0;
599 /* we're done */
600 if (cnt && (*cnt)-- == 0)
601 return 1;
602 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
603 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
604 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Jan Engelhardta2df1642008-10-08 11:35:19 +0200606 par.target = t->u.target;
607 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200608 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200609 if (par.target->destroy != NULL)
610 par.target->destroy(&par);
611 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return 0;
613}
614
615static inline int
616ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800617 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
619{
620 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200621 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800623 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200625 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200626 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800629 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return 0;
631
632 if (e->bitmask & ~EBT_F_MASK) {
633 BUGPRINT("Unknown flag for bitmask\n");
634 return -EINVAL;
635 }
636 if (e->invflags & ~EBT_INV_MASK) {
637 BUGPRINT("Unknown flag for inv bitmask\n");
638 return -EINVAL;
639 }
640 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
641 BUGPRINT("NOPROTO & 802_3 not allowed\n");
642 return -EINVAL;
643 }
644 /* what hook do we belong to? */
645 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800646 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 continue;
648 if ((char *)newinfo->hook_entry[i] < (char *)e)
649 hook = i;
650 else
651 break;
652 }
653 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
654 a base chain */
655 if (i < NF_BR_NUMHOOKS)
656 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
657 else {
658 for (i = 0; i < udc_cnt; i++)
659 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
660 break;
661 if (i == 0)
662 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
663 else
664 hookmask = cl_s[i - 1].hookmask;
665 }
666 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200667
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200668 mtpar.table = tgpar.table = name;
669 mtpar.entryinfo = tgpar.entryinfo = e;
670 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200671 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200672 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (ret != 0)
674 goto cleanup_matches;
675 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200676 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (ret != 0)
678 goto cleanup_watchers;
679 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800680 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Jan Engelhardt043ef462008-10-08 11:35:15 +0200682 target = try_then_request_module(
683 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
684 "ebt_%s", t->u.name);
685 if (IS_ERR(target)) {
686 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200687 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200688 } else if (target == NULL) {
689 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200690 goto cleanup_watchers;
691 }
692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 t->u.target = target;
694 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800695 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 BUGPRINT("Standard target size too big\n");
697 ret = -EFAULT;
698 goto cleanup_watchers;
699 }
700 if (((struct ebt_standard_target *)t)->verdict <
701 -NUM_STANDARD_TARGETS) {
702 BUGPRINT("Invalid standard target\n");
703 ret = -EFAULT;
704 goto cleanup_watchers;
705 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200706 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
707 module_put(t->u.target->me);
708 ret = -EFAULT;
709 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200710 }
711
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200712 tgpar.target = target;
713 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200714 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200715 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200716 if (ret < 0) {
717 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200718 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
720 (*cnt)++;
721 return 0;
722cleanup_watchers:
723 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
724cleanup_matches:
725 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
726 return ret;
727}
728
729/*
730 * checks for loops and sets the hook mask for udc
731 * the hook mask for udc tells us from which base chains the udc can be
732 * accessed. This mask is a parameter to the check() functions of the extensions
733 */
734static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
735 unsigned int udc_cnt, unsigned int hooknr, char *base)
736{
737 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
738 struct ebt_entry *e = (struct ebt_entry *)chain->data;
739 struct ebt_entry_target *t;
740
741 while (pos < nentries || chain_nr != -1) {
742 /* end of udc, go back one 'recursion' step */
743 if (pos == nentries) {
744 /* put back values of the time when this chain was called */
745 e = cl_s[chain_nr].cs.e;
746 if (cl_s[chain_nr].from != -1)
747 nentries =
748 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
749 else
750 nentries = chain->nentries;
751 pos = cl_s[chain_nr].cs.n;
752 /* make sure we won't see a loop that isn't one */
753 cl_s[chain_nr].cs.n = 0;
754 chain_nr = cl_s[chain_nr].from;
755 if (pos == nentries)
756 continue;
757 }
758 t = (struct ebt_entry_target *)
759 (((char *)e) + e->target_offset);
760 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
761 goto letscontinue;
762 if (e->target_offset + sizeof(struct ebt_standard_target) >
763 e->next_offset) {
764 BUGPRINT("Standard target size too big\n");
765 return -1;
766 }
767 verdict = ((struct ebt_standard_target *)t)->verdict;
768 if (verdict >= 0) { /* jump to another chain */
769 struct ebt_entries *hlp2 =
770 (struct ebt_entries *)(base + verdict);
771 for (i = 0; i < udc_cnt; i++)
772 if (hlp2 == cl_s[i].cs.chaininfo)
773 break;
774 /* bad destination or loop */
775 if (i == udc_cnt) {
776 BUGPRINT("bad destination\n");
777 return -1;
778 }
779 if (cl_s[i].cs.n) {
780 BUGPRINT("loop\n");
781 return -1;
782 }
Al Viro98a08242006-11-30 19:24:49 -0800783 if (cl_s[i].hookmask & (1 << hooknr))
784 goto letscontinue;
785 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 cl_s[i].cs.n = pos + 1;
787 pos = 0;
788 cl_s[i].cs.e = ((void *)e + e->next_offset);
789 e = (struct ebt_entry *)(hlp2->data);
790 nentries = hlp2->nentries;
791 cl_s[i].from = chain_nr;
792 chain_nr = i;
793 /* this udc is accessible from the base chain for hooknr */
794 cl_s[i].hookmask |= (1 << hooknr);
795 continue;
796 }
797letscontinue:
798 e = (void *)e + e->next_offset;
799 pos++;
800 }
801 return 0;
802}
803
804/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800805static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
807 unsigned int i, j, k, udc_cnt;
808 int ret;
809 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
810
811 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800812 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 i++;
814 if (i == NF_BR_NUMHOOKS) {
815 BUGPRINT("No valid hooks specified\n");
816 return -EINVAL;
817 }
Al Viro1f072c92006-11-30 19:26:53 -0800818 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 BUGPRINT("Chains don't start at beginning\n");
820 return -EINVAL;
821 }
822 /* make sure chains are ordered after each other in same order
823 as their corresponding hooks */
824 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800825 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800827 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 BUGPRINT("Hook order must be followed\n");
829 return -EINVAL;
830 }
831 i = j;
832 }
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 /* do some early checkings and initialize some things */
835 i = 0; /* holds the expected nr. of entries for the chain */
836 j = 0; /* holds the up to now counted entries for the chain */
837 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900838 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
840 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800841 ebt_check_entry_size_and_hooks, newinfo,
842 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 if (ret != 0)
845 return ret;
846
847 if (i != j) {
848 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900849 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return -EINVAL;
851 }
852 if (k != newinfo->nentries) {
853 BUGPRINT("Total nentries is wrong\n");
854 return -EINVAL;
855 }
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 /* get the location of the udc, put them in an array
858 while we're at it, allocate the chainstack */
859 if (udc_cnt) {
860 /* this will get free'd in do_replace()/ebt_register_table()
861 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700862 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800863 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 if (!newinfo->chainstack)
865 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700866 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700868 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (!newinfo->chainstack[i]) {
870 while (i)
871 vfree(newinfo->chainstack[--i]);
872 vfree(newinfo->chainstack);
873 newinfo->chainstack = NULL;
874 return -ENOMEM;
875 }
876 }
877
Jayachandran C18bc89a2006-04-20 00:14:49 -0700878 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (!cl_s)
880 return -ENOMEM;
881 i = 0; /* the i'th udc */
882 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800883 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* sanity check */
885 if (i != udc_cnt) {
886 BUGPRINT("i != udc_cnt\n");
887 vfree(cl_s);
888 return -EFAULT;
889 }
890 }
891
892 /* Check for loops */
893 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800894 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if (check_chainloops(newinfo->hook_entry[i],
896 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700897 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 return -EINVAL;
899 }
900
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200901 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 - the nr of entries in each chain is right
903 - the size of the allocated space is right
904 - all valid hooks have a corresponding chain
905 - there are no loops
906 - wrong data can still be on the level of a single entry
907 - could be there are jumps to places that are not the
908 beginning of a chain. This can only occur in chains that
909 are not accessible from any base chains, so we don't care. */
910
911 /* used to know what we need to clean up if something goes wrong */
912 i = 0;
913 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800914 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 if (ret != 0) {
916 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
917 ebt_cleanup_entry, &i);
918 }
James Lamanna68d31872005-06-22 22:12:57 -0700919 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 return ret;
921}
922
923/* called under write_lock */
924static void get_counters(struct ebt_counter *oldcounters,
925 struct ebt_counter *counters, unsigned int nentries)
926{
927 int i, cpu;
928 struct ebt_counter *counter_base;
929
930 /* counters of cpu 0 */
931 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700932 sizeof(struct ebt_counter) * nentries);
933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700935 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700936 if (cpu == 0)
937 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
939 for (i = 0; i < nentries; i++) {
940 counters[i].pcnt += counter_base[i].pcnt;
941 counters[i].bcnt += counter_base[i].bcnt;
942 }
943 }
944}
945
946/* replace the table */
947static int do_replace(void __user *user, unsigned int len)
948{
949 int ret, i, countersize;
950 struct ebt_table_info *newinfo;
951 struct ebt_replace tmp;
952 struct ebt_table *t;
953 struct ebt_counter *counterstmp = NULL;
954 /* used to be able to unlock earlier */
955 struct ebt_table_info *table;
956
957 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
958 return -EFAULT;
959
960 if (len != sizeof(tmp) + tmp.entries_size) {
961 BUGPRINT("Wrong len argument\n");
962 return -EINVAL;
963 }
964
965 if (tmp.entries_size == 0) {
966 BUGPRINT("Entries_size never zero\n");
967 return -EINVAL;
968 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800969 /* overflow check */
970 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
971 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
972 return -ENOMEM;
973 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
974 return -ENOMEM;
975
Christoph Lameter53b8a312007-02-20 13:57:51 -0800976 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700977 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (!newinfo)
979 return -ENOMEM;
980
981 if (countersize)
982 memset(newinfo->counters, 0, countersize);
983
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800984 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (!newinfo->entries) {
986 ret = -ENOMEM;
987 goto free_newinfo;
988 }
989 if (copy_from_user(
990 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
991 BUGPRINT("Couldn't copy entries from userspace\n");
992 ret = -EFAULT;
993 goto free_entries;
994 }
995
996 /* the user wants counters back
997 the check on the size is done later, when we have the lock */
998 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700999 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (!counterstmp) {
1001 ret = -ENOMEM;
1002 goto free_entries;
1003 }
1004 }
1005 else
1006 counterstmp = NULL;
1007
1008 /* this can get initialized by translate_table() */
1009 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001010 ret = ebt_verify_pointers(&tmp, newinfo);
1011 if (ret != 0)
1012 goto free_counterstmp;
1013
1014 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 if (ret != 0)
1017 goto free_counterstmp;
1018
1019 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1020 if (!t) {
1021 ret = -ENOENT;
1022 goto free_iterate;
1023 }
1024
1025 /* the table doesn't like it */
1026 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1027 goto free_unlock;
1028
1029 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1030 BUGPRINT("Wrong nr. of counters requested\n");
1031 ret = -EINVAL;
1032 goto free_unlock;
1033 }
1034
1035 /* we have the mutex lock, so no danger in reading this pointer */
1036 table = t->private;
1037 /* make sure the table can only be rmmod'ed if it contains no rules */
1038 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1039 ret = -ENOENT;
1040 goto free_unlock;
1041 } else if (table->nentries && !newinfo->nentries)
1042 module_put(t->me);
1043 /* we need an atomic snapshot of the counters */
1044 write_lock_bh(&t->lock);
1045 if (tmp.num_counters)
1046 get_counters(t->private->counters, counterstmp,
1047 t->private->nentries);
1048
1049 t->private = newinfo;
1050 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001051 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 /* so, a user can change the chains while having messed up her counter
1053 allocation. Only reason why this is done is because this way the lock
1054 is held only once, while this doesn't bring the kernel into a
1055 dangerous state. */
1056 if (tmp.num_counters &&
1057 copy_to_user(tmp.counters, counterstmp,
1058 tmp.num_counters * sizeof(struct ebt_counter))) {
1059 BUGPRINT("Couldn't copy counters to userspace\n");
1060 ret = -EFAULT;
1061 }
1062 else
1063 ret = 0;
1064
1065 /* decrease module count and free resources */
1066 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1067 ebt_cleanup_entry, NULL);
1068
1069 vfree(table->entries);
1070 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001071 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 vfree(table->chainstack[i]);
1073 vfree(table->chainstack);
1074 }
1075 vfree(table);
1076
James Lamanna68d31872005-06-22 22:12:57 -07001077 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return ret;
1079
1080free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001081 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082free_iterate:
1083 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1084 ebt_cleanup_entry, NULL);
1085free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001086 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 /* can be initialized in translate_table() */
1088 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001089 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 vfree(newinfo->chainstack[i]);
1091 vfree(newinfo->chainstack);
1092 }
1093free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001094 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001096 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return ret;
1098}
1099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100int ebt_register_table(struct ebt_table *table)
1101{
1102 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001103 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001104 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001106 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Al Virodf07a812006-11-30 19:28:25 -08001108 if (!table || !(repl = table->table) || !repl->entries ||
1109 repl->entries_size == 0 ||
1110 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1112 return -EINVAL;
1113 }
1114
Christoph Lameter53b8a312007-02-20 13:57:51 -08001115 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001116 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 ret = -ENOMEM;
1118 if (!newinfo)
1119 return -ENOMEM;
1120
Al Virodf07a812006-11-30 19:28:25 -08001121 p = vmalloc(repl->entries_size);
1122 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 goto free_newinfo;
1124
Al Virodf07a812006-11-30 19:28:25 -08001125 memcpy(p, repl->entries, repl->entries_size);
1126 newinfo->entries = p;
1127
1128 newinfo->entries_size = repl->entries_size;
1129 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 if (countersize)
1132 memset(newinfo->counters, 0, countersize);
1133
1134 /* fill in newinfo and parse the entries */
1135 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001136 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1137 if ((repl->valid_hooks & (1 << i)) == 0)
1138 newinfo->hook_entry[i] = NULL;
1139 else
1140 newinfo->hook_entry[i] = p +
1141 ((char *)repl->hook_entry[i] - repl->entries);
1142 }
1143 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 if (ret != 0) {
1145 BUGPRINT("Translate_table failed\n");
1146 goto free_chainstack;
1147 }
1148
1149 if (table->check && table->check(newinfo, table->valid_hooks)) {
1150 BUGPRINT("The table doesn't like its own initial data, lol\n");
1151 return -EINVAL;
1152 }
1153
1154 table->private = newinfo;
1155 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001156 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 if (ret != 0)
1158 goto free_chainstack;
1159
Patrick McHardydf0933d2006-09-20 11:57:53 -07001160 list_for_each_entry(t, &ebt_tables, list) {
1161 if (strcmp(t->name, table->name) == 0) {
1162 ret = -EEXIST;
1163 BUGPRINT("Table name already exists\n");
1164 goto free_unlock;
1165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167
1168 /* Hold a reference count if the chains aren't empty */
1169 if (newinfo->nentries && !try_module_get(table->me)) {
1170 ret = -ENOENT;
1171 goto free_unlock;
1172 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001173 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001174 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return 0;
1176free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001177 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178free_chainstack:
1179 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001180 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 vfree(newinfo->chainstack[i]);
1182 vfree(newinfo->chainstack);
1183 }
1184 vfree(newinfo->entries);
1185free_newinfo:
1186 vfree(newinfo);
1187 return ret;
1188}
1189
1190void ebt_unregister_table(struct ebt_table *table)
1191{
1192 int i;
1193
1194 if (!table) {
1195 BUGPRINT("Request to unregister NULL table!!!\n");
1196 return;
1197 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001198 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001199 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001200 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001201 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001203 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 vfree(table->private->chainstack[i]);
1205 vfree(table->private->chainstack);
1206 }
1207 vfree(table->private);
1208}
1209
1210/* userspace just supplied us with counters */
1211static int update_counters(void __user *user, unsigned int len)
1212{
1213 int i, ret;
1214 struct ebt_counter *tmp;
1215 struct ebt_replace hlp;
1216 struct ebt_table *t;
1217
1218 if (copy_from_user(&hlp, user, sizeof(hlp)))
1219 return -EFAULT;
1220
1221 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1222 return -EINVAL;
1223 if (hlp.num_counters == 0)
1224 return -EINVAL;
1225
Jayachandran C18bc89a2006-04-20 00:14:49 -07001226 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 MEMPRINT("Update_counters && nomemory\n");
1228 return -ENOMEM;
1229 }
1230
1231 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1232 if (!t)
1233 goto free_tmp;
1234
1235 if (hlp.num_counters != t->private->nentries) {
1236 BUGPRINT("Wrong nr of counters\n");
1237 ret = -EINVAL;
1238 goto unlock_mutex;
1239 }
1240
1241 if ( copy_from_user(tmp, hlp.counters,
1242 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1243 BUGPRINT("Updata_counters && !cfu\n");
1244 ret = -EFAULT;
1245 goto unlock_mutex;
1246 }
1247
1248 /* we want an atomic add of the counters */
1249 write_lock_bh(&t->lock);
1250
1251 /* we add to the counters of the first cpu */
1252 for (i = 0; i < hlp.num_counters; i++) {
1253 t->private->counters[i].pcnt += tmp[i].pcnt;
1254 t->private->counters[i].bcnt += tmp[i].bcnt;
1255 }
1256
1257 write_unlock_bh(&t->lock);
1258 ret = 0;
1259unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001260 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261free_tmp:
1262 vfree(tmp);
1263 return ret;
1264}
1265
1266static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001267 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268{
Al Viro1e419cd2006-11-30 19:28:48 -08001269 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1271 return -EFAULT;
1272 return 0;
1273}
1274
1275static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001276 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277{
Al Viro1e419cd2006-11-30 19:28:48 -08001278 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1280 return -EFAULT;
1281 return 0;
1282}
1283
Al Viro1e419cd2006-11-30 19:28:48 -08001284static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
1286 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001287 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 struct ebt_entry_target *t;
1289
Al Viro40642f92006-11-30 19:24:12 -08001290 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 return 0;
1292
Al Viro1e419cd2006-11-30 19:28:48 -08001293 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1297 if (ret != 0)
1298 return ret;
1299 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1300 if (ret != 0)
1301 return ret;
1302 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1303 return -EFAULT;
1304 return 0;
1305}
1306
Ingo Molnar57b47a52006-03-20 22:35:41 -08001307/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1309 int *len, int cmd)
1310{
1311 struct ebt_replace tmp;
1312 struct ebt_counter *counterstmp, *oldcounters;
1313 unsigned int entries_size, nentries;
1314 char *entries;
1315
1316 if (cmd == EBT_SO_GET_ENTRIES) {
1317 entries_size = t->private->entries_size;
1318 nentries = t->private->nentries;
1319 entries = t->private->entries;
1320 oldcounters = t->private->counters;
1321 } else {
1322 entries_size = t->table->entries_size;
1323 nentries = t->table->nentries;
1324 entries = t->table->entries;
1325 oldcounters = t->table->counters;
1326 }
1327
1328 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1329 BUGPRINT("Cfu didn't work\n");
1330 return -EFAULT;
1331 }
1332
1333 if (*len != sizeof(struct ebt_replace) + entries_size +
1334 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1335 BUGPRINT("Wrong size\n");
1336 return -EINVAL;
1337 }
1338
1339 if (tmp.nentries != nentries) {
1340 BUGPRINT("Nentries wrong\n");
1341 return -EINVAL;
1342 }
1343
1344 if (tmp.entries_size != entries_size) {
1345 BUGPRINT("Wrong size\n");
1346 return -EINVAL;
1347 }
1348
1349 /* userspace might not need the counters */
1350 if (tmp.num_counters) {
1351 if (tmp.num_counters != nentries) {
1352 BUGPRINT("Num_counters wrong\n");
1353 return -EINVAL;
1354 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001355 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (!counterstmp) {
1357 MEMPRINT("Couldn't copy counters, out of memory\n");
1358 return -ENOMEM;
1359 }
1360 write_lock_bh(&t->lock);
1361 get_counters(oldcounters, counterstmp, nentries);
1362 write_unlock_bh(&t->lock);
1363
1364 if (copy_to_user(tmp.counters, counterstmp,
1365 nentries * sizeof(struct ebt_counter))) {
1366 BUGPRINT("Couldn't copy counters to userspace\n");
1367 vfree(counterstmp);
1368 return -EFAULT;
1369 }
1370 vfree(counterstmp);
1371 }
1372
1373 if (copy_to_user(tmp.entries, entries, entries_size)) {
1374 BUGPRINT("Couldn't copy entries to userspace\n");
1375 return -EFAULT;
1376 }
1377 /* set the match/watcher/target names right */
1378 return EBT_ENTRY_ITERATE(entries, entries_size,
1379 ebt_make_names, entries, tmp.entries);
1380}
1381
1382static int do_ebt_set_ctl(struct sock *sk,
1383 int cmd, void __user *user, unsigned int len)
1384{
1385 int ret;
1386
1387 switch(cmd) {
1388 case EBT_SO_SET_ENTRIES:
1389 ret = do_replace(user, len);
1390 break;
1391 case EBT_SO_SET_COUNTERS:
1392 ret = update_counters(user, len);
1393 break;
1394 default:
1395 ret = -EINVAL;
1396 }
1397 return ret;
1398}
1399
1400static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1401{
1402 int ret;
1403 struct ebt_replace tmp;
1404 struct ebt_table *t;
1405
1406 if (copy_from_user(&tmp, user, sizeof(tmp)))
1407 return -EFAULT;
1408
1409 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1410 if (!t)
1411 return ret;
1412
1413 switch(cmd) {
1414 case EBT_SO_GET_INFO:
1415 case EBT_SO_GET_INIT_INFO:
1416 if (*len != sizeof(struct ebt_replace)){
1417 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001418 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 break;
1420 }
1421 if (cmd == EBT_SO_GET_INFO) {
1422 tmp.nentries = t->private->nentries;
1423 tmp.entries_size = t->private->entries_size;
1424 tmp.valid_hooks = t->valid_hooks;
1425 } else {
1426 tmp.nentries = t->table->nentries;
1427 tmp.entries_size = t->table->entries_size;
1428 tmp.valid_hooks = t->table->valid_hooks;
1429 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001430 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 if (copy_to_user(user, &tmp, *len) != 0){
1432 BUGPRINT("c2u Didn't work\n");
1433 ret = -EFAULT;
1434 break;
1435 }
1436 ret = 0;
1437 break;
1438
1439 case EBT_SO_GET_ENTRIES:
1440 case EBT_SO_GET_INIT_ENTRIES:
1441 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001442 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 break;
1444
1445 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001446 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 ret = -EINVAL;
1448 }
1449
1450 return ret;
1451}
1452
1453static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001454{
1455 .pf = PF_INET,
1456 .set_optmin = EBT_BASE_CTL,
1457 .set_optmax = EBT_SO_SET_MAX + 1,
1458 .set = do_ebt_set_ctl,
1459 .get_optmin = EBT_BASE_CTL,
1460 .get_optmax = EBT_SO_GET_MAX + 1,
1461 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001462 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463};
1464
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001465static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466{
1467 int ret;
1468
Jan Engelhardt043ef462008-10-08 11:35:15 +02001469 ret = xt_register_target(&ebt_standard_target);
1470 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001472 ret = nf_register_sockopt(&ebt_sockopts);
1473 if (ret < 0) {
1474 xt_unregister_target(&ebt_standard_target);
1475 return ret;
1476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Patrick McHardya887c1c2007-07-14 20:46:15 -07001478 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return 0;
1480}
1481
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001482static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001485 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001486 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487}
1488
1489EXPORT_SYMBOL(ebt_register_table);
1490EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001492module_init(ebtables_init);
1493module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494MODULE_LICENSE("GPL");