blob: c1a82b2826ebc0c7d87a9794bc52ab5a2c53ddb5 [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 -070058
Jan Engelhardt043ef462008-10-08 11:35:15 +020059static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020060 .name = "standard",
61 .revision = 0,
62 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020063 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020064};
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Jan Engelhardt7eb35582008-10-08 11:35:19 +020066static inline int
67ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
68 struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020070 par->target = w->u.watcher;
71 par->targinfo = w->data;
72 w->u.watcher->target(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 /* watchers don't give a verdict */
74 return 0;
75}
76
77static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020078 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020080 par->match = m->u.match;
81 par->matchinfo = m->data;
82 return m->u.match->match(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85static inline int ebt_dev_check(char *entry, const struct net_device *device)
86{
87 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080088 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 if (*entry == '\0')
91 return 0;
92 if (!device)
93 return 1;
94 /* 1 is the wildcard token */
95 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
96 i++;
97 return (devname[i] != entry[i] && entry[i] != 1);
98}
99
100#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
101/* process standard matches */
102static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
103 const struct net_device *in, const struct net_device *out)
104{
105 int verdict, i;
106
107 if (e->bitmask & EBT_802_3) {
108 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
109 return 1;
110 } else if (!(e->bitmask & EBT_NOPROTO) &&
111 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
112 return 1;
113
114 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
115 return 1;
116 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
117 return 1;
118 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
119 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
120 return 1;
121 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
122 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
123 return 1;
124
125 if (e->bitmask & EBT_SOURCEMAC) {
126 verdict = 0;
127 for (i = 0; i < 6; i++)
128 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
129 e->sourcemsk[i];
130 if (FWINV2(verdict != 0, EBT_ISOURCE) )
131 return 1;
132 }
133 if (e->bitmask & EBT_DESTMAC) {
134 verdict = 0;
135 for (i = 0; i < 6; i++)
136 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
137 e->destmsk[i];
138 if (FWINV2(verdict != 0, EBT_IDEST) )
139 return 1;
140 }
141 return 0;
142}
143
144/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700145unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 const struct net_device *in, const struct net_device *out,
147 struct ebt_table *table)
148{
149 int i, nentries;
150 struct ebt_entry *point;
151 struct ebt_counter *counter_base, *cb_base;
152 struct ebt_entry_target *t;
153 int verdict, sp = 0;
154 struct ebt_chainstack *cs;
155 struct ebt_entries *chaininfo;
156 char *base;
157 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200158 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200159 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200160 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200161
Jan Engelhardt916a9172008-10-08 11:35:20 +0200162 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307static void *
308find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800309 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700311 return try_then_request_module(
312 find_inlist_lock_noload(head, name, error, mutex),
313 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100317find_table_lock(struct net *net, const char *name, int *error,
318 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100320 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
321 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200325ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
326 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200328 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200329 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800330 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 int ret;
332
Al Viro14197d52006-11-30 19:25:21 -0800333 if (left < sizeof(struct ebt_entry_match) ||
334 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200336
337 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
338 m->u.name, 0), "ebt_%s", m->u.name);
339 if (IS_ERR(match))
340 return PTR_ERR(match);
341 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200343 m->u.match = match;
344
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200345 par->match = match;
346 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200347 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200348 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200349 if (ret < 0) {
350 module_put(match->me);
351 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 (*cnt)++;
355 return 0;
356}
357
358static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200359ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
360 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200362 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200363 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800364 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 int ret;
366
Al Viro14197d52006-11-30 19:25:21 -0800367 if (left < sizeof(struct ebt_entry_watcher) ||
368 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200370
371 watcher = try_then_request_module(
372 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
373 "ebt_%s", w->u.name);
374 if (IS_ERR(watcher))
375 return PTR_ERR(watcher);
376 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200378 w->u.watcher = watcher;
379
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200380 par->target = watcher;
381 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200382 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200383 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200384 if (ret < 0) {
385 module_put(watcher->me);
386 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 (*cnt)++;
390 return 0;
391}
392
Al Viro70fe9af2006-11-30 19:26:14 -0800393static int ebt_verify_pointers(struct ebt_replace *repl,
394 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
Al Viro70fe9af2006-11-30 19:26:14 -0800396 unsigned int limit = repl->entries_size;
397 unsigned int valid_hooks = repl->valid_hooks;
398 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 int i;
400
Al Viroe4fd77d2006-11-30 19:26:35 -0800401 for (i = 0; i < NF_BR_NUMHOOKS; i++)
402 newinfo->hook_entry[i] = NULL;
403
404 newinfo->entries_size = repl->entries_size;
405 newinfo->nentries = repl->nentries;
406
Al Viro70fe9af2006-11-30 19:26:14 -0800407 while (offset < limit) {
408 size_t left = limit - offset;
409 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800410
Al Viro70fe9af2006-11-30 19:26:14 -0800411 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 break;
Al Viro22b440b2006-11-30 19:25:51 -0800413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
415 if ((valid_hooks & (1 << i)) == 0)
416 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800417 if ((char __user *)repl->hook_entry[i] ==
418 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800419 break;
420 }
421
422 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
423 if (e->bitmask != 0) {
424 /* we make userspace set this right,
425 so there is no misunderstanding */
426 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
427 "in distinguisher\n");
428 return -EINVAL;
429 }
430 if (i != NF_BR_NUMHOOKS)
431 newinfo->hook_entry[i] = (struct ebt_entries *)e;
432 if (left < sizeof(struct ebt_entries))
433 break;
434 offset += sizeof(struct ebt_entries);
435 } else {
436 if (left < sizeof(struct ebt_entry))
437 break;
438 if (left < e->next_offset)
439 break;
440 offset += e->next_offset;
441 }
442 }
443 if (offset != limit) {
444 BUGPRINT("entries_size too small\n");
445 return -EINVAL;
446 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800447
448 /* check if all valid hooks have a chain */
449 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
450 if (!newinfo->hook_entry[i] &&
451 (valid_hooks & (1 << i))) {
452 BUGPRINT("Valid hook without chain\n");
453 return -EINVAL;
454 }
455 }
Al Viro70fe9af2006-11-30 19:26:14 -0800456 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800457}
458
459/*
460 * this one is very careful, as it is the first function
461 * to parse the userspace data
462 */
463static inline int
464ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800465 struct ebt_table_info *newinfo,
466 unsigned int *n, unsigned int *cnt,
467 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800468{
Al Viro22b440b2006-11-30 19:25:51 -0800469 int i;
470
471 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800472 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800473 break;
474 }
475 /* beginning of a new chain
476 if i == NF_BR_NUMHOOKS it must be a user defined chain */
477 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* this checks if the previous chain has as many entries
479 as it said it has */
480 if (*n != *cnt) {
481 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900482 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return -EINVAL;
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
486 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
487 /* only RETURN from udc */
488 if (i != NF_BR_NUMHOOKS ||
489 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
490 BUGPRINT("bad policy\n");
491 return -EINVAL;
492 }
493 }
494 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
495 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
497 BUGPRINT("counter_offset != totalcnt");
498 return -EINVAL;
499 }
500 *n = ((struct ebt_entries *)e)->nentries;
501 *cnt = 0;
502 return 0;
503 }
504 /* a plain old entry, heh */
505 if (sizeof(struct ebt_entry) > e->watchers_offset ||
506 e->watchers_offset > e->target_offset ||
507 e->target_offset >= e->next_offset) {
508 BUGPRINT("entry offsets not in right order\n");
509 return -EINVAL;
510 }
511 /* this is not checked anywhere else */
512 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
513 BUGPRINT("target size too small\n");
514 return -EINVAL;
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 (*cnt)++;
517 (*totalcnt)++;
518 return 0;
519}
520
521struct ebt_cl_stack
522{
523 struct ebt_chainstack cs;
524 int from;
525 unsigned int hookmask;
526};
527
528/*
529 * we need these positions to check that the jumps to a different part of the
530 * entries is a jump to the beginning of a new chain.
531 */
532static inline int
533ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800534 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
536 int i;
537
538 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800539 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return 0;
541 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
543 break;
544 }
545 /* only care about udc */
546 if (i != NF_BR_NUMHOOKS)
547 return 0;
548
549 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
550 /* these initialisations are depended on later in check_chainloops() */
551 udc[*n].cs.n = 0;
552 udc[*n].hookmask = 0;
553
554 (*n)++;
555 return 0;
556}
557
558static inline int
559ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
560{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200561 struct xt_mtdtor_param par;
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (i && (*i)-- == 0)
564 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200566 par.match = m->u.match;
567 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200568 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200569 if (par.match->destroy != NULL)
570 par.match->destroy(&par);
571 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return 0;
573}
574
575static inline int
576ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
577{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200578 struct xt_tgdtor_param par;
579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 if (i && (*i)-- == 0)
581 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Jan Engelhardta2df1642008-10-08 11:35:19 +0200583 par.target = w->u.watcher;
584 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200585 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200586 if (par.target->destroy != NULL)
587 par.target->destroy(&par);
588 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return 0;
590}
591
592static inline int
593ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
594{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200595 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 struct ebt_entry_target *t;
597
Al Viro40642f92006-11-30 19:24:12 -0800598 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return 0;
600 /* we're done */
601 if (cnt && (*cnt)-- == 0)
602 return 1;
603 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
604 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
605 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Jan Engelhardta2df1642008-10-08 11:35:19 +0200607 par.target = t->u.target;
608 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200609 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200610 if (par.target->destroy != NULL)
611 par.target->destroy(&par);
612 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
614}
615
616static inline int
617ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800618 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
620{
621 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200622 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800624 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200626 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200627 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800630 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return 0;
632
633 if (e->bitmask & ~EBT_F_MASK) {
634 BUGPRINT("Unknown flag for bitmask\n");
635 return -EINVAL;
636 }
637 if (e->invflags & ~EBT_INV_MASK) {
638 BUGPRINT("Unknown flag for inv bitmask\n");
639 return -EINVAL;
640 }
641 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
642 BUGPRINT("NOPROTO & 802_3 not allowed\n");
643 return -EINVAL;
644 }
645 /* what hook do we belong to? */
646 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800647 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 continue;
649 if ((char *)newinfo->hook_entry[i] < (char *)e)
650 hook = i;
651 else
652 break;
653 }
654 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
655 a base chain */
656 if (i < NF_BR_NUMHOOKS)
657 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
658 else {
659 for (i = 0; i < udc_cnt; i++)
660 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
661 break;
662 if (i == 0)
663 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
664 else
665 hookmask = cl_s[i - 1].hookmask;
666 }
667 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200668
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200669 mtpar.table = tgpar.table = name;
670 mtpar.entryinfo = tgpar.entryinfo = e;
671 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200672 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200673 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (ret != 0)
675 goto cleanup_matches;
676 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200677 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (ret != 0)
679 goto cleanup_watchers;
680 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800681 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jan Engelhardt043ef462008-10-08 11:35:15 +0200683 target = try_then_request_module(
684 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
685 "ebt_%s", t->u.name);
686 if (IS_ERR(target)) {
687 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200688 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200689 } else if (target == NULL) {
690 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200691 goto cleanup_watchers;
692 }
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 t->u.target = target;
695 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800696 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 BUGPRINT("Standard target size too big\n");
698 ret = -EFAULT;
699 goto cleanup_watchers;
700 }
701 if (((struct ebt_standard_target *)t)->verdict <
702 -NUM_STANDARD_TARGETS) {
703 BUGPRINT("Invalid standard target\n");
704 ret = -EFAULT;
705 goto cleanup_watchers;
706 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200707 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
708 module_put(t->u.target->me);
709 ret = -EFAULT;
710 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200711 }
712
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200713 tgpar.target = target;
714 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200715 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200716 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200717 if (ret < 0) {
718 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200719 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721 (*cnt)++;
722 return 0;
723cleanup_watchers:
724 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
725cleanup_matches:
726 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
727 return ret;
728}
729
730/*
731 * checks for loops and sets the hook mask for udc
732 * the hook mask for udc tells us from which base chains the udc can be
733 * accessed. This mask is a parameter to the check() functions of the extensions
734 */
735static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
736 unsigned int udc_cnt, unsigned int hooknr, char *base)
737{
738 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
739 struct ebt_entry *e = (struct ebt_entry *)chain->data;
740 struct ebt_entry_target *t;
741
742 while (pos < nentries || chain_nr != -1) {
743 /* end of udc, go back one 'recursion' step */
744 if (pos == nentries) {
745 /* put back values of the time when this chain was called */
746 e = cl_s[chain_nr].cs.e;
747 if (cl_s[chain_nr].from != -1)
748 nentries =
749 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
750 else
751 nentries = chain->nentries;
752 pos = cl_s[chain_nr].cs.n;
753 /* make sure we won't see a loop that isn't one */
754 cl_s[chain_nr].cs.n = 0;
755 chain_nr = cl_s[chain_nr].from;
756 if (pos == nentries)
757 continue;
758 }
759 t = (struct ebt_entry_target *)
760 (((char *)e) + e->target_offset);
761 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
762 goto letscontinue;
763 if (e->target_offset + sizeof(struct ebt_standard_target) >
764 e->next_offset) {
765 BUGPRINT("Standard target size too big\n");
766 return -1;
767 }
768 verdict = ((struct ebt_standard_target *)t)->verdict;
769 if (verdict >= 0) { /* jump to another chain */
770 struct ebt_entries *hlp2 =
771 (struct ebt_entries *)(base + verdict);
772 for (i = 0; i < udc_cnt; i++)
773 if (hlp2 == cl_s[i].cs.chaininfo)
774 break;
775 /* bad destination or loop */
776 if (i == udc_cnt) {
777 BUGPRINT("bad destination\n");
778 return -1;
779 }
780 if (cl_s[i].cs.n) {
781 BUGPRINT("loop\n");
782 return -1;
783 }
Al Viro98a08242006-11-30 19:24:49 -0800784 if (cl_s[i].hookmask & (1 << hooknr))
785 goto letscontinue;
786 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 cl_s[i].cs.n = pos + 1;
788 pos = 0;
789 cl_s[i].cs.e = ((void *)e + e->next_offset);
790 e = (struct ebt_entry *)(hlp2->data);
791 nentries = hlp2->nentries;
792 cl_s[i].from = chain_nr;
793 chain_nr = i;
794 /* this udc is accessible from the base chain for hooknr */
795 cl_s[i].hookmask |= (1 << hooknr);
796 continue;
797 }
798letscontinue:
799 e = (void *)e + e->next_offset;
800 pos++;
801 }
802 return 0;
803}
804
805/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800806static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
808 unsigned int i, j, k, udc_cnt;
809 int ret;
810 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
811
812 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800813 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 i++;
815 if (i == NF_BR_NUMHOOKS) {
816 BUGPRINT("No valid hooks specified\n");
817 return -EINVAL;
818 }
Al Viro1f072c92006-11-30 19:26:53 -0800819 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 BUGPRINT("Chains don't start at beginning\n");
821 return -EINVAL;
822 }
823 /* make sure chains are ordered after each other in same order
824 as their corresponding hooks */
825 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800826 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800828 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 BUGPRINT("Hook order must be followed\n");
830 return -EINVAL;
831 }
832 i = j;
833 }
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 /* do some early checkings and initialize some things */
836 i = 0; /* holds the expected nr. of entries for the chain */
837 j = 0; /* holds the up to now counted entries for the chain */
838 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900839 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
841 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800842 ebt_check_entry_size_and_hooks, newinfo,
843 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 if (ret != 0)
846 return ret;
847
848 if (i != j) {
849 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900850 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return -EINVAL;
852 }
853 if (k != newinfo->nentries) {
854 BUGPRINT("Total nentries is wrong\n");
855 return -EINVAL;
856 }
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* get the location of the udc, put them in an array
859 while we're at it, allocate the chainstack */
860 if (udc_cnt) {
861 /* this will get free'd in do_replace()/ebt_register_table()
862 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700863 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800864 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 if (!newinfo->chainstack)
866 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700867 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700869 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (!newinfo->chainstack[i]) {
871 while (i)
872 vfree(newinfo->chainstack[--i]);
873 vfree(newinfo->chainstack);
874 newinfo->chainstack = NULL;
875 return -ENOMEM;
876 }
877 }
878
Jayachandran C18bc89a2006-04-20 00:14:49 -0700879 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!cl_s)
881 return -ENOMEM;
882 i = 0; /* the i'th udc */
883 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800884 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 /* sanity check */
886 if (i != udc_cnt) {
887 BUGPRINT("i != udc_cnt\n");
888 vfree(cl_s);
889 return -EFAULT;
890 }
891 }
892
893 /* Check for loops */
894 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800895 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (check_chainloops(newinfo->hook_entry[i],
897 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700898 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 return -EINVAL;
900 }
901
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200902 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 - the nr of entries in each chain is right
904 - the size of the allocated space is right
905 - all valid hooks have a corresponding chain
906 - there are no loops
907 - wrong data can still be on the level of a single entry
908 - could be there are jumps to places that are not the
909 beginning of a chain. This can only occur in chains that
910 are not accessible from any base chains, so we don't care. */
911
912 /* used to know what we need to clean up if something goes wrong */
913 i = 0;
914 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800915 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 if (ret != 0) {
917 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
918 ebt_cleanup_entry, &i);
919 }
James Lamanna68d31872005-06-22 22:12:57 -0700920 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 return ret;
922}
923
924/* called under write_lock */
925static void get_counters(struct ebt_counter *oldcounters,
926 struct ebt_counter *counters, unsigned int nentries)
927{
928 int i, cpu;
929 struct ebt_counter *counter_base;
930
931 /* counters of cpu 0 */
932 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700933 sizeof(struct ebt_counter) * nentries);
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700936 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700937 if (cpu == 0)
938 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
940 for (i = 0; i < nentries; i++) {
941 counters[i].pcnt += counter_base[i].pcnt;
942 counters[i].bcnt += counter_base[i].bcnt;
943 }
944 }
945}
946
947/* replace the table */
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100948static int do_replace(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949{
950 int ret, i, countersize;
951 struct ebt_table_info *newinfo;
952 struct ebt_replace tmp;
953 struct ebt_table *t;
954 struct ebt_counter *counterstmp = NULL;
955 /* used to be able to unlock earlier */
956 struct ebt_table_info *table;
957
958 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
959 return -EFAULT;
960
961 if (len != sizeof(tmp) + tmp.entries_size) {
962 BUGPRINT("Wrong len argument\n");
963 return -EINVAL;
964 }
965
966 if (tmp.entries_size == 0) {
967 BUGPRINT("Entries_size never zero\n");
968 return -EINVAL;
969 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800970 /* overflow check */
971 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
972 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
973 return -ENOMEM;
974 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
975 return -ENOMEM;
976
Christoph Lameter53b8a312007-02-20 13:57:51 -0800977 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700978 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (!newinfo)
980 return -ENOMEM;
981
982 if (countersize)
983 memset(newinfo->counters, 0, countersize);
984
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800985 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (!newinfo->entries) {
987 ret = -ENOMEM;
988 goto free_newinfo;
989 }
990 if (copy_from_user(
991 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
992 BUGPRINT("Couldn't copy entries from userspace\n");
993 ret = -EFAULT;
994 goto free_entries;
995 }
996
997 /* the user wants counters back
998 the check on the size is done later, when we have the lock */
999 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001000 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (!counterstmp) {
1002 ret = -ENOMEM;
1003 goto free_entries;
1004 }
1005 }
1006 else
1007 counterstmp = NULL;
1008
1009 /* this can get initialized by translate_table() */
1010 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001011 ret = ebt_verify_pointers(&tmp, newinfo);
1012 if (ret != 0)
1013 goto free_counterstmp;
1014
1015 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017 if (ret != 0)
1018 goto free_counterstmp;
1019
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001020 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (!t) {
1022 ret = -ENOENT;
1023 goto free_iterate;
1024 }
1025
1026 /* the table doesn't like it */
1027 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1028 goto free_unlock;
1029
1030 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1031 BUGPRINT("Wrong nr. of counters requested\n");
1032 ret = -EINVAL;
1033 goto free_unlock;
1034 }
1035
1036 /* we have the mutex lock, so no danger in reading this pointer */
1037 table = t->private;
1038 /* make sure the table can only be rmmod'ed if it contains no rules */
1039 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1040 ret = -ENOENT;
1041 goto free_unlock;
1042 } else if (table->nentries && !newinfo->nentries)
1043 module_put(t->me);
1044 /* we need an atomic snapshot of the counters */
1045 write_lock_bh(&t->lock);
1046 if (tmp.num_counters)
1047 get_counters(t->private->counters, counterstmp,
1048 t->private->nentries);
1049
1050 t->private = newinfo;
1051 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001052 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* so, a user can change the chains while having messed up her counter
1054 allocation. Only reason why this is done is because this way the lock
1055 is held only once, while this doesn't bring the kernel into a
1056 dangerous state. */
1057 if (tmp.num_counters &&
1058 copy_to_user(tmp.counters, counterstmp,
1059 tmp.num_counters * sizeof(struct ebt_counter))) {
1060 BUGPRINT("Couldn't copy counters to userspace\n");
1061 ret = -EFAULT;
1062 }
1063 else
1064 ret = 0;
1065
1066 /* decrease module count and free resources */
1067 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1068 ebt_cleanup_entry, NULL);
1069
1070 vfree(table->entries);
1071 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001072 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 vfree(table->chainstack[i]);
1074 vfree(table->chainstack);
1075 }
1076 vfree(table);
1077
James Lamanna68d31872005-06-22 22:12:57 -07001078 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return ret;
1080
1081free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001082 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083free_iterate:
1084 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1085 ebt_cleanup_entry, NULL);
1086free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001087 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 /* can be initialized in translate_table() */
1089 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001090 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 vfree(newinfo->chainstack[i]);
1092 vfree(newinfo->chainstack);
1093 }
1094free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001095 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001097 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return ret;
1099}
1100
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001101int ebt_register_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102{
1103 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001104 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001105 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001107 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Al Virodf07a812006-11-30 19:28:25 -08001109 if (!table || !(repl = table->table) || !repl->entries ||
1110 repl->entries_size == 0 ||
1111 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1113 return -EINVAL;
1114 }
1115
Christoph Lameter53b8a312007-02-20 13:57:51 -08001116 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001117 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 ret = -ENOMEM;
1119 if (!newinfo)
1120 return -ENOMEM;
1121
Al Virodf07a812006-11-30 19:28:25 -08001122 p = vmalloc(repl->entries_size);
1123 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 goto free_newinfo;
1125
Al Virodf07a812006-11-30 19:28:25 -08001126 memcpy(p, repl->entries, repl->entries_size);
1127 newinfo->entries = p;
1128
1129 newinfo->entries_size = repl->entries_size;
1130 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 if (countersize)
1133 memset(newinfo->counters, 0, countersize);
1134
1135 /* fill in newinfo and parse the entries */
1136 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001137 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1138 if ((repl->valid_hooks & (1 << i)) == 0)
1139 newinfo->hook_entry[i] = NULL;
1140 else
1141 newinfo->hook_entry[i] = p +
1142 ((char *)repl->hook_entry[i] - repl->entries);
1143 }
1144 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 if (ret != 0) {
1146 BUGPRINT("Translate_table failed\n");
1147 goto free_chainstack;
1148 }
1149
1150 if (table->check && table->check(newinfo, table->valid_hooks)) {
1151 BUGPRINT("The table doesn't like its own initial data, lol\n");
1152 return -EINVAL;
1153 }
1154
1155 table->private = newinfo;
1156 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001157 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (ret != 0)
1159 goto free_chainstack;
1160
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001161 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001162 if (strcmp(t->name, table->name) == 0) {
1163 ret = -EEXIST;
1164 BUGPRINT("Table name already exists\n");
1165 goto free_unlock;
1166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
1168
1169 /* Hold a reference count if the chains aren't empty */
1170 if (newinfo->nentries && !try_module_get(table->me)) {
1171 ret = -ENOENT;
1172 goto free_unlock;
1173 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001174 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001175 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 return 0;
1177free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001178 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179free_chainstack:
1180 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001181 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 vfree(newinfo->chainstack[i]);
1183 vfree(newinfo->chainstack);
1184 }
1185 vfree(newinfo->entries);
1186free_newinfo:
1187 vfree(newinfo);
1188 return ret;
1189}
1190
1191void ebt_unregister_table(struct ebt_table *table)
1192{
1193 int i;
1194
1195 if (!table) {
1196 BUGPRINT("Request to unregister NULL table!!!\n");
1197 return;
1198 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001199 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001200 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001201 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001202 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001204 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 vfree(table->private->chainstack[i]);
1206 vfree(table->private->chainstack);
1207 }
1208 vfree(table->private);
1209}
1210
1211/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001212static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 int i, ret;
1215 struct ebt_counter *tmp;
1216 struct ebt_replace hlp;
1217 struct ebt_table *t;
1218
1219 if (copy_from_user(&hlp, user, sizeof(hlp)))
1220 return -EFAULT;
1221
1222 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1223 return -EINVAL;
1224 if (hlp.num_counters == 0)
1225 return -EINVAL;
1226
Jayachandran C18bc89a2006-04-20 00:14:49 -07001227 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 MEMPRINT("Update_counters && nomemory\n");
1229 return -ENOMEM;
1230 }
1231
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001232 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 if (!t)
1234 goto free_tmp;
1235
1236 if (hlp.num_counters != t->private->nentries) {
1237 BUGPRINT("Wrong nr of counters\n");
1238 ret = -EINVAL;
1239 goto unlock_mutex;
1240 }
1241
1242 if ( copy_from_user(tmp, hlp.counters,
1243 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1244 BUGPRINT("Updata_counters && !cfu\n");
1245 ret = -EFAULT;
1246 goto unlock_mutex;
1247 }
1248
1249 /* we want an atomic add of the counters */
1250 write_lock_bh(&t->lock);
1251
1252 /* we add to the counters of the first cpu */
1253 for (i = 0; i < hlp.num_counters; i++) {
1254 t->private->counters[i].pcnt += tmp[i].pcnt;
1255 t->private->counters[i].bcnt += tmp[i].bcnt;
1256 }
1257
1258 write_unlock_bh(&t->lock);
1259 ret = 0;
1260unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001261 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262free_tmp:
1263 vfree(tmp);
1264 return ret;
1265}
1266
1267static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001268 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269{
Al Viro1e419cd2006-11-30 19:28:48 -08001270 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1272 return -EFAULT;
1273 return 0;
1274}
1275
1276static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001277 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
Al Viro1e419cd2006-11-30 19:28:48 -08001279 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1281 return -EFAULT;
1282 return 0;
1283}
1284
Al Viro1e419cd2006-11-30 19:28:48 -08001285static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
1287 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001288 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 struct ebt_entry_target *t;
1290
Al Viro40642f92006-11-30 19:24:12 -08001291 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 return 0;
1293
Al Viro1e419cd2006-11-30 19:28:48 -08001294 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1298 if (ret != 0)
1299 return ret;
1300 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1301 if (ret != 0)
1302 return ret;
1303 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1304 return -EFAULT;
1305 return 0;
1306}
1307
Ingo Molnar57b47a52006-03-20 22:35:41 -08001308/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1310 int *len, int cmd)
1311{
1312 struct ebt_replace tmp;
1313 struct ebt_counter *counterstmp, *oldcounters;
1314 unsigned int entries_size, nentries;
1315 char *entries;
1316
1317 if (cmd == EBT_SO_GET_ENTRIES) {
1318 entries_size = t->private->entries_size;
1319 nentries = t->private->nentries;
1320 entries = t->private->entries;
1321 oldcounters = t->private->counters;
1322 } else {
1323 entries_size = t->table->entries_size;
1324 nentries = t->table->nentries;
1325 entries = t->table->entries;
1326 oldcounters = t->table->counters;
1327 }
1328
1329 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1330 BUGPRINT("Cfu didn't work\n");
1331 return -EFAULT;
1332 }
1333
1334 if (*len != sizeof(struct ebt_replace) + entries_size +
1335 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1336 BUGPRINT("Wrong size\n");
1337 return -EINVAL;
1338 }
1339
1340 if (tmp.nentries != nentries) {
1341 BUGPRINT("Nentries wrong\n");
1342 return -EINVAL;
1343 }
1344
1345 if (tmp.entries_size != entries_size) {
1346 BUGPRINT("Wrong size\n");
1347 return -EINVAL;
1348 }
1349
1350 /* userspace might not need the counters */
1351 if (tmp.num_counters) {
1352 if (tmp.num_counters != nentries) {
1353 BUGPRINT("Num_counters wrong\n");
1354 return -EINVAL;
1355 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001356 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 if (!counterstmp) {
1358 MEMPRINT("Couldn't copy counters, out of memory\n");
1359 return -ENOMEM;
1360 }
1361 write_lock_bh(&t->lock);
1362 get_counters(oldcounters, counterstmp, nentries);
1363 write_unlock_bh(&t->lock);
1364
1365 if (copy_to_user(tmp.counters, counterstmp,
1366 nentries * sizeof(struct ebt_counter))) {
1367 BUGPRINT("Couldn't copy counters to userspace\n");
1368 vfree(counterstmp);
1369 return -EFAULT;
1370 }
1371 vfree(counterstmp);
1372 }
1373
1374 if (copy_to_user(tmp.entries, entries, entries_size)) {
1375 BUGPRINT("Couldn't copy entries to userspace\n");
1376 return -EFAULT;
1377 }
1378 /* set the match/watcher/target names right */
1379 return EBT_ENTRY_ITERATE(entries, entries_size,
1380 ebt_make_names, entries, tmp.entries);
1381}
1382
1383static int do_ebt_set_ctl(struct sock *sk,
1384 int cmd, void __user *user, unsigned int len)
1385{
1386 int ret;
1387
1388 switch(cmd) {
1389 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001390 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 break;
1392 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001393 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 break;
1395 default:
1396 ret = -EINVAL;
1397 }
1398 return ret;
1399}
1400
1401static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1402{
1403 int ret;
1404 struct ebt_replace tmp;
1405 struct ebt_table *t;
1406
1407 if (copy_from_user(&tmp, user, sizeof(tmp)))
1408 return -EFAULT;
1409
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001410 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (!t)
1412 return ret;
1413
1414 switch(cmd) {
1415 case EBT_SO_GET_INFO:
1416 case EBT_SO_GET_INIT_INFO:
1417 if (*len != sizeof(struct ebt_replace)){
1418 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001419 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 break;
1421 }
1422 if (cmd == EBT_SO_GET_INFO) {
1423 tmp.nentries = t->private->nentries;
1424 tmp.entries_size = t->private->entries_size;
1425 tmp.valid_hooks = t->valid_hooks;
1426 } else {
1427 tmp.nentries = t->table->nentries;
1428 tmp.entries_size = t->table->entries_size;
1429 tmp.valid_hooks = t->table->valid_hooks;
1430 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001431 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 if (copy_to_user(user, &tmp, *len) != 0){
1433 BUGPRINT("c2u Didn't work\n");
1434 ret = -EFAULT;
1435 break;
1436 }
1437 ret = 0;
1438 break;
1439
1440 case EBT_SO_GET_ENTRIES:
1441 case EBT_SO_GET_INIT_ENTRIES:
1442 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001443 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 break;
1445
1446 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001447 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 ret = -EINVAL;
1449 }
1450
1451 return ret;
1452}
1453
1454static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001455{
1456 .pf = PF_INET,
1457 .set_optmin = EBT_BASE_CTL,
1458 .set_optmax = EBT_SO_SET_MAX + 1,
1459 .set = do_ebt_set_ctl,
1460 .get_optmin = EBT_BASE_CTL,
1461 .get_optmax = EBT_SO_GET_MAX + 1,
1462 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001463 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464};
1465
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001466static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467{
1468 int ret;
1469
Jan Engelhardt043ef462008-10-08 11:35:15 +02001470 ret = xt_register_target(&ebt_standard_target);
1471 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001473 ret = nf_register_sockopt(&ebt_sockopts);
1474 if (ret < 0) {
1475 xt_unregister_target(&ebt_standard_target);
1476 return ret;
1477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Patrick McHardya887c1c2007-07-14 20:46:15 -07001479 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return 0;
1481}
1482
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001483static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
1485 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001486 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001487 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488}
1489
1490EXPORT_SYMBOL(ebt_register_table);
1491EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001493module_init(ebtables_init);
1494module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495MODULE_LICENSE("GPL");