blob: cf823c21c166696179c18b89b7f719a513d91978 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ebtables
3 *
4 * Author:
5 * Bart De Schuymer <bdschuym@pandora.be>
6 *
7 * ebtables.c,v 2.0, July, 2002
8 *
9 * This code is stongly inspired on the iptables code which is
10 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19#include <linux/kmod.h>
20#include <linux/module.h>
21#include <linux/vmalloc.h>
Jan Engelhardt18219d32008-10-08 11:35:13 +020022#include <linux/netfilter/x_tables.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netfilter_bridge/ebtables.h>
24#include <linux/spinlock.h>
Patrick McHardydf0933d2006-09-20 11:57:53 -070025#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/uaccess.h>
27#include <linux/smp.h>
David S. Millerc8923c62005-10-13 14:41:23 -070028#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/sock.h>
30/* needed for logical [in,out]-dev filtering */
31#include "../br_private.h"
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090034 "report to author: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* #define BUGPRINT(format, args...) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090037 ": out of memory: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/* #define MEMPRINT(format, args...) */
39
40
41
42/*
43 * Each cpu has its own set of counters, so there is no need for write_lock in
44 * the softirq
45 * For reading or updating the counters, the user context needs to
46 * get a write_lock
47 */
48
49/* The size of each set of counters is altered to get cache alignment */
50#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
51#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
52#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
53 COUNTER_OFFSET(n) * cpu))
54
55
56
Ingo Molnar57b47a52006-03-20 22:35:41 -080057static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static LIST_HEAD(ebt_tables);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Jan Engelhardt043ef462008-10-08 11:35:15 +020060static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020061 .name = "standard",
62 .revision = 0,
63 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020064 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020065};
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Jan Engelhardt7eb35582008-10-08 11:35:19 +020067static inline int
68ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
69 struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020071 par->target = w->u.watcher;
72 par->targinfo = w->data;
73 w->u.watcher->target(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 /* watchers don't give a verdict */
75 return 0;
76}
77
78static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020079 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020081 par->match = m->u.match;
82 par->matchinfo = m->data;
83 return m->u.match->match(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084}
85
86static inline int ebt_dev_check(char *entry, const struct net_device *device)
87{
88 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080089 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91 if (*entry == '\0')
92 return 0;
93 if (!device)
94 return 1;
95 /* 1 is the wildcard token */
96 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
97 i++;
98 return (devname[i] != entry[i] && entry[i] != 1);
99}
100
101#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
102/* process standard matches */
103static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
104 const struct net_device *in, const struct net_device *out)
105{
106 int verdict, i;
107
108 if (e->bitmask & EBT_802_3) {
109 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
110 return 1;
111 } else if (!(e->bitmask & EBT_NOPROTO) &&
112 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
113 return 1;
114
115 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
116 return 1;
117 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
118 return 1;
119 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
121 return 1;
122 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
123 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
124 return 1;
125
126 if (e->bitmask & EBT_SOURCEMAC) {
127 verdict = 0;
128 for (i = 0; i < 6; i++)
129 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
130 e->sourcemsk[i];
131 if (FWINV2(verdict != 0, EBT_ISOURCE) )
132 return 1;
133 }
134 if (e->bitmask & EBT_DESTMAC) {
135 verdict = 0;
136 for (i = 0; i < 6; i++)
137 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
138 e->destmsk[i];
139 if (FWINV2(verdict != 0, EBT_IDEST) )
140 return 1;
141 }
142 return 0;
143}
144
145/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700146unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 const struct net_device *in, const struct net_device *out,
148 struct ebt_table *table)
149{
150 int i, nentries;
151 struct ebt_entry *point;
152 struct ebt_counter *counter_base, *cb_base;
153 struct ebt_entry_target *t;
154 int verdict, sp = 0;
155 struct ebt_chainstack *cs;
156 struct ebt_entries *chaininfo;
157 char *base;
158 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200159 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200160 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200161 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200162
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200163 mtpar.in = tgpar.in = in;
164 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200165 mtpar.hotdrop = &hotdrop;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200166 tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 read_lock_bh(&table->lock);
169 private = table->private;
170 cb_base = COUNTER_BASE(private->counters, private->nentries,
171 smp_processor_id());
172 if (private->chainstack)
173 cs = private->chainstack[smp_processor_id()];
174 else
175 cs = NULL;
176 chaininfo = private->hook_entry[hook];
177 nentries = private->hook_entry[hook]->nentries;
178 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
179 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
180 /* base for chain jumps */
181 base = private->entries;
182 i = 0;
183 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700184 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 goto letscontinue;
186
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200187 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200189 if (hotdrop) {
190 read_unlock_bh(&table->lock);
191 return NF_DROP;
192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 /* increase counter */
195 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700196 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 /* these should only watch: not modify, nor tell us
199 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200200 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 t = (struct ebt_entry_target *)
203 (((char *)point) + point->target_offset);
204 /* standard target */
205 if (!t->u.target->target)
206 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200207 else {
208 tgpar.target = t->u.target;
209 tgpar.targinfo = t->data;
210 verdict = t->u.target->target(skb, &tgpar);
211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (verdict == EBT_ACCEPT) {
213 read_unlock_bh(&table->lock);
214 return NF_ACCEPT;
215 }
216 if (verdict == EBT_DROP) {
217 read_unlock_bh(&table->lock);
218 return NF_DROP;
219 }
220 if (verdict == EBT_RETURN) {
221letsreturn:
222#ifdef CONFIG_NETFILTER_DEBUG
223 if (sp == 0) {
224 BUGPRINT("RETURN on base chain");
225 /* act like this is EBT_CONTINUE */
226 goto letscontinue;
227 }
228#endif
229 sp--;
230 /* put all the local variables right */
231 i = cs[sp].n;
232 chaininfo = cs[sp].chaininfo;
233 nentries = chaininfo->nentries;
234 point = cs[sp].e;
235 counter_base = cb_base +
236 chaininfo->counter_offset;
237 continue;
238 }
239 if (verdict == EBT_CONTINUE)
240 goto letscontinue;
241#ifdef CONFIG_NETFILTER_DEBUG
242 if (verdict < 0) {
243 BUGPRINT("bogus standard verdict\n");
244 read_unlock_bh(&table->lock);
245 return NF_DROP;
246 }
247#endif
248 /* jump to a udc */
249 cs[sp].n = i + 1;
250 cs[sp].chaininfo = chaininfo;
251 cs[sp].e = (struct ebt_entry *)
252 (((char *)point) + point->next_offset);
253 i = 0;
254 chaininfo = (struct ebt_entries *) (base + verdict);
255#ifdef CONFIG_NETFILTER_DEBUG
256 if (chaininfo->distinguisher) {
257 BUGPRINT("jump to non-chain\n");
258 read_unlock_bh(&table->lock);
259 return NF_DROP;
260 }
261#endif
262 nentries = chaininfo->nentries;
263 point = (struct ebt_entry *)chaininfo->data;
264 counter_base = cb_base + chaininfo->counter_offset;
265 sp++;
266 continue;
267letscontinue:
268 point = (struct ebt_entry *)
269 (((char *)point) + point->next_offset);
270 i++;
271 }
272
273 /* I actually like this :) */
274 if (chaininfo->policy == EBT_RETURN)
275 goto letsreturn;
276 if (chaininfo->policy == EBT_ACCEPT) {
277 read_unlock_bh(&table->lock);
278 return NF_ACCEPT;
279 }
280 read_unlock_bh(&table->lock);
281 return NF_DROP;
282}
283
284/* If it succeeds, returns element and locks mutex */
285static inline void *
286find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800287 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700289 struct {
290 struct list_head list;
291 char name[EBT_FUNCTION_MAXNAMELEN];
292 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Ingo Molnar57b47a52006-03-20 22:35:41 -0800294 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 if (*error != 0)
296 return NULL;
297
Patrick McHardydf0933d2006-09-20 11:57:53 -0700298 list_for_each_entry(e, head, list) {
299 if (strcmp(e->name, name) == 0)
300 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700302 *error = -ENOENT;
303 mutex_unlock(mutex);
304 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
307#ifndef CONFIG_KMOD
308#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
309#else
310static void *
311find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800312 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 void *ret;
315
316 ret = find_inlist_lock_noload(head, name, error, mutex);
317 if (!ret) {
318 request_module("%s%s", prefix, name);
319 ret = find_inlist_lock_noload(head, name, error, mutex);
320 }
321 return ret;
322}
323#endif
324
325static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800326find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
329}
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200332ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
333 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200335 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200336 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800337 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 int ret;
339
Al Viro14197d52006-11-30 19:25:21 -0800340 if (left < sizeof(struct ebt_entry_match) ||
341 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200343
344 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
345 m->u.name, 0), "ebt_%s", m->u.name);
346 if (IS_ERR(match))
347 return PTR_ERR(match);
348 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200350 m->u.match = match;
351
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200352 par->match = match;
353 par->matchinfo = m->data;
354 ret = xt_check_match(par, NFPROTO_BRIDGE, m->match_size,
355 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200356 if (ret < 0) {
357 module_put(match->me);
358 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 (*cnt)++;
362 return 0;
363}
364
365static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200366ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
367 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200369 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200370 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800371 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int ret;
373
Al Viro14197d52006-11-30 19:25:21 -0800374 if (left < sizeof(struct ebt_entry_watcher) ||
375 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200377
378 watcher = try_then_request_module(
379 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
380 "ebt_%s", w->u.name);
381 if (IS_ERR(watcher))
382 return PTR_ERR(watcher);
383 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200385 w->u.watcher = watcher;
386
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200387 par->target = watcher;
388 par->targinfo = w->data;
389 ret = xt_check_target(par, NFPROTO_BRIDGE, w->watcher_size,
390 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200391 if (ret < 0) {
392 module_put(watcher->me);
393 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 (*cnt)++;
397 return 0;
398}
399
Al Viro70fe9af2006-11-30 19:26:14 -0800400static int ebt_verify_pointers(struct ebt_replace *repl,
401 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Al Viro70fe9af2006-11-30 19:26:14 -0800403 unsigned int limit = repl->entries_size;
404 unsigned int valid_hooks = repl->valid_hooks;
405 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 int i;
407
Al Viroe4fd77d2006-11-30 19:26:35 -0800408 for (i = 0; i < NF_BR_NUMHOOKS; i++)
409 newinfo->hook_entry[i] = NULL;
410
411 newinfo->entries_size = repl->entries_size;
412 newinfo->nentries = repl->nentries;
413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 while (offset < limit) {
415 size_t left = limit - offset;
416 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800417
Al Viro70fe9af2006-11-30 19:26:14 -0800418 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
Al Viro22b440b2006-11-30 19:25:51 -0800420
Al Viro70fe9af2006-11-30 19:26:14 -0800421 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
422 if ((valid_hooks & (1 << i)) == 0)
423 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800424 if ((char __user *)repl->hook_entry[i] ==
425 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800426 break;
427 }
428
429 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
430 if (e->bitmask != 0) {
431 /* we make userspace set this right,
432 so there is no misunderstanding */
433 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
434 "in distinguisher\n");
435 return -EINVAL;
436 }
437 if (i != NF_BR_NUMHOOKS)
438 newinfo->hook_entry[i] = (struct ebt_entries *)e;
439 if (left < sizeof(struct ebt_entries))
440 break;
441 offset += sizeof(struct ebt_entries);
442 } else {
443 if (left < sizeof(struct ebt_entry))
444 break;
445 if (left < e->next_offset)
446 break;
447 offset += e->next_offset;
448 }
449 }
450 if (offset != limit) {
451 BUGPRINT("entries_size too small\n");
452 return -EINVAL;
453 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800454
455 /* check if all valid hooks have a chain */
456 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
457 if (!newinfo->hook_entry[i] &&
458 (valid_hooks & (1 << i))) {
459 BUGPRINT("Valid hook without chain\n");
460 return -EINVAL;
461 }
462 }
Al Viro70fe9af2006-11-30 19:26:14 -0800463 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800464}
465
466/*
467 * this one is very careful, as it is the first function
468 * to parse the userspace data
469 */
470static inline int
471ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800472 struct ebt_table_info *newinfo,
473 unsigned int *n, unsigned int *cnt,
474 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800475{
Al Viro22b440b2006-11-30 19:25:51 -0800476 int i;
477
478 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800479 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800480 break;
481 }
482 /* beginning of a new chain
483 if i == NF_BR_NUMHOOKS it must be a user defined chain */
484 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 /* this checks if the previous chain has as many entries
486 as it said it has */
487 if (*n != *cnt) {
488 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900489 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return -EINVAL;
491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
493 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
494 /* only RETURN from udc */
495 if (i != NF_BR_NUMHOOKS ||
496 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
497 BUGPRINT("bad policy\n");
498 return -EINVAL;
499 }
500 }
501 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
502 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
504 BUGPRINT("counter_offset != totalcnt");
505 return -EINVAL;
506 }
507 *n = ((struct ebt_entries *)e)->nentries;
508 *cnt = 0;
509 return 0;
510 }
511 /* a plain old entry, heh */
512 if (sizeof(struct ebt_entry) > e->watchers_offset ||
513 e->watchers_offset > e->target_offset ||
514 e->target_offset >= e->next_offset) {
515 BUGPRINT("entry offsets not in right order\n");
516 return -EINVAL;
517 }
518 /* this is not checked anywhere else */
519 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
520 BUGPRINT("target size too small\n");
521 return -EINVAL;
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 (*cnt)++;
524 (*totalcnt)++;
525 return 0;
526}
527
528struct ebt_cl_stack
529{
530 struct ebt_chainstack cs;
531 int from;
532 unsigned int hookmask;
533};
534
535/*
536 * we need these positions to check that the jumps to a different part of the
537 * entries is a jump to the beginning of a new chain.
538 */
539static inline int
540ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800541 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 int i;
544
545 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800546 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return 0;
548 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
550 break;
551 }
552 /* only care about udc */
553 if (i != NF_BR_NUMHOOKS)
554 return 0;
555
556 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
557 /* these initialisations are depended on later in check_chainloops() */
558 udc[*n].cs.n = 0;
559 udc[*n].hookmask = 0;
560
561 (*n)++;
562 return 0;
563}
564
565static inline int
566ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
567{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200568 struct xt_mtdtor_param par;
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (i && (*i)-- == 0)
571 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200573 par.match = m->u.match;
574 par.matchinfo = m->data;
575 if (par.match->destroy != NULL)
576 par.match->destroy(&par);
577 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return 0;
579}
580
581static inline int
582ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
583{
584 if (i && (*i)-- == 0)
585 return 1;
586 if (w->u.watcher->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200587 w->u.watcher->destroy(w->u.watcher, w->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 module_put(w->u.watcher->me);
589
590 return 0;
591}
592
593static inline int
594ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
595{
596 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);
606 if (t->u.target->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200607 t->u.target->destroy(t->u.target, t->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 module_put(t->u.target->me);
609
610 return 0;
611}
612
613static inline int
614ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800615 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
617{
618 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200619 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800621 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200623 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200624 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800627 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return 0;
629
630 if (e->bitmask & ~EBT_F_MASK) {
631 BUGPRINT("Unknown flag for bitmask\n");
632 return -EINVAL;
633 }
634 if (e->invflags & ~EBT_INV_MASK) {
635 BUGPRINT("Unknown flag for inv bitmask\n");
636 return -EINVAL;
637 }
638 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
639 BUGPRINT("NOPROTO & 802_3 not allowed\n");
640 return -EINVAL;
641 }
642 /* what hook do we belong to? */
643 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800644 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 continue;
646 if ((char *)newinfo->hook_entry[i] < (char *)e)
647 hook = i;
648 else
649 break;
650 }
651 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
652 a base chain */
653 if (i < NF_BR_NUMHOOKS)
654 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
655 else {
656 for (i = 0; i < udc_cnt; i++)
657 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
658 break;
659 if (i == 0)
660 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
661 else
662 hookmask = cl_s[i - 1].hookmask;
663 }
664 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200665
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200666 mtpar.table = tgpar.table = name;
667 mtpar.entryinfo = tgpar.entryinfo = e;
668 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200669 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if (ret != 0)
671 goto cleanup_matches;
672 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200673 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (ret != 0)
675 goto cleanup_watchers;
676 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800677 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Jan Engelhardt043ef462008-10-08 11:35:15 +0200679 target = try_then_request_module(
680 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
681 "ebt_%s", t->u.name);
682 if (IS_ERR(target)) {
683 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200684 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200685 } else if (target == NULL) {
686 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200687 goto cleanup_watchers;
688 }
689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 t->u.target = target;
691 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800692 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 BUGPRINT("Standard target size too big\n");
694 ret = -EFAULT;
695 goto cleanup_watchers;
696 }
697 if (((struct ebt_standard_target *)t)->verdict <
698 -NUM_STANDARD_TARGETS) {
699 BUGPRINT("Invalid standard target\n");
700 ret = -EFAULT;
701 goto cleanup_watchers;
702 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200703 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
704 module_put(t->u.target->me);
705 ret = -EFAULT;
706 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200707 }
708
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200709 tgpar.target = target;
710 tgpar.targinfo = t->data;
711 ret = xt_check_target(&tgpar, NFPROTO_BRIDGE, t->target_size,
712 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200713 if (ret < 0) {
714 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200715 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
717 (*cnt)++;
718 return 0;
719cleanup_watchers:
720 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
721cleanup_matches:
722 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
723 return ret;
724}
725
726/*
727 * checks for loops and sets the hook mask for udc
728 * the hook mask for udc tells us from which base chains the udc can be
729 * accessed. This mask is a parameter to the check() functions of the extensions
730 */
731static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
732 unsigned int udc_cnt, unsigned int hooknr, char *base)
733{
734 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
735 struct ebt_entry *e = (struct ebt_entry *)chain->data;
736 struct ebt_entry_target *t;
737
738 while (pos < nentries || chain_nr != -1) {
739 /* end of udc, go back one 'recursion' step */
740 if (pos == nentries) {
741 /* put back values of the time when this chain was called */
742 e = cl_s[chain_nr].cs.e;
743 if (cl_s[chain_nr].from != -1)
744 nentries =
745 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
746 else
747 nentries = chain->nentries;
748 pos = cl_s[chain_nr].cs.n;
749 /* make sure we won't see a loop that isn't one */
750 cl_s[chain_nr].cs.n = 0;
751 chain_nr = cl_s[chain_nr].from;
752 if (pos == nentries)
753 continue;
754 }
755 t = (struct ebt_entry_target *)
756 (((char *)e) + e->target_offset);
757 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
758 goto letscontinue;
759 if (e->target_offset + sizeof(struct ebt_standard_target) >
760 e->next_offset) {
761 BUGPRINT("Standard target size too big\n");
762 return -1;
763 }
764 verdict = ((struct ebt_standard_target *)t)->verdict;
765 if (verdict >= 0) { /* jump to another chain */
766 struct ebt_entries *hlp2 =
767 (struct ebt_entries *)(base + verdict);
768 for (i = 0; i < udc_cnt; i++)
769 if (hlp2 == cl_s[i].cs.chaininfo)
770 break;
771 /* bad destination or loop */
772 if (i == udc_cnt) {
773 BUGPRINT("bad destination\n");
774 return -1;
775 }
776 if (cl_s[i].cs.n) {
777 BUGPRINT("loop\n");
778 return -1;
779 }
Al Viro98a08242006-11-30 19:24:49 -0800780 if (cl_s[i].hookmask & (1 << hooknr))
781 goto letscontinue;
782 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 cl_s[i].cs.n = pos + 1;
784 pos = 0;
785 cl_s[i].cs.e = ((void *)e + e->next_offset);
786 e = (struct ebt_entry *)(hlp2->data);
787 nentries = hlp2->nentries;
788 cl_s[i].from = chain_nr;
789 chain_nr = i;
790 /* this udc is accessible from the base chain for hooknr */
791 cl_s[i].hookmask |= (1 << hooknr);
792 continue;
793 }
794letscontinue:
795 e = (void *)e + e->next_offset;
796 pos++;
797 }
798 return 0;
799}
800
801/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800802static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 unsigned int i, j, k, udc_cnt;
805 int ret;
806 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
807
808 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800809 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 i++;
811 if (i == NF_BR_NUMHOOKS) {
812 BUGPRINT("No valid hooks specified\n");
813 return -EINVAL;
814 }
Al Viro1f072c92006-11-30 19:26:53 -0800815 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 BUGPRINT("Chains don't start at beginning\n");
817 return -EINVAL;
818 }
819 /* make sure chains are ordered after each other in same order
820 as their corresponding hooks */
821 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800822 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800824 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 BUGPRINT("Hook order must be followed\n");
826 return -EINVAL;
827 }
828 i = j;
829 }
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 /* do some early checkings and initialize some things */
832 i = 0; /* holds the expected nr. of entries for the chain */
833 j = 0; /* holds the up to now counted entries for the chain */
834 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900835 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
837 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800838 ebt_check_entry_size_and_hooks, newinfo,
839 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 if (ret != 0)
842 return ret;
843
844 if (i != j) {
845 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900846 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 return -EINVAL;
848 }
849 if (k != newinfo->nentries) {
850 BUGPRINT("Total nentries is wrong\n");
851 return -EINVAL;
852 }
853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 /* get the location of the udc, put them in an array
855 while we're at it, allocate the chainstack */
856 if (udc_cnt) {
857 /* this will get free'd in do_replace()/ebt_register_table()
858 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700859 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800860 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 if (!newinfo->chainstack)
862 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700863 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700865 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (!newinfo->chainstack[i]) {
867 while (i)
868 vfree(newinfo->chainstack[--i]);
869 vfree(newinfo->chainstack);
870 newinfo->chainstack = NULL;
871 return -ENOMEM;
872 }
873 }
874
Jayachandran C18bc89a2006-04-20 00:14:49 -0700875 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (!cl_s)
877 return -ENOMEM;
878 i = 0; /* the i'th udc */
879 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800880 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 /* sanity check */
882 if (i != udc_cnt) {
883 BUGPRINT("i != udc_cnt\n");
884 vfree(cl_s);
885 return -EFAULT;
886 }
887 }
888
889 /* Check for loops */
890 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800891 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (check_chainloops(newinfo->hook_entry[i],
893 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700894 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 return -EINVAL;
896 }
897
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200898 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 - the nr of entries in each chain is right
900 - the size of the allocated space is right
901 - all valid hooks have a corresponding chain
902 - there are no loops
903 - wrong data can still be on the level of a single entry
904 - could be there are jumps to places that are not the
905 beginning of a chain. This can only occur in chains that
906 are not accessible from any base chains, so we don't care. */
907
908 /* used to know what we need to clean up if something goes wrong */
909 i = 0;
910 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800911 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (ret != 0) {
913 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
914 ebt_cleanup_entry, &i);
915 }
James Lamanna68d31872005-06-22 22:12:57 -0700916 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return ret;
918}
919
920/* called under write_lock */
921static void get_counters(struct ebt_counter *oldcounters,
922 struct ebt_counter *counters, unsigned int nentries)
923{
924 int i, cpu;
925 struct ebt_counter *counter_base;
926
927 /* counters of cpu 0 */
928 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700929 sizeof(struct ebt_counter) * nentries);
930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700932 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700933 if (cpu == 0)
934 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
936 for (i = 0; i < nentries; i++) {
937 counters[i].pcnt += counter_base[i].pcnt;
938 counters[i].bcnt += counter_base[i].bcnt;
939 }
940 }
941}
942
943/* replace the table */
944static int do_replace(void __user *user, unsigned int len)
945{
946 int ret, i, countersize;
947 struct ebt_table_info *newinfo;
948 struct ebt_replace tmp;
949 struct ebt_table *t;
950 struct ebt_counter *counterstmp = NULL;
951 /* used to be able to unlock earlier */
952 struct ebt_table_info *table;
953
954 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
955 return -EFAULT;
956
957 if (len != sizeof(tmp) + tmp.entries_size) {
958 BUGPRINT("Wrong len argument\n");
959 return -EINVAL;
960 }
961
962 if (tmp.entries_size == 0) {
963 BUGPRINT("Entries_size never zero\n");
964 return -EINVAL;
965 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800966 /* overflow check */
967 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
968 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
969 return -ENOMEM;
970 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
971 return -ENOMEM;
972
Christoph Lameter53b8a312007-02-20 13:57:51 -0800973 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700974 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (!newinfo)
976 return -ENOMEM;
977
978 if (countersize)
979 memset(newinfo->counters, 0, countersize);
980
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800981 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (!newinfo->entries) {
983 ret = -ENOMEM;
984 goto free_newinfo;
985 }
986 if (copy_from_user(
987 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
988 BUGPRINT("Couldn't copy entries from userspace\n");
989 ret = -EFAULT;
990 goto free_entries;
991 }
992
993 /* the user wants counters back
994 the check on the size is done later, when we have the lock */
995 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700996 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 if (!counterstmp) {
998 ret = -ENOMEM;
999 goto free_entries;
1000 }
1001 }
1002 else
1003 counterstmp = NULL;
1004
1005 /* this can get initialized by translate_table() */
1006 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001007 ret = ebt_verify_pointers(&tmp, newinfo);
1008 if (ret != 0)
1009 goto free_counterstmp;
1010
1011 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 if (ret != 0)
1014 goto free_counterstmp;
1015
1016 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1017 if (!t) {
1018 ret = -ENOENT;
1019 goto free_iterate;
1020 }
1021
1022 /* the table doesn't like it */
1023 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1024 goto free_unlock;
1025
1026 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1027 BUGPRINT("Wrong nr. of counters requested\n");
1028 ret = -EINVAL;
1029 goto free_unlock;
1030 }
1031
1032 /* we have the mutex lock, so no danger in reading this pointer */
1033 table = t->private;
1034 /* make sure the table can only be rmmod'ed if it contains no rules */
1035 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1036 ret = -ENOENT;
1037 goto free_unlock;
1038 } else if (table->nentries && !newinfo->nentries)
1039 module_put(t->me);
1040 /* we need an atomic snapshot of the counters */
1041 write_lock_bh(&t->lock);
1042 if (tmp.num_counters)
1043 get_counters(t->private->counters, counterstmp,
1044 t->private->nentries);
1045
1046 t->private = newinfo;
1047 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001048 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 /* so, a user can change the chains while having messed up her counter
1050 allocation. Only reason why this is done is because this way the lock
1051 is held only once, while this doesn't bring the kernel into a
1052 dangerous state. */
1053 if (tmp.num_counters &&
1054 copy_to_user(tmp.counters, counterstmp,
1055 tmp.num_counters * sizeof(struct ebt_counter))) {
1056 BUGPRINT("Couldn't copy counters to userspace\n");
1057 ret = -EFAULT;
1058 }
1059 else
1060 ret = 0;
1061
1062 /* decrease module count and free resources */
1063 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1064 ebt_cleanup_entry, NULL);
1065
1066 vfree(table->entries);
1067 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001068 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 vfree(table->chainstack[i]);
1070 vfree(table->chainstack);
1071 }
1072 vfree(table);
1073
James Lamanna68d31872005-06-22 22:12:57 -07001074 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 return ret;
1076
1077free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001078 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079free_iterate:
1080 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1081 ebt_cleanup_entry, NULL);
1082free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001083 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 /* can be initialized in translate_table() */
1085 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001086 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 vfree(newinfo->chainstack[i]);
1088 vfree(newinfo->chainstack);
1089 }
1090free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001091 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001093 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return ret;
1095}
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097int ebt_register_table(struct ebt_table *table)
1098{
1099 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001100 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001101 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001103 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Al Virodf07a812006-11-30 19:28:25 -08001105 if (!table || !(repl = table->table) || !repl->entries ||
1106 repl->entries_size == 0 ||
1107 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1109 return -EINVAL;
1110 }
1111
Christoph Lameter53b8a312007-02-20 13:57:51 -08001112 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001113 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 ret = -ENOMEM;
1115 if (!newinfo)
1116 return -ENOMEM;
1117
Al Virodf07a812006-11-30 19:28:25 -08001118 p = vmalloc(repl->entries_size);
1119 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 goto free_newinfo;
1121
Al Virodf07a812006-11-30 19:28:25 -08001122 memcpy(p, repl->entries, repl->entries_size);
1123 newinfo->entries = p;
1124
1125 newinfo->entries_size = repl->entries_size;
1126 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 if (countersize)
1129 memset(newinfo->counters, 0, countersize);
1130
1131 /* fill in newinfo and parse the entries */
1132 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001133 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1134 if ((repl->valid_hooks & (1 << i)) == 0)
1135 newinfo->hook_entry[i] = NULL;
1136 else
1137 newinfo->hook_entry[i] = p +
1138 ((char *)repl->hook_entry[i] - repl->entries);
1139 }
1140 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 if (ret != 0) {
1142 BUGPRINT("Translate_table failed\n");
1143 goto free_chainstack;
1144 }
1145
1146 if (table->check && table->check(newinfo, table->valid_hooks)) {
1147 BUGPRINT("The table doesn't like its own initial data, lol\n");
1148 return -EINVAL;
1149 }
1150
1151 table->private = newinfo;
1152 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001153 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (ret != 0)
1155 goto free_chainstack;
1156
Patrick McHardydf0933d2006-09-20 11:57:53 -07001157 list_for_each_entry(t, &ebt_tables, list) {
1158 if (strcmp(t->name, table->name) == 0) {
1159 ret = -EEXIST;
1160 BUGPRINT("Table name already exists\n");
1161 goto free_unlock;
1162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
1164
1165 /* Hold a reference count if the chains aren't empty */
1166 if (newinfo->nentries && !try_module_get(table->me)) {
1167 ret = -ENOENT;
1168 goto free_unlock;
1169 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001170 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001171 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return 0;
1173free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001174 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175free_chainstack:
1176 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001177 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 vfree(newinfo->chainstack[i]);
1179 vfree(newinfo->chainstack);
1180 }
1181 vfree(newinfo->entries);
1182free_newinfo:
1183 vfree(newinfo);
1184 return ret;
1185}
1186
1187void ebt_unregister_table(struct ebt_table *table)
1188{
1189 int i;
1190
1191 if (!table) {
1192 BUGPRINT("Request to unregister NULL table!!!\n");
1193 return;
1194 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001195 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001196 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001197 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001198 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001200 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 vfree(table->private->chainstack[i]);
1202 vfree(table->private->chainstack);
1203 }
1204 vfree(table->private);
1205}
1206
1207/* userspace just supplied us with counters */
1208static int update_counters(void __user *user, unsigned int len)
1209{
1210 int i, ret;
1211 struct ebt_counter *tmp;
1212 struct ebt_replace hlp;
1213 struct ebt_table *t;
1214
1215 if (copy_from_user(&hlp, user, sizeof(hlp)))
1216 return -EFAULT;
1217
1218 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1219 return -EINVAL;
1220 if (hlp.num_counters == 0)
1221 return -EINVAL;
1222
Jayachandran C18bc89a2006-04-20 00:14:49 -07001223 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 MEMPRINT("Update_counters && nomemory\n");
1225 return -ENOMEM;
1226 }
1227
1228 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1229 if (!t)
1230 goto free_tmp;
1231
1232 if (hlp.num_counters != t->private->nentries) {
1233 BUGPRINT("Wrong nr of counters\n");
1234 ret = -EINVAL;
1235 goto unlock_mutex;
1236 }
1237
1238 if ( copy_from_user(tmp, hlp.counters,
1239 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1240 BUGPRINT("Updata_counters && !cfu\n");
1241 ret = -EFAULT;
1242 goto unlock_mutex;
1243 }
1244
1245 /* we want an atomic add of the counters */
1246 write_lock_bh(&t->lock);
1247
1248 /* we add to the counters of the first cpu */
1249 for (i = 0; i < hlp.num_counters; i++) {
1250 t->private->counters[i].pcnt += tmp[i].pcnt;
1251 t->private->counters[i].bcnt += tmp[i].bcnt;
1252 }
1253
1254 write_unlock_bh(&t->lock);
1255 ret = 0;
1256unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001257 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258free_tmp:
1259 vfree(tmp);
1260 return ret;
1261}
1262
1263static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001264 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265{
Al Viro1e419cd2006-11-30 19:28:48 -08001266 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1268 return -EFAULT;
1269 return 0;
1270}
1271
1272static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001273 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
Al Viro1e419cd2006-11-30 19:28:48 -08001275 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1277 return -EFAULT;
1278 return 0;
1279}
1280
Al Viro1e419cd2006-11-30 19:28:48 -08001281static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
1283 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001284 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 struct ebt_entry_target *t;
1286
Al Viro40642f92006-11-30 19:24:12 -08001287 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 return 0;
1289
Al Viro1e419cd2006-11-30 19:28:48 -08001290 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1294 if (ret != 0)
1295 return ret;
1296 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1297 if (ret != 0)
1298 return ret;
1299 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1300 return -EFAULT;
1301 return 0;
1302}
1303
Ingo Molnar57b47a52006-03-20 22:35:41 -08001304/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1306 int *len, int cmd)
1307{
1308 struct ebt_replace tmp;
1309 struct ebt_counter *counterstmp, *oldcounters;
1310 unsigned int entries_size, nentries;
1311 char *entries;
1312
1313 if (cmd == EBT_SO_GET_ENTRIES) {
1314 entries_size = t->private->entries_size;
1315 nentries = t->private->nentries;
1316 entries = t->private->entries;
1317 oldcounters = t->private->counters;
1318 } else {
1319 entries_size = t->table->entries_size;
1320 nentries = t->table->nentries;
1321 entries = t->table->entries;
1322 oldcounters = t->table->counters;
1323 }
1324
1325 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1326 BUGPRINT("Cfu didn't work\n");
1327 return -EFAULT;
1328 }
1329
1330 if (*len != sizeof(struct ebt_replace) + entries_size +
1331 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1332 BUGPRINT("Wrong size\n");
1333 return -EINVAL;
1334 }
1335
1336 if (tmp.nentries != nentries) {
1337 BUGPRINT("Nentries wrong\n");
1338 return -EINVAL;
1339 }
1340
1341 if (tmp.entries_size != entries_size) {
1342 BUGPRINT("Wrong size\n");
1343 return -EINVAL;
1344 }
1345
1346 /* userspace might not need the counters */
1347 if (tmp.num_counters) {
1348 if (tmp.num_counters != nentries) {
1349 BUGPRINT("Num_counters wrong\n");
1350 return -EINVAL;
1351 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001352 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if (!counterstmp) {
1354 MEMPRINT("Couldn't copy counters, out of memory\n");
1355 return -ENOMEM;
1356 }
1357 write_lock_bh(&t->lock);
1358 get_counters(oldcounters, counterstmp, nentries);
1359 write_unlock_bh(&t->lock);
1360
1361 if (copy_to_user(tmp.counters, counterstmp,
1362 nentries * sizeof(struct ebt_counter))) {
1363 BUGPRINT("Couldn't copy counters to userspace\n");
1364 vfree(counterstmp);
1365 return -EFAULT;
1366 }
1367 vfree(counterstmp);
1368 }
1369
1370 if (copy_to_user(tmp.entries, entries, entries_size)) {
1371 BUGPRINT("Couldn't copy entries to userspace\n");
1372 return -EFAULT;
1373 }
1374 /* set the match/watcher/target names right */
1375 return EBT_ENTRY_ITERATE(entries, entries_size,
1376 ebt_make_names, entries, tmp.entries);
1377}
1378
1379static int do_ebt_set_ctl(struct sock *sk,
1380 int cmd, void __user *user, unsigned int len)
1381{
1382 int ret;
1383
1384 switch(cmd) {
1385 case EBT_SO_SET_ENTRIES:
1386 ret = do_replace(user, len);
1387 break;
1388 case EBT_SO_SET_COUNTERS:
1389 ret = update_counters(user, len);
1390 break;
1391 default:
1392 ret = -EINVAL;
1393 }
1394 return ret;
1395}
1396
1397static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1398{
1399 int ret;
1400 struct ebt_replace tmp;
1401 struct ebt_table *t;
1402
1403 if (copy_from_user(&tmp, user, sizeof(tmp)))
1404 return -EFAULT;
1405
1406 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1407 if (!t)
1408 return ret;
1409
1410 switch(cmd) {
1411 case EBT_SO_GET_INFO:
1412 case EBT_SO_GET_INIT_INFO:
1413 if (*len != sizeof(struct ebt_replace)){
1414 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001415 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 break;
1417 }
1418 if (cmd == EBT_SO_GET_INFO) {
1419 tmp.nentries = t->private->nentries;
1420 tmp.entries_size = t->private->entries_size;
1421 tmp.valid_hooks = t->valid_hooks;
1422 } else {
1423 tmp.nentries = t->table->nentries;
1424 tmp.entries_size = t->table->entries_size;
1425 tmp.valid_hooks = t->table->valid_hooks;
1426 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001427 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 if (copy_to_user(user, &tmp, *len) != 0){
1429 BUGPRINT("c2u Didn't work\n");
1430 ret = -EFAULT;
1431 break;
1432 }
1433 ret = 0;
1434 break;
1435
1436 case EBT_SO_GET_ENTRIES:
1437 case EBT_SO_GET_INIT_ENTRIES:
1438 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001439 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 break;
1441
1442 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001443 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 ret = -EINVAL;
1445 }
1446
1447 return ret;
1448}
1449
1450static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001451{
1452 .pf = PF_INET,
1453 .set_optmin = EBT_BASE_CTL,
1454 .set_optmax = EBT_SO_SET_MAX + 1,
1455 .set = do_ebt_set_ctl,
1456 .get_optmin = EBT_BASE_CTL,
1457 .get_optmax = EBT_SO_GET_MAX + 1,
1458 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001459 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460};
1461
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001462static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463{
1464 int ret;
1465
Jan Engelhardt043ef462008-10-08 11:35:15 +02001466 ret = xt_register_target(&ebt_standard_target);
1467 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001469 ret = nf_register_sockopt(&ebt_sockopts);
1470 if (ret < 0) {
1471 xt_unregister_target(&ebt_standard_target);
1472 return ret;
1473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Patrick McHardya887c1c2007-07-14 20:46:15 -07001475 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 return 0;
1477}
1478
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001479static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480{
1481 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001482 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001483 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484}
1485
1486EXPORT_SYMBOL(ebt_register_table);
1487EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001489module_init(ebtables_init);
1490module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491MODULE_LICENSE("GPL");