blob: 5bb88eb0aad43c928c5d43877a2497121dec832d [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
308#ifndef CONFIG_KMOD
309#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
310#else
311static void *
312find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800313 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
315 void *ret;
316
317 ret = find_inlist_lock_noload(head, name, error, mutex);
318 if (!ret) {
319 request_module("%s%s", prefix, name);
320 ret = find_inlist_lock_noload(head, name, error, mutex);
321 }
322 return ret;
323}
324#endif
325
326static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800327find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
330}
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200333ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
334 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200336 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200337 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800338 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 int ret;
340
Al Viro14197d52006-11-30 19:25:21 -0800341 if (left < sizeof(struct ebt_entry_match) ||
342 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200344
345 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
346 m->u.name, 0), "ebt_%s", m->u.name);
347 if (IS_ERR(match))
348 return PTR_ERR(match);
349 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200351 m->u.match = match;
352
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200353 par->match = match;
354 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200355 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200356 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200357 if (ret < 0) {
358 module_put(match->me);
359 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 (*cnt)++;
363 return 0;
364}
365
366static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200367ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
368 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200370 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200371 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800372 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 int ret;
374
Al Viro14197d52006-11-30 19:25:21 -0800375 if (left < sizeof(struct ebt_entry_watcher) ||
376 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200378
379 watcher = try_then_request_module(
380 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
381 "ebt_%s", w->u.name);
382 if (IS_ERR(watcher))
383 return PTR_ERR(watcher);
384 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200386 w->u.watcher = watcher;
387
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200388 par->target = watcher;
389 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200390 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200391 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200392 if (ret < 0) {
393 module_put(watcher->me);
394 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 (*cnt)++;
398 return 0;
399}
400
Al Viro70fe9af2006-11-30 19:26:14 -0800401static int ebt_verify_pointers(struct ebt_replace *repl,
402 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
Al Viro70fe9af2006-11-30 19:26:14 -0800404 unsigned int limit = repl->entries_size;
405 unsigned int valid_hooks = repl->valid_hooks;
406 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 int i;
408
Al Viroe4fd77d2006-11-30 19:26:35 -0800409 for (i = 0; i < NF_BR_NUMHOOKS; i++)
410 newinfo->hook_entry[i] = NULL;
411
412 newinfo->entries_size = repl->entries_size;
413 newinfo->nentries = repl->nentries;
414
Al Viro70fe9af2006-11-30 19:26:14 -0800415 while (offset < limit) {
416 size_t left = limit - offset;
417 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800418
Al Viro70fe9af2006-11-30 19:26:14 -0800419 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 break;
Al Viro22b440b2006-11-30 19:25:51 -0800421
Al Viro70fe9af2006-11-30 19:26:14 -0800422 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
423 if ((valid_hooks & (1 << i)) == 0)
424 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800425 if ((char __user *)repl->hook_entry[i] ==
426 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800427 break;
428 }
429
430 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
431 if (e->bitmask != 0) {
432 /* we make userspace set this right,
433 so there is no misunderstanding */
434 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
435 "in distinguisher\n");
436 return -EINVAL;
437 }
438 if (i != NF_BR_NUMHOOKS)
439 newinfo->hook_entry[i] = (struct ebt_entries *)e;
440 if (left < sizeof(struct ebt_entries))
441 break;
442 offset += sizeof(struct ebt_entries);
443 } else {
444 if (left < sizeof(struct ebt_entry))
445 break;
446 if (left < e->next_offset)
447 break;
448 offset += e->next_offset;
449 }
450 }
451 if (offset != limit) {
452 BUGPRINT("entries_size too small\n");
453 return -EINVAL;
454 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800455
456 /* check if all valid hooks have a chain */
457 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
458 if (!newinfo->hook_entry[i] &&
459 (valid_hooks & (1 << i))) {
460 BUGPRINT("Valid hook without chain\n");
461 return -EINVAL;
462 }
463 }
Al Viro70fe9af2006-11-30 19:26:14 -0800464 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800465}
466
467/*
468 * this one is very careful, as it is the first function
469 * to parse the userspace data
470 */
471static inline int
472ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800473 struct ebt_table_info *newinfo,
474 unsigned int *n, unsigned int *cnt,
475 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800476{
Al Viro22b440b2006-11-30 19:25:51 -0800477 int i;
478
479 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800480 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800481 break;
482 }
483 /* beginning of a new chain
484 if i == NF_BR_NUMHOOKS it must be a user defined chain */
485 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 /* this checks if the previous chain has as many entries
487 as it said it has */
488 if (*n != *cnt) {
489 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900490 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return -EINVAL;
492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
494 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
495 /* only RETURN from udc */
496 if (i != NF_BR_NUMHOOKS ||
497 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
498 BUGPRINT("bad policy\n");
499 return -EINVAL;
500 }
501 }
502 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
503 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
505 BUGPRINT("counter_offset != totalcnt");
506 return -EINVAL;
507 }
508 *n = ((struct ebt_entries *)e)->nentries;
509 *cnt = 0;
510 return 0;
511 }
512 /* a plain old entry, heh */
513 if (sizeof(struct ebt_entry) > e->watchers_offset ||
514 e->watchers_offset > e->target_offset ||
515 e->target_offset >= e->next_offset) {
516 BUGPRINT("entry offsets not in right order\n");
517 return -EINVAL;
518 }
519 /* this is not checked anywhere else */
520 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
521 BUGPRINT("target size too small\n");
522 return -EINVAL;
523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 (*cnt)++;
525 (*totalcnt)++;
526 return 0;
527}
528
529struct ebt_cl_stack
530{
531 struct ebt_chainstack cs;
532 int from;
533 unsigned int hookmask;
534};
535
536/*
537 * we need these positions to check that the jumps to a different part of the
538 * entries is a jump to the beginning of a new chain.
539 */
540static inline int
541ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800542 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
544 int i;
545
546 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800547 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 return 0;
549 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
551 break;
552 }
553 /* only care about udc */
554 if (i != NF_BR_NUMHOOKS)
555 return 0;
556
557 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
558 /* these initialisations are depended on later in check_chainloops() */
559 udc[*n].cs.n = 0;
560 udc[*n].hookmask = 0;
561
562 (*n)++;
563 return 0;
564}
565
566static inline int
567ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
568{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200569 struct xt_mtdtor_param par;
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 if (i && (*i)-- == 0)
572 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200574 par.match = m->u.match;
575 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200576 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200577 if (par.match->destroy != NULL)
578 par.match->destroy(&par);
579 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return 0;
581}
582
583static inline int
584ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
585{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200586 struct xt_tgdtor_param par;
587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 if (i && (*i)-- == 0)
589 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Jan Engelhardta2df1642008-10-08 11:35:19 +0200591 par.target = w->u.watcher;
592 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200593 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200594 if (par.target->destroy != NULL)
595 par.target->destroy(&par);
596 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return 0;
598}
599
600static inline int
601ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
602{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200603 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 struct ebt_entry_target *t;
605
Al Viro40642f92006-11-30 19:24:12 -0800606 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 return 0;
608 /* we're done */
609 if (cnt && (*cnt)-- == 0)
610 return 1;
611 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
612 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
613 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Jan Engelhardta2df1642008-10-08 11:35:19 +0200615 par.target = t->u.target;
616 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200617 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200618 if (par.target->destroy != NULL)
619 par.target->destroy(&par);
620 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return 0;
622}
623
624static inline int
625ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800626 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
628{
629 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200630 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800632 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200634 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200635 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800638 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
640
641 if (e->bitmask & ~EBT_F_MASK) {
642 BUGPRINT("Unknown flag for bitmask\n");
643 return -EINVAL;
644 }
645 if (e->invflags & ~EBT_INV_MASK) {
646 BUGPRINT("Unknown flag for inv bitmask\n");
647 return -EINVAL;
648 }
649 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
650 BUGPRINT("NOPROTO & 802_3 not allowed\n");
651 return -EINVAL;
652 }
653 /* what hook do we belong to? */
654 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800655 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 continue;
657 if ((char *)newinfo->hook_entry[i] < (char *)e)
658 hook = i;
659 else
660 break;
661 }
662 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
663 a base chain */
664 if (i < NF_BR_NUMHOOKS)
665 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
666 else {
667 for (i = 0; i < udc_cnt; i++)
668 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
669 break;
670 if (i == 0)
671 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
672 else
673 hookmask = cl_s[i - 1].hookmask;
674 }
675 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200676
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200677 mtpar.table = tgpar.table = name;
678 mtpar.entryinfo = tgpar.entryinfo = e;
679 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200680 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200681 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (ret != 0)
683 goto cleanup_matches;
684 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200685 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (ret != 0)
687 goto cleanup_watchers;
688 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800689 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Jan Engelhardt043ef462008-10-08 11:35:15 +0200691 target = try_then_request_module(
692 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
693 "ebt_%s", t->u.name);
694 if (IS_ERR(target)) {
695 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200696 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200697 } else if (target == NULL) {
698 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200699 goto cleanup_watchers;
700 }
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 t->u.target = target;
703 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800704 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 BUGPRINT("Standard target size too big\n");
706 ret = -EFAULT;
707 goto cleanup_watchers;
708 }
709 if (((struct ebt_standard_target *)t)->verdict <
710 -NUM_STANDARD_TARGETS) {
711 BUGPRINT("Invalid standard target\n");
712 ret = -EFAULT;
713 goto cleanup_watchers;
714 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200715 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
716 module_put(t->u.target->me);
717 ret = -EFAULT;
718 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200719 }
720
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200721 tgpar.target = target;
722 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200723 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200724 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200725 if (ret < 0) {
726 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200727 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 }
729 (*cnt)++;
730 return 0;
731cleanup_watchers:
732 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
733cleanup_matches:
734 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
735 return ret;
736}
737
738/*
739 * checks for loops and sets the hook mask for udc
740 * the hook mask for udc tells us from which base chains the udc can be
741 * accessed. This mask is a parameter to the check() functions of the extensions
742 */
743static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
744 unsigned int udc_cnt, unsigned int hooknr, char *base)
745{
746 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
747 struct ebt_entry *e = (struct ebt_entry *)chain->data;
748 struct ebt_entry_target *t;
749
750 while (pos < nentries || chain_nr != -1) {
751 /* end of udc, go back one 'recursion' step */
752 if (pos == nentries) {
753 /* put back values of the time when this chain was called */
754 e = cl_s[chain_nr].cs.e;
755 if (cl_s[chain_nr].from != -1)
756 nentries =
757 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
758 else
759 nentries = chain->nentries;
760 pos = cl_s[chain_nr].cs.n;
761 /* make sure we won't see a loop that isn't one */
762 cl_s[chain_nr].cs.n = 0;
763 chain_nr = cl_s[chain_nr].from;
764 if (pos == nentries)
765 continue;
766 }
767 t = (struct ebt_entry_target *)
768 (((char *)e) + e->target_offset);
769 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
770 goto letscontinue;
771 if (e->target_offset + sizeof(struct ebt_standard_target) >
772 e->next_offset) {
773 BUGPRINT("Standard target size too big\n");
774 return -1;
775 }
776 verdict = ((struct ebt_standard_target *)t)->verdict;
777 if (verdict >= 0) { /* jump to another chain */
778 struct ebt_entries *hlp2 =
779 (struct ebt_entries *)(base + verdict);
780 for (i = 0; i < udc_cnt; i++)
781 if (hlp2 == cl_s[i].cs.chaininfo)
782 break;
783 /* bad destination or loop */
784 if (i == udc_cnt) {
785 BUGPRINT("bad destination\n");
786 return -1;
787 }
788 if (cl_s[i].cs.n) {
789 BUGPRINT("loop\n");
790 return -1;
791 }
Al Viro98a08242006-11-30 19:24:49 -0800792 if (cl_s[i].hookmask & (1 << hooknr))
793 goto letscontinue;
794 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 cl_s[i].cs.n = pos + 1;
796 pos = 0;
797 cl_s[i].cs.e = ((void *)e + e->next_offset);
798 e = (struct ebt_entry *)(hlp2->data);
799 nentries = hlp2->nentries;
800 cl_s[i].from = chain_nr;
801 chain_nr = i;
802 /* this udc is accessible from the base chain for hooknr */
803 cl_s[i].hookmask |= (1 << hooknr);
804 continue;
805 }
806letscontinue:
807 e = (void *)e + e->next_offset;
808 pos++;
809 }
810 return 0;
811}
812
813/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800814static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 unsigned int i, j, k, udc_cnt;
817 int ret;
818 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
819
820 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800821 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 i++;
823 if (i == NF_BR_NUMHOOKS) {
824 BUGPRINT("No valid hooks specified\n");
825 return -EINVAL;
826 }
Al Viro1f072c92006-11-30 19:26:53 -0800827 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 BUGPRINT("Chains don't start at beginning\n");
829 return -EINVAL;
830 }
831 /* make sure chains are ordered after each other in same order
832 as their corresponding hooks */
833 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800834 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800836 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 BUGPRINT("Hook order must be followed\n");
838 return -EINVAL;
839 }
840 i = j;
841 }
842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /* do some early checkings and initialize some things */
844 i = 0; /* holds the expected nr. of entries for the chain */
845 j = 0; /* holds the up to now counted entries for the chain */
846 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900847 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
849 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800850 ebt_check_entry_size_and_hooks, newinfo,
851 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
853 if (ret != 0)
854 return ret;
855
856 if (i != j) {
857 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900858 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 return -EINVAL;
860 }
861 if (k != newinfo->nentries) {
862 BUGPRINT("Total nentries is wrong\n");
863 return -EINVAL;
864 }
865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /* get the location of the udc, put them in an array
867 while we're at it, allocate the chainstack */
868 if (udc_cnt) {
869 /* this will get free'd in do_replace()/ebt_register_table()
870 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700871 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800872 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (!newinfo->chainstack)
874 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700875 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700877 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (!newinfo->chainstack[i]) {
879 while (i)
880 vfree(newinfo->chainstack[--i]);
881 vfree(newinfo->chainstack);
882 newinfo->chainstack = NULL;
883 return -ENOMEM;
884 }
885 }
886
Jayachandran C18bc89a2006-04-20 00:14:49 -0700887 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (!cl_s)
889 return -ENOMEM;
890 i = 0; /* the i'th udc */
891 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800892 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 /* sanity check */
894 if (i != udc_cnt) {
895 BUGPRINT("i != udc_cnt\n");
896 vfree(cl_s);
897 return -EFAULT;
898 }
899 }
900
901 /* Check for loops */
902 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800903 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (check_chainloops(newinfo->hook_entry[i],
905 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700906 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 return -EINVAL;
908 }
909
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200910 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 - the nr of entries in each chain is right
912 - the size of the allocated space is right
913 - all valid hooks have a corresponding chain
914 - there are no loops
915 - wrong data can still be on the level of a single entry
916 - could be there are jumps to places that are not the
917 beginning of a chain. This can only occur in chains that
918 are not accessible from any base chains, so we don't care. */
919
920 /* used to know what we need to clean up if something goes wrong */
921 i = 0;
922 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800923 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 if (ret != 0) {
925 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
926 ebt_cleanup_entry, &i);
927 }
James Lamanna68d31872005-06-22 22:12:57 -0700928 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 return ret;
930}
931
932/* called under write_lock */
933static void get_counters(struct ebt_counter *oldcounters,
934 struct ebt_counter *counters, unsigned int nentries)
935{
936 int i, cpu;
937 struct ebt_counter *counter_base;
938
939 /* counters of cpu 0 */
940 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700941 sizeof(struct ebt_counter) * nentries);
942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700944 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700945 if (cpu == 0)
946 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
948 for (i = 0; i < nentries; i++) {
949 counters[i].pcnt += counter_base[i].pcnt;
950 counters[i].bcnt += counter_base[i].bcnt;
951 }
952 }
953}
954
955/* replace the table */
956static int do_replace(void __user *user, unsigned int len)
957{
958 int ret, i, countersize;
959 struct ebt_table_info *newinfo;
960 struct ebt_replace tmp;
961 struct ebt_table *t;
962 struct ebt_counter *counterstmp = NULL;
963 /* used to be able to unlock earlier */
964 struct ebt_table_info *table;
965
966 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
967 return -EFAULT;
968
969 if (len != sizeof(tmp) + tmp.entries_size) {
970 BUGPRINT("Wrong len argument\n");
971 return -EINVAL;
972 }
973
974 if (tmp.entries_size == 0) {
975 BUGPRINT("Entries_size never zero\n");
976 return -EINVAL;
977 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800978 /* overflow check */
979 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
980 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
981 return -ENOMEM;
982 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
983 return -ENOMEM;
984
Christoph Lameter53b8a312007-02-20 13:57:51 -0800985 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700986 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (!newinfo)
988 return -ENOMEM;
989
990 if (countersize)
991 memset(newinfo->counters, 0, countersize);
992
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800993 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 if (!newinfo->entries) {
995 ret = -ENOMEM;
996 goto free_newinfo;
997 }
998 if (copy_from_user(
999 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1000 BUGPRINT("Couldn't copy entries from userspace\n");
1001 ret = -EFAULT;
1002 goto free_entries;
1003 }
1004
1005 /* the user wants counters back
1006 the check on the size is done later, when we have the lock */
1007 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001008 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (!counterstmp) {
1010 ret = -ENOMEM;
1011 goto free_entries;
1012 }
1013 }
1014 else
1015 counterstmp = NULL;
1016
1017 /* this can get initialized by translate_table() */
1018 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001019 ret = ebt_verify_pointers(&tmp, newinfo);
1020 if (ret != 0)
1021 goto free_counterstmp;
1022
1023 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 if (ret != 0)
1026 goto free_counterstmp;
1027
1028 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1029 if (!t) {
1030 ret = -ENOENT;
1031 goto free_iterate;
1032 }
1033
1034 /* the table doesn't like it */
1035 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1036 goto free_unlock;
1037
1038 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1039 BUGPRINT("Wrong nr. of counters requested\n");
1040 ret = -EINVAL;
1041 goto free_unlock;
1042 }
1043
1044 /* we have the mutex lock, so no danger in reading this pointer */
1045 table = t->private;
1046 /* make sure the table can only be rmmod'ed if it contains no rules */
1047 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1048 ret = -ENOENT;
1049 goto free_unlock;
1050 } else if (table->nentries && !newinfo->nentries)
1051 module_put(t->me);
1052 /* we need an atomic snapshot of the counters */
1053 write_lock_bh(&t->lock);
1054 if (tmp.num_counters)
1055 get_counters(t->private->counters, counterstmp,
1056 t->private->nentries);
1057
1058 t->private = newinfo;
1059 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001060 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 /* so, a user can change the chains while having messed up her counter
1062 allocation. Only reason why this is done is because this way the lock
1063 is held only once, while this doesn't bring the kernel into a
1064 dangerous state. */
1065 if (tmp.num_counters &&
1066 copy_to_user(tmp.counters, counterstmp,
1067 tmp.num_counters * sizeof(struct ebt_counter))) {
1068 BUGPRINT("Couldn't copy counters to userspace\n");
1069 ret = -EFAULT;
1070 }
1071 else
1072 ret = 0;
1073
1074 /* decrease module count and free resources */
1075 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1076 ebt_cleanup_entry, NULL);
1077
1078 vfree(table->entries);
1079 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001080 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 vfree(table->chainstack[i]);
1082 vfree(table->chainstack);
1083 }
1084 vfree(table);
1085
James Lamanna68d31872005-06-22 22:12:57 -07001086 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return ret;
1088
1089free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001090 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091free_iterate:
1092 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1093 ebt_cleanup_entry, NULL);
1094free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001095 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 /* can be initialized in translate_table() */
1097 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001098 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 vfree(newinfo->chainstack[i]);
1100 vfree(newinfo->chainstack);
1101 }
1102free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001103 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001105 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 return ret;
1107}
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109int ebt_register_table(struct ebt_table *table)
1110{
1111 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001112 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001113 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001115 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Al Virodf07a812006-11-30 19:28:25 -08001117 if (!table || !(repl = table->table) || !repl->entries ||
1118 repl->entries_size == 0 ||
1119 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1121 return -EINVAL;
1122 }
1123
Christoph Lameter53b8a312007-02-20 13:57:51 -08001124 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001125 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 ret = -ENOMEM;
1127 if (!newinfo)
1128 return -ENOMEM;
1129
Al Virodf07a812006-11-30 19:28:25 -08001130 p = vmalloc(repl->entries_size);
1131 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 goto free_newinfo;
1133
Al Virodf07a812006-11-30 19:28:25 -08001134 memcpy(p, repl->entries, repl->entries_size);
1135 newinfo->entries = p;
1136
1137 newinfo->entries_size = repl->entries_size;
1138 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 if (countersize)
1141 memset(newinfo->counters, 0, countersize);
1142
1143 /* fill in newinfo and parse the entries */
1144 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001145 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1146 if ((repl->valid_hooks & (1 << i)) == 0)
1147 newinfo->hook_entry[i] = NULL;
1148 else
1149 newinfo->hook_entry[i] = p +
1150 ((char *)repl->hook_entry[i] - repl->entries);
1151 }
1152 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (ret != 0) {
1154 BUGPRINT("Translate_table failed\n");
1155 goto free_chainstack;
1156 }
1157
1158 if (table->check && table->check(newinfo, table->valid_hooks)) {
1159 BUGPRINT("The table doesn't like its own initial data, lol\n");
1160 return -EINVAL;
1161 }
1162
1163 table->private = newinfo;
1164 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001165 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 if (ret != 0)
1167 goto free_chainstack;
1168
Patrick McHardydf0933d2006-09-20 11:57:53 -07001169 list_for_each_entry(t, &ebt_tables, list) {
1170 if (strcmp(t->name, table->name) == 0) {
1171 ret = -EEXIST;
1172 BUGPRINT("Table name already exists\n");
1173 goto free_unlock;
1174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176
1177 /* Hold a reference count if the chains aren't empty */
1178 if (newinfo->nentries && !try_module_get(table->me)) {
1179 ret = -ENOENT;
1180 goto free_unlock;
1181 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001182 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001183 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 return 0;
1185free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001186 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187free_chainstack:
1188 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001189 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 vfree(newinfo->chainstack[i]);
1191 vfree(newinfo->chainstack);
1192 }
1193 vfree(newinfo->entries);
1194free_newinfo:
1195 vfree(newinfo);
1196 return ret;
1197}
1198
1199void ebt_unregister_table(struct ebt_table *table)
1200{
1201 int i;
1202
1203 if (!table) {
1204 BUGPRINT("Request to unregister NULL table!!!\n");
1205 return;
1206 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001207 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001208 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001209 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001210 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001212 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 vfree(table->private->chainstack[i]);
1214 vfree(table->private->chainstack);
1215 }
1216 vfree(table->private);
1217}
1218
1219/* userspace just supplied us with counters */
1220static int update_counters(void __user *user, unsigned int len)
1221{
1222 int i, ret;
1223 struct ebt_counter *tmp;
1224 struct ebt_replace hlp;
1225 struct ebt_table *t;
1226
1227 if (copy_from_user(&hlp, user, sizeof(hlp)))
1228 return -EFAULT;
1229
1230 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1231 return -EINVAL;
1232 if (hlp.num_counters == 0)
1233 return -EINVAL;
1234
Jayachandran C18bc89a2006-04-20 00:14:49 -07001235 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 MEMPRINT("Update_counters && nomemory\n");
1237 return -ENOMEM;
1238 }
1239
1240 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1241 if (!t)
1242 goto free_tmp;
1243
1244 if (hlp.num_counters != t->private->nentries) {
1245 BUGPRINT("Wrong nr of counters\n");
1246 ret = -EINVAL;
1247 goto unlock_mutex;
1248 }
1249
1250 if ( copy_from_user(tmp, hlp.counters,
1251 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1252 BUGPRINT("Updata_counters && !cfu\n");
1253 ret = -EFAULT;
1254 goto unlock_mutex;
1255 }
1256
1257 /* we want an atomic add of the counters */
1258 write_lock_bh(&t->lock);
1259
1260 /* we add to the counters of the first cpu */
1261 for (i = 0; i < hlp.num_counters; i++) {
1262 t->private->counters[i].pcnt += tmp[i].pcnt;
1263 t->private->counters[i].bcnt += tmp[i].bcnt;
1264 }
1265
1266 write_unlock_bh(&t->lock);
1267 ret = 0;
1268unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001269 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270free_tmp:
1271 vfree(tmp);
1272 return ret;
1273}
1274
1275static inline int ebt_make_matchname(struct ebt_entry_match *m,
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 *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1280 return -EFAULT;
1281 return 0;
1282}
1283
1284static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001285 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
Al Viro1e419cd2006-11-30 19:28:48 -08001287 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1289 return -EFAULT;
1290 return 0;
1291}
1292
Al Viro1e419cd2006-11-30 19:28:48 -08001293static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
1295 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001296 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 struct ebt_entry_target *t;
1298
Al Viro40642f92006-11-30 19:24:12 -08001299 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 return 0;
1301
Al Viro1e419cd2006-11-30 19:28:48 -08001302 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1306 if (ret != 0)
1307 return ret;
1308 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1309 if (ret != 0)
1310 return ret;
1311 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1312 return -EFAULT;
1313 return 0;
1314}
1315
Ingo Molnar57b47a52006-03-20 22:35:41 -08001316/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1318 int *len, int cmd)
1319{
1320 struct ebt_replace tmp;
1321 struct ebt_counter *counterstmp, *oldcounters;
1322 unsigned int entries_size, nentries;
1323 char *entries;
1324
1325 if (cmd == EBT_SO_GET_ENTRIES) {
1326 entries_size = t->private->entries_size;
1327 nentries = t->private->nentries;
1328 entries = t->private->entries;
1329 oldcounters = t->private->counters;
1330 } else {
1331 entries_size = t->table->entries_size;
1332 nentries = t->table->nentries;
1333 entries = t->table->entries;
1334 oldcounters = t->table->counters;
1335 }
1336
1337 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1338 BUGPRINT("Cfu didn't work\n");
1339 return -EFAULT;
1340 }
1341
1342 if (*len != sizeof(struct ebt_replace) + entries_size +
1343 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1344 BUGPRINT("Wrong size\n");
1345 return -EINVAL;
1346 }
1347
1348 if (tmp.nentries != nentries) {
1349 BUGPRINT("Nentries wrong\n");
1350 return -EINVAL;
1351 }
1352
1353 if (tmp.entries_size != entries_size) {
1354 BUGPRINT("Wrong size\n");
1355 return -EINVAL;
1356 }
1357
1358 /* userspace might not need the counters */
1359 if (tmp.num_counters) {
1360 if (tmp.num_counters != nentries) {
1361 BUGPRINT("Num_counters wrong\n");
1362 return -EINVAL;
1363 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001364 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (!counterstmp) {
1366 MEMPRINT("Couldn't copy counters, out of memory\n");
1367 return -ENOMEM;
1368 }
1369 write_lock_bh(&t->lock);
1370 get_counters(oldcounters, counterstmp, nentries);
1371 write_unlock_bh(&t->lock);
1372
1373 if (copy_to_user(tmp.counters, counterstmp,
1374 nentries * sizeof(struct ebt_counter))) {
1375 BUGPRINT("Couldn't copy counters to userspace\n");
1376 vfree(counterstmp);
1377 return -EFAULT;
1378 }
1379 vfree(counterstmp);
1380 }
1381
1382 if (copy_to_user(tmp.entries, entries, entries_size)) {
1383 BUGPRINT("Couldn't copy entries to userspace\n");
1384 return -EFAULT;
1385 }
1386 /* set the match/watcher/target names right */
1387 return EBT_ENTRY_ITERATE(entries, entries_size,
1388 ebt_make_names, entries, tmp.entries);
1389}
1390
1391static int do_ebt_set_ctl(struct sock *sk,
1392 int cmd, void __user *user, unsigned int len)
1393{
1394 int ret;
1395
1396 switch(cmd) {
1397 case EBT_SO_SET_ENTRIES:
1398 ret = do_replace(user, len);
1399 break;
1400 case EBT_SO_SET_COUNTERS:
1401 ret = update_counters(user, len);
1402 break;
1403 default:
1404 ret = -EINVAL;
1405 }
1406 return ret;
1407}
1408
1409static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1410{
1411 int ret;
1412 struct ebt_replace tmp;
1413 struct ebt_table *t;
1414
1415 if (copy_from_user(&tmp, user, sizeof(tmp)))
1416 return -EFAULT;
1417
1418 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1419 if (!t)
1420 return ret;
1421
1422 switch(cmd) {
1423 case EBT_SO_GET_INFO:
1424 case EBT_SO_GET_INIT_INFO:
1425 if (*len != sizeof(struct ebt_replace)){
1426 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001427 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 break;
1429 }
1430 if (cmd == EBT_SO_GET_INFO) {
1431 tmp.nentries = t->private->nentries;
1432 tmp.entries_size = t->private->entries_size;
1433 tmp.valid_hooks = t->valid_hooks;
1434 } else {
1435 tmp.nentries = t->table->nentries;
1436 tmp.entries_size = t->table->entries_size;
1437 tmp.valid_hooks = t->table->valid_hooks;
1438 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001439 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 if (copy_to_user(user, &tmp, *len) != 0){
1441 BUGPRINT("c2u Didn't work\n");
1442 ret = -EFAULT;
1443 break;
1444 }
1445 ret = 0;
1446 break;
1447
1448 case EBT_SO_GET_ENTRIES:
1449 case EBT_SO_GET_INIT_ENTRIES:
1450 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001451 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 break;
1453
1454 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001455 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 ret = -EINVAL;
1457 }
1458
1459 return ret;
1460}
1461
1462static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001463{
1464 .pf = PF_INET,
1465 .set_optmin = EBT_BASE_CTL,
1466 .set_optmax = EBT_SO_SET_MAX + 1,
1467 .set = do_ebt_set_ctl,
1468 .get_optmin = EBT_BASE_CTL,
1469 .get_optmax = EBT_SO_GET_MAX + 1,
1470 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001471 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472};
1473
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001474static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475{
1476 int ret;
1477
Jan Engelhardt043ef462008-10-08 11:35:15 +02001478 ret = xt_register_target(&ebt_standard_target);
1479 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001481 ret = nf_register_sockopt(&ebt_sockopts);
1482 if (ret < 0) {
1483 xt_unregister_target(&ebt_standard_target);
1484 return ret;
1485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Patrick McHardya887c1c2007-07-14 20:46:15 -07001487 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 return 0;
1489}
1490
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001491static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
1493 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001494 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001495 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496}
1497
1498EXPORT_SYMBOL(ebt_register_table);
1499EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001501module_init(ebtables_init);
1502module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503MODULE_LICENSE("GPL");