netfilter: xt_conntrack: support matching on port ranges
[linux-2.6-block.git] / net / ipv6 / netfilter / ip6_tables.c
CommitLineData
1da177e4
LT
1/*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
6b7d31fc 5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
1da177e4
LT
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
1da177e4 10 */
90e7d4ab 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4fc268d2 12#include <linux/capability.h>
14c85021 13#include <linux/in.h>
1da177e4
LT
14#include <linux/skbuff.h>
15#include <linux/kmod.h>
16#include <linux/vmalloc.h>
17#include <linux/netdevice.h>
18#include <linux/module.h>
4bdbf6c0 19#include <linux/poison.h>
1da177e4 20#include <linux/icmpv6.h>
1da177e4 21#include <net/ipv6.h>
3bc3fe5e 22#include <net/compat.h>
1da177e4 23#include <asm/uaccess.h>
57b47a53 24#include <linux/mutex.h>
1da177e4 25#include <linux/proc_fs.h>
3bc3fe5e 26#include <linux/err.h>
c8923c6b 27#include <linux/cpumask.h>
1da177e4
LT
28
29#include <linux/netfilter_ipv6/ip6_tables.h>
2e4e6a17 30#include <linux/netfilter/x_tables.h>
f01ffbd6 31#include <net/netfilter/nf_log.h>
e3eaa991 32#include "../../netfilter/xt_repldata.h"
1da177e4
LT
33
34MODULE_LICENSE("GPL");
35MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36MODULE_DESCRIPTION("IPv6 packet filter");
37
1da177e4
LT
38/*#define DEBUG_IP_FIREWALL*/
39/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
40/*#define DEBUG_IP_FIREWALL_USER*/
41
42#ifdef DEBUG_IP_FIREWALL
ff67e4e4 43#define dprintf(format, args...) pr_info(format , ## args)
1da177e4
LT
44#else
45#define dprintf(format, args...)
46#endif
47
48#ifdef DEBUG_IP_FIREWALL_USER
ff67e4e4 49#define duprintf(format, args...) pr_info(format , ## args)
1da177e4
LT
50#else
51#define duprintf(format, args...)
52#endif
53
54#ifdef CONFIG_NETFILTER_DEBUG
af567603 55#define IP_NF_ASSERT(x) WARN_ON(!(x))
1da177e4
LT
56#else
57#define IP_NF_ASSERT(x)
58#endif
1da177e4 59
1da177e4
LT
60#if 0
61/* All the better to debug you with... */
62#define static
63#define inline
64#endif
65
e3eaa991
JE
66void *ip6t_alloc_initial_table(const struct xt_table *info)
67{
68 return xt_alloc_initial_table(ip6t, IP6T);
69}
70EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
71
6b7d31fc 72/*
1da177e4 73 We keep a set of rules for each CPU, so we can avoid write-locking
6b7d31fc
HW
74 them in the softirq when updating the counters and therefore
75 only need to read-lock in the softirq; doing a write_lock_bh() in user
76 context stops packets coming through and allows user context to read
77 the counters or update the rules.
1da177e4 78
1da177e4
LT
79 Hence the start of any table is given by get_table() below. */
80
1da177e4 81/* Check for an extension */
1ab1457c 82int
1da177e4
LT
83ip6t_ext_hdr(u8 nexthdr)
84{
a02cec21
ED
85 return (nexthdr == IPPROTO_HOPOPTS) ||
86 (nexthdr == IPPROTO_ROUTING) ||
87 (nexthdr == IPPROTO_FRAGMENT) ||
88 (nexthdr == IPPROTO_ESP) ||
89 (nexthdr == IPPROTO_AH) ||
90 (nexthdr == IPPROTO_NONE) ||
91 (nexthdr == IPPROTO_DSTOPTS);
1da177e4
LT
92}
93
94/* Returns whether matches rule or not. */
022748a9 95/* Performance critical - called for every packet */
1d93a9cb 96static inline bool
1da177e4
LT
97ip6_packet_match(const struct sk_buff *skb,
98 const char *indev,
99 const char *outdev,
100 const struct ip6t_ip6 *ip6info,
101 unsigned int *protoff,
cff533ac 102 int *fragoff, bool *hotdrop)
1da177e4 103{
1da177e4 104 unsigned long ret;
0660e03f 105 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
1da177e4 106
e79ec50b 107#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
1da177e4 108
f2ffd9ee 109 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
3666ed1c
JP
110 &ip6info->src), IP6T_INV_SRCIP) ||
111 FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
112 &ip6info->dst), IP6T_INV_DSTIP)) {
1da177e4
LT
113 dprintf("Source or dest mismatch.\n");
114/*
115 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
116 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
117 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
118 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
119 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
120 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
1d93a9cb 121 return false;
1da177e4
LT
122 }
123
b8dfe498 124 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
1da177e4
LT
125
126 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
127 dprintf("VIA in mismatch (%s vs %s).%s\n",
128 indev, ip6info->iniface,
129 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
1d93a9cb 130 return false;
1da177e4
LT
131 }
132
b8dfe498 133 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
1da177e4
LT
134
135 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
136 dprintf("VIA out mismatch (%s vs %s).%s\n",
137 outdev, ip6info->outiface,
138 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
1d93a9cb 139 return false;
1da177e4
LT
140 }
141
142/* ... might want to do something with class and flowlabel here ... */
143
144 /* look for the desired protocol header */
145 if((ip6info->flags & IP6T_F_PROTO)) {
b777e0ce
PM
146 int protohdr;
147 unsigned short _frag_off;
1da177e4 148
b777e0ce 149 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
51d8b1a6
PM
150 if (protohdr < 0) {
151 if (_frag_off == 0)
cff533ac 152 *hotdrop = true;
1d93a9cb 153 return false;
51d8b1a6 154 }
b777e0ce 155 *fragoff = _frag_off;
1da177e4
LT
156
157 dprintf("Packet protocol %hi ?= %s%hi.\n",
1ab1457c 158 protohdr,
1da177e4
LT
159 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
160 ip6info->proto);
161
b777e0ce 162 if (ip6info->proto == protohdr) {
1da177e4 163 if(ip6info->invflags & IP6T_INV_PROTO) {
1d93a9cb 164 return false;
1da177e4 165 }
1d93a9cb 166 return true;
1da177e4
LT
167 }
168
169 /* We need match for the '-p all', too! */
170 if ((ip6info->proto != 0) &&
171 !(ip6info->invflags & IP6T_INV_PROTO))
1d93a9cb 172 return false;
1da177e4 173 }
1d93a9cb 174 return true;
1da177e4
LT
175}
176
177/* should be ip6 safe */
022748a9 178static bool
1da177e4
LT
179ip6_checkentry(const struct ip6t_ip6 *ipv6)
180{
181 if (ipv6->flags & ~IP6T_F_MASK) {
182 duprintf("Unknown flag bits set: %08X\n",
183 ipv6->flags & ~IP6T_F_MASK);
ccb79bdc 184 return false;
1da177e4
LT
185 }
186 if (ipv6->invflags & ~IP6T_INV_MASK) {
187 duprintf("Unknown invflag bits set: %08X\n",
188 ipv6->invflags & ~IP6T_INV_MASK);
ccb79bdc 189 return false;
1da177e4 190 }
ccb79bdc 191 return true;
1da177e4
LT
192}
193
194static unsigned int
4b560b44 195ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
1da177e4
LT
196{
197 if (net_ratelimit())
ff67e4e4 198 pr_info("error: `%s'\n", (const char *)par->targinfo);
1da177e4
LT
199
200 return NF_DROP;
201}
202
1da177e4 203static inline struct ip6t_entry *
d5d1baa1 204get_entry(const void *base, unsigned int offset)
1da177e4
LT
205{
206 return (struct ip6t_entry *)(base + offset);
207}
208
ba9dda3a 209/* All zeroes == unconditional rule. */
022748a9 210/* Mildly perf critical (only if packet tracing is on) */
47901dc2 211static inline bool unconditional(const struct ip6t_ip6 *ipv6)
ba9dda3a 212{
47901dc2 213 static const struct ip6t_ip6 uncond;
ba9dda3a 214
47901dc2 215 return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
ba9dda3a
JK
216}
217
87a2e70d 218static inline const struct xt_entry_target *
d5d1baa1
JE
219ip6t_get_target_c(const struct ip6t_entry *e)
220{
221 return ip6t_get_target((struct ip6t_entry *)e);
222}
223
ba9dda3a
JK
224#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
225 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
226/* This cries for unification! */
022748a9 227static const char *const hooknames[] = {
6e23ae2a
PM
228 [NF_INET_PRE_ROUTING] = "PREROUTING",
229 [NF_INET_LOCAL_IN] = "INPUT",
230 [NF_INET_FORWARD] = "FORWARD",
231 [NF_INET_LOCAL_OUT] = "OUTPUT",
232 [NF_INET_POST_ROUTING] = "POSTROUTING",
ba9dda3a
JK
233};
234
235enum nf_ip_trace_comments {
236 NF_IP6_TRACE_COMMENT_RULE,
237 NF_IP6_TRACE_COMMENT_RETURN,
238 NF_IP6_TRACE_COMMENT_POLICY,
239};
240
022748a9 241static const char *const comments[] = {
ba9dda3a
JK
242 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
243 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
244 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
245};
246
247static struct nf_loginfo trace_loginfo = {
248 .type = NF_LOG_TYPE_LOG,
249 .u = {
250 .log = {
251 .level = 4,
252 .logflags = NF_LOG_MASK,
253 },
254 },
255};
256
022748a9 257/* Mildly perf critical (only if packet tracing is on) */
ba9dda3a 258static inline int
d5d1baa1 259get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
4f2f6f23
JE
260 const char *hookname, const char **chainname,
261 const char **comment, unsigned int *rulenum)
ba9dda3a 262{
87a2e70d 263 const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
ba9dda3a 264
243bf6e2 265 if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
ba9dda3a
JK
266 /* Head of user chain: ERROR target with chainname */
267 *chainname = t->target.data;
268 (*rulenum) = 0;
269 } else if (s == e) {
270 (*rulenum)++;
271
3666ed1c
JP
272 if (s->target_offset == sizeof(struct ip6t_entry) &&
273 strcmp(t->target.u.kernel.target->name,
243bf6e2 274 XT_STANDARD_TARGET) == 0 &&
3666ed1c
JP
275 t->verdict < 0 &&
276 unconditional(&s->ipv6)) {
ba9dda3a
JK
277 /* Tail of chains: STANDARD target (return/policy) */
278 *comment = *chainname == hookname
4f2f6f23
JE
279 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
280 : comments[NF_IP6_TRACE_COMMENT_RETURN];
ba9dda3a
JK
281 }
282 return 1;
283 } else
284 (*rulenum)++;
285
286 return 0;
287}
288
d5d1baa1 289static void trace_packet(const struct sk_buff *skb,
ba9dda3a
JK
290 unsigned int hook,
291 const struct net_device *in,
292 const struct net_device *out,
ecb6f85e 293 const char *tablename,
d5d1baa1
JE
294 const struct xt_table_info *private,
295 const struct ip6t_entry *e)
ba9dda3a 296{
d5d1baa1 297 const void *table_base;
5452e425 298 const struct ip6t_entry *root;
4f2f6f23 299 const char *hookname, *chainname, *comment;
72b2b1dd 300 const struct ip6t_entry *iter;
ba9dda3a
JK
301 unsigned int rulenum = 0;
302
ccf5bd8c 303 table_base = private->entries[smp_processor_id()];
ba9dda3a
JK
304 root = get_entry(table_base, private->hook_entry[hook]);
305
4f2f6f23
JE
306 hookname = chainname = hooknames[hook];
307 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
ba9dda3a 308
72b2b1dd
JE
309 xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
310 if (get_chainname_rulenum(iter, e, hookname,
311 &chainname, &comment, &rulenum) != 0)
312 break;
ba9dda3a
JK
313
314 nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
315 "TRACE: %s:%s:%s:%u ",
316 tablename, chainname, comment, rulenum);
317}
318#endif
319
98e86403
JE
320static inline __pure struct ip6t_entry *
321ip6t_next_entry(const struct ip6t_entry *entry)
322{
323 return (void *)entry + entry->next_offset;
324}
325
1da177e4
LT
326/* Returns one of the generic firewall policies, like NF_ACCEPT. */
327unsigned int
3db05fea 328ip6t_do_table(struct sk_buff *skb,
1da177e4
LT
329 unsigned int hook,
330 const struct net_device *in,
331 const struct net_device *out,
fe1cb108 332 struct xt_table *table)
1da177e4 333{
6b7d31fc 334 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
1da177e4
LT
335 /* Initializing verdict to NF_DROP keeps gcc happy. */
336 unsigned int verdict = NF_DROP;
337 const char *indev, *outdev;
d5d1baa1 338 const void *table_base;
f3c5c1bf
JE
339 struct ip6t_entry *e, **jumpstack;
340 unsigned int *stackptr, origptr, cpu;
d5d1baa1 341 const struct xt_table_info *private;
de74c169 342 struct xt_action_param acpar;
1da177e4
LT
343
344 /* Initialization */
345 indev = in ? in->name : nulldevname;
346 outdev = out ? out->name : nulldevname;
1da177e4
LT
347 /* We handle fragments by dealing with the first fragment as
348 * if it was a normal packet. All other fragments are treated
349 * normally, except that they will NEVER match rules that ask
350 * things we don't know, ie. tcp syn flag or ports). If the
351 * rule is also a fragment-specific rule, non-fragments won't
352 * match it. */
b4ba2611 353 acpar.hotdrop = false;
de74c169
JE
354 acpar.in = in;
355 acpar.out = out;
356 acpar.family = NFPROTO_IPV6;
357 acpar.hooknum = hook;
1da177e4 358
1da177e4 359 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
78454473 360
942e4a2b
SH
361 xt_info_rdlock_bh();
362 private = table->private;
f3c5c1bf
JE
363 cpu = smp_processor_id();
364 table_base = private->entries[cpu];
365 jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
7489aec8 366 stackptr = per_cpu_ptr(private->stackptr, cpu);
f3c5c1bf 367 origptr = *stackptr;
78454473 368
2e4e6a17 369 e = get_entry(table_base, private->hook_entry[hook]);
1da177e4 370
1da177e4 371 do {
87a2e70d 372 const struct xt_entry_target *t;
dcea992a 373 const struct xt_entry_match *ematch;
a1ff4ac8 374
1da177e4 375 IP_NF_ASSERT(e);
a1ff4ac8 376 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
b4ba2611 377 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
dcea992a 378 no_match:
a1ff4ac8
JE
379 e = ip6t_next_entry(e);
380 continue;
381 }
1da177e4 382
ef53d702 383 xt_ematch_foreach(ematch, e) {
de74c169
JE
384 acpar.match = ematch->u.kernel.match;
385 acpar.matchinfo = ematch->data;
386 if (!acpar.match->match(skb, &acpar))
dcea992a 387 goto no_match;
ef53d702 388 }
dcea992a 389
261abc8c 390 ADD_COUNTER(e->counters, skb->len, 1);
1da177e4 391
d5d1baa1 392 t = ip6t_get_target_c(e);
a1ff4ac8 393 IP_NF_ASSERT(t->u.kernel.target);
ba9dda3a
JK
394
395#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
396 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
a1ff4ac8
JE
397 /* The packet is traced: log it */
398 if (unlikely(skb->nf_trace))
399 trace_packet(skb, hook, in, out,
400 table->name, private, e);
ba9dda3a 401#endif
a1ff4ac8
JE
402 /* Standard target? */
403 if (!t->u.kernel.target->target) {
404 int v;
405
87a2e70d 406 v = ((struct xt_standard_target *)t)->verdict;
a1ff4ac8
JE
407 if (v < 0) {
408 /* Pop from stack? */
243bf6e2 409 if (v != XT_RETURN) {
a1ff4ac8
JE
410 verdict = (unsigned)(-v) - 1;
411 break;
1da177e4 412 }
f3c5c1bf
JE
413 if (*stackptr == 0)
414 e = get_entry(table_base,
415 private->underflow[hook]);
416 else
417 e = ip6t_next_entry(jumpstack[--*stackptr]);
a1ff4ac8
JE
418 continue;
419 }
3666ed1c
JP
420 if (table_base + v != ip6t_next_entry(e) &&
421 !(e->ipv6.flags & IP6T_F_GOTO)) {
f3c5c1bf
JE
422 if (*stackptr >= private->stacksize) {
423 verdict = NF_DROP;
424 break;
425 }
426 jumpstack[(*stackptr)++] = e;
a1ff4ac8 427 }
1da177e4 428
a1ff4ac8 429 e = get_entry(table_base, v);
7a6b1c46
JE
430 continue;
431 }
432
de74c169
JE
433 acpar.target = t->u.kernel.target;
434 acpar.targinfo = t->data;
7eb35586 435
de74c169 436 verdict = t->u.kernel.target->target(skb, &acpar);
243bf6e2 437 if (verdict == XT_CONTINUE)
7a6b1c46
JE
438 e = ip6t_next_entry(e);
439 else
440 /* Verdict */
441 break;
b4ba2611 442 } while (!acpar.hotdrop);
1da177e4 443
942e4a2b 444 xt_info_rdunlock_bh();
f3c5c1bf 445 *stackptr = origptr;
1da177e4
LT
446
447#ifdef DEBUG_ALLOW_ALL
448 return NF_ACCEPT;
449#else
b4ba2611 450 if (acpar.hotdrop)
1da177e4
LT
451 return NF_DROP;
452 else return verdict;
453#endif
454}
455
1da177e4
LT
456/* Figures out from what hook each rule can be called: returns 0 if
457 there are loops. Puts hook bitmask in comefrom. */
458static int
d5d1baa1 459mark_source_chains(const struct xt_table_info *newinfo,
31836064 460 unsigned int valid_hooks, void *entry0)
1da177e4
LT
461{
462 unsigned int hook;
463
464 /* No recursion; use packet counter to save back ptrs (reset
465 to 0 as we leave), and comefrom to save source hook bitmask */
6e23ae2a 466 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
1da177e4 467 unsigned int pos = newinfo->hook_entry[hook];
9c547959 468 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
1da177e4
LT
469
470 if (!(valid_hooks & (1 << hook)))
471 continue;
472
473 /* Set initial back pointer. */
474 e->counters.pcnt = pos;
475
476 for (;;) {
87a2e70d 477 const struct xt_standard_target *t
d5d1baa1 478 = (void *)ip6t_get_target_c(e);
9c547959 479 int visited = e->comefrom & (1 << hook);
1da177e4 480
6e23ae2a 481 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
654d0fbd 482 pr_err("iptables: loop hook %u pos %u %08X.\n",
1da177e4
LT
483 hook, pos, e->comefrom);
484 return 0;
485 }
9c547959 486 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
1da177e4
LT
487
488 /* Unconditional return/END. */
3666ed1c
JP
489 if ((e->target_offset == sizeof(struct ip6t_entry) &&
490 (strcmp(t->target.u.user.name,
243bf6e2 491 XT_STANDARD_TARGET) == 0) &&
3666ed1c
JP
492 t->verdict < 0 &&
493 unconditional(&e->ipv6)) || visited) {
1da177e4
LT
494 unsigned int oldpos, size;
495
1f9352ae 496 if ((strcmp(t->target.u.user.name,
243bf6e2 497 XT_STANDARD_TARGET) == 0) &&
1f9352ae 498 t->verdict < -NF_MAX_VERDICT - 1) {
74c9c0c1
DM
499 duprintf("mark_source_chains: bad "
500 "negative verdict (%i)\n",
501 t->verdict);
502 return 0;
503 }
504
1da177e4
LT
505 /* Return: backtrack through the last
506 big jump. */
507 do {
6e23ae2a 508 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
1da177e4
LT
509#ifdef DEBUG_IP_FIREWALL_USER
510 if (e->comefrom
6e23ae2a 511 & (1 << NF_INET_NUMHOOKS)) {
1da177e4
LT
512 duprintf("Back unset "
513 "on hook %u "
514 "rule %u\n",
515 hook, pos);
516 }
517#endif
518 oldpos = pos;
519 pos = e->counters.pcnt;
520 e->counters.pcnt = 0;
521
522 /* We're at the start. */
523 if (pos == oldpos)
524 goto next;
525
526 e = (struct ip6t_entry *)
31836064 527 (entry0 + pos);
1da177e4
LT
528 } while (oldpos == pos + e->next_offset);
529
530 /* Move along one */
531 size = e->next_offset;
532 e = (struct ip6t_entry *)
31836064 533 (entry0 + pos + size);
1da177e4
LT
534 e->counters.pcnt = pos;
535 pos += size;
536 } else {
537 int newpos = t->verdict;
538
539 if (strcmp(t->target.u.user.name,
243bf6e2 540 XT_STANDARD_TARGET) == 0 &&
3666ed1c 541 newpos >= 0) {
74c9c0c1
DM
542 if (newpos > newinfo->size -
543 sizeof(struct ip6t_entry)) {
544 duprintf("mark_source_chains: "
545 "bad verdict (%i)\n",
546 newpos);
547 return 0;
548 }
1da177e4
LT
549 /* This a jump; chase it. */
550 duprintf("Jump rule %u -> %u\n",
551 pos, newpos);
552 } else {
553 /* ... this is a fallthru */
554 newpos = pos + e->next_offset;
555 }
556 e = (struct ip6t_entry *)
31836064 557 (entry0 + newpos);
1da177e4
LT
558 e->counters.pcnt = pos;
559 pos = newpos;
560 }
561 }
562 next:
563 duprintf("Finished chain %u\n", hook);
564 }
565 return 1;
566}
567
87a2e70d 568static void cleanup_match(struct xt_entry_match *m, struct net *net)
1da177e4 569{
6be3d859
JE
570 struct xt_mtdtor_param par;
571
f54e9367 572 par.net = net;
6be3d859
JE
573 par.match = m->u.kernel.match;
574 par.matchinfo = m->data;
916a917d 575 par.family = NFPROTO_IPV6;
6be3d859
JE
576 if (par.match->destroy != NULL)
577 par.match->destroy(&par);
578 module_put(par.match->me);
1da177e4
LT
579}
580
022748a9 581static int
d5d1baa1 582check_entry(const struct ip6t_entry *e, const char *name)
f173c8a1 583{
87a2e70d 584 const struct xt_entry_target *t;
f173c8a1
PM
585
586 if (!ip6_checkentry(&e->ipv6)) {
587 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
588 return -EINVAL;
589 }
590
87a2e70d 591 if (e->target_offset + sizeof(struct xt_entry_target) >
f173c8a1
PM
592 e->next_offset)
593 return -EINVAL;
594
d5d1baa1 595 t = ip6t_get_target_c(e);
f173c8a1
PM
596 if (e->target_offset + t->u.target_size > e->next_offset)
597 return -EINVAL;
598
599 return 0;
600}
601
87a2e70d 602static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
f173c8a1 603{
9b4fce7a 604 const struct ip6t_ip6 *ipv6 = par->entryinfo;
f173c8a1
PM
605 int ret;
606
9b4fce7a
JE
607 par->match = m->u.kernel.match;
608 par->matchinfo = m->data;
609
916a917d 610 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
9b4fce7a 611 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
367c6790 612 if (ret < 0) {
f173c8a1 613 duprintf("ip_tables: check failed for `%s'.\n",
9b4fce7a 614 par.match->name);
367c6790 615 return ret;
f173c8a1 616 }
367c6790 617 return 0;
f173c8a1
PM
618}
619
022748a9 620static int
87a2e70d 621find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
1da177e4 622{
6709dbbb 623 struct xt_match *match;
3cdc7c95 624 int ret;
1da177e4 625
fd0ec0e6
JE
626 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
627 m->u.user.revision);
628 if (IS_ERR(match)) {
f173c8a1 629 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
fd0ec0e6 630 return PTR_ERR(match);
1da177e4
LT
631 }
632 m->u.kernel.match = match;
1da177e4 633
6bdb331b 634 ret = check_match(m, par);
3cdc7c95
PM
635 if (ret)
636 goto err;
637
1da177e4 638 return 0;
3cdc7c95
PM
639err:
640 module_put(m->u.kernel.match->me);
641 return ret;
1da177e4
LT
642}
643
add67461 644static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
1da177e4 645{
87a2e70d 646 struct xt_entry_target *t = ip6t_get_target(e);
af5d6dc2 647 struct xt_tgchk_param par = {
add67461 648 .net = net,
af5d6dc2
JE
649 .table = name,
650 .entryinfo = e,
651 .target = t->u.kernel.target,
652 .targinfo = t->data,
653 .hook_mask = e->comefrom,
916a917d 654 .family = NFPROTO_IPV6,
af5d6dc2 655 };
1da177e4 656 int ret;
1da177e4 657
f173c8a1 658 t = ip6t_get_target(e);
916a917d 659 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
af5d6dc2 660 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
367c6790 661 if (ret < 0) {
f173c8a1
PM
662 duprintf("ip_tables: check failed for `%s'.\n",
663 t->u.kernel.target->name);
367c6790 664 return ret;
1da177e4 665 }
367c6790 666 return 0;
f173c8a1 667}
1da177e4 668
022748a9 669static int
a83d8e8d 670find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
0559518b 671 unsigned int size)
f173c8a1 672{
87a2e70d 673 struct xt_entry_target *t;
f173c8a1
PM
674 struct xt_target *target;
675 int ret;
676 unsigned int j;
9b4fce7a 677 struct xt_mtchk_param mtpar;
dcea992a 678 struct xt_entry_match *ematch;
f173c8a1
PM
679
680 ret = check_entry(e, name);
681 if (ret)
682 return ret;
590bdf7f 683
1da177e4 684 j = 0;
a83d8e8d 685 mtpar.net = net;
9b4fce7a
JE
686 mtpar.table = name;
687 mtpar.entryinfo = &e->ipv6;
688 mtpar.hook_mask = e->comefrom;
916a917d 689 mtpar.family = NFPROTO_IPV6;
dcea992a 690 xt_ematch_foreach(ematch, e) {
6bdb331b 691 ret = find_check_match(ematch, &mtpar);
dcea992a 692 if (ret != 0)
6bdb331b
JE
693 goto cleanup_matches;
694 ++j;
dcea992a 695 }
1da177e4
LT
696
697 t = ip6t_get_target(e);
d2a7b6ba
JE
698 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
699 t->u.user.revision);
700 if (IS_ERR(target)) {
f173c8a1 701 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
d2a7b6ba 702 ret = PTR_ERR(target);
1da177e4
LT
703 goto cleanup_matches;
704 }
705 t->u.kernel.target = target;
6b7d31fc 706
add67461 707 ret = check_target(e, net, name);
3cdc7c95
PM
708 if (ret)
709 goto err;
1da177e4 710 return 0;
3cdc7c95
PM
711 err:
712 module_put(t->u.kernel.target->me);
1da177e4 713 cleanup_matches:
6bdb331b
JE
714 xt_ematch_foreach(ematch, e) {
715 if (j-- == 0)
dcea992a 716 break;
6bdb331b
JE
717 cleanup_match(ematch, net);
718 }
1da177e4
LT
719 return ret;
720}
721
d5d1baa1 722static bool check_underflow(const struct ip6t_entry *e)
e2fe35c1 723{
87a2e70d 724 const struct xt_entry_target *t;
e2fe35c1
JE
725 unsigned int verdict;
726
727 if (!unconditional(&e->ipv6))
728 return false;
d5d1baa1 729 t = ip6t_get_target_c(e);
e2fe35c1
JE
730 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
731 return false;
87a2e70d 732 verdict = ((struct xt_standard_target *)t)->verdict;
e2fe35c1
JE
733 verdict = -verdict - 1;
734 return verdict == NF_DROP || verdict == NF_ACCEPT;
735}
736
022748a9 737static int
1da177e4 738check_entry_size_and_hooks(struct ip6t_entry *e,
2e4e6a17 739 struct xt_table_info *newinfo,
d5d1baa1
JE
740 const unsigned char *base,
741 const unsigned char *limit,
1da177e4
LT
742 const unsigned int *hook_entries,
743 const unsigned int *underflows,
0559518b 744 unsigned int valid_hooks)
1da177e4
LT
745{
746 unsigned int h;
747
3666ed1c
JP
748 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
749 (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
1da177e4
LT
750 duprintf("Bad offset %p\n", e);
751 return -EINVAL;
752 }
753
754 if (e->next_offset
87a2e70d 755 < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
1da177e4
LT
756 duprintf("checking: element %p size %u\n",
757 e, e->next_offset);
758 return -EINVAL;
759 }
760
761 /* Check hooks & underflows */
6e23ae2a 762 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
a7d51738
JE
763 if (!(valid_hooks & (1 << h)))
764 continue;
1da177e4
LT
765 if ((unsigned char *)e - base == hook_entries[h])
766 newinfo->hook_entry[h] = hook_entries[h];
90e7d4ab 767 if ((unsigned char *)e - base == underflows[h]) {
e2fe35c1
JE
768 if (!check_underflow(e)) {
769 pr_err("Underflows must be unconditional and "
770 "use the STANDARD target with "
771 "ACCEPT/DROP\n");
90e7d4ab
JE
772 return -EINVAL;
773 }
1da177e4 774 newinfo->underflow[h] = underflows[h];
90e7d4ab 775 }
1da177e4
LT
776 }
777
1da177e4 778 /* Clear counters and comefrom */
2e4e6a17 779 e->counters = ((struct xt_counters) { 0, 0 });
1da177e4 780 e->comefrom = 0;
1da177e4
LT
781 return 0;
782}
783
0559518b 784static void cleanup_entry(struct ip6t_entry *e, struct net *net)
1da177e4 785{
a2df1648 786 struct xt_tgdtor_param par;
87a2e70d 787 struct xt_entry_target *t;
dcea992a 788 struct xt_entry_match *ematch;
1da177e4 789
1da177e4 790 /* Cleanup all matches */
dcea992a 791 xt_ematch_foreach(ematch, e)
6bdb331b 792 cleanup_match(ematch, net);
1da177e4 793 t = ip6t_get_target(e);
a2df1648 794
add67461 795 par.net = net;
a2df1648
JE
796 par.target = t->u.kernel.target;
797 par.targinfo = t->data;
916a917d 798 par.family = NFPROTO_IPV6;
a2df1648
JE
799 if (par.target->destroy != NULL)
800 par.target->destroy(&par);
801 module_put(par.target->me);
1da177e4
LT
802}
803
804/* Checks and translates the user-supplied table segment (held in
805 newinfo) */
806static int
0f234214
JE
807translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
808 const struct ip6t_replace *repl)
1da177e4 809{
72b2b1dd 810 struct ip6t_entry *iter;
1da177e4 811 unsigned int i;
72b2b1dd 812 int ret = 0;
1da177e4 813
0f234214
JE
814 newinfo->size = repl->size;
815 newinfo->number = repl->num_entries;
1da177e4
LT
816
817 /* Init all hooks to impossible value. */
6e23ae2a 818 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1da177e4
LT
819 newinfo->hook_entry[i] = 0xFFFFFFFF;
820 newinfo->underflow[i] = 0xFFFFFFFF;
821 }
822
823 duprintf("translate_table: size %u\n", newinfo->size);
824 i = 0;
825 /* Walk through entries, checking offsets. */
72b2b1dd
JE
826 xt_entry_foreach(iter, entry0, newinfo->size) {
827 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
6b4ff2d7
JE
828 entry0 + repl->size,
829 repl->hook_entry,
830 repl->underflow,
831 repl->valid_hooks);
72b2b1dd 832 if (ret != 0)
0559518b
JE
833 return ret;
834 ++i;
f3c5c1bf
JE
835 if (strcmp(ip6t_get_target(iter)->u.user.name,
836 XT_ERROR_TARGET) == 0)
837 ++newinfo->stacksize;
72b2b1dd 838 }
1da177e4 839
0f234214 840 if (i != repl->num_entries) {
1da177e4 841 duprintf("translate_table: %u not %u entries\n",
0f234214 842 i, repl->num_entries);
1da177e4
LT
843 return -EINVAL;
844 }
845
846 /* Check hooks all assigned */
6e23ae2a 847 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1da177e4 848 /* Only hooks which are valid */
0f234214 849 if (!(repl->valid_hooks & (1 << i)))
1da177e4
LT
850 continue;
851 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
852 duprintf("Invalid hook entry %u %u\n",
0f234214 853 i, repl->hook_entry[i]);
1da177e4
LT
854 return -EINVAL;
855 }
856 if (newinfo->underflow[i] == 0xFFFFFFFF) {
857 duprintf("Invalid underflow %u %u\n",
0f234214 858 i, repl->underflow[i]);
1da177e4
LT
859 return -EINVAL;
860 }
861 }
862
0f234214 863 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
74c9c0c1
DM
864 return -ELOOP;
865
1da177e4
LT
866 /* Finally, each sanity check must pass */
867 i = 0;
72b2b1dd 868 xt_entry_foreach(iter, entry0, newinfo->size) {
0f234214 869 ret = find_check_entry(iter, net, repl->name, repl->size);
72b2b1dd
JE
870 if (ret != 0)
871 break;
0559518b 872 ++i;
72b2b1dd 873 }
1da177e4 874
74c9c0c1 875 if (ret != 0) {
0559518b
JE
876 xt_entry_foreach(iter, entry0, newinfo->size) {
877 if (i-- == 0)
72b2b1dd 878 break;
0559518b
JE
879 cleanup_entry(iter, net);
880 }
74c9c0c1
DM
881 return ret;
882 }
1da177e4
LT
883
884 /* And one copy for every other CPU */
6f912042 885 for_each_possible_cpu(i) {
31836064
ED
886 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
887 memcpy(newinfo->entries[i], entry0, newinfo->size);
1da177e4
LT
888 }
889
9c547959 890 return ret;
1da177e4
LT
891}
892
1da177e4 893static void
2e4e6a17
HW
894get_counters(const struct xt_table_info *t,
895 struct xt_counters counters[])
1da177e4 896{
72b2b1dd 897 struct ip6t_entry *iter;
1da177e4
LT
898 unsigned int cpu;
899 unsigned int i;
24b36f01 900 unsigned int curcpu = get_cpu();
31836064
ED
901
902 /* Instead of clearing (by a previous call to memset())
903 * the counters and using adds, we set the counters
904 * with data used by 'current' CPU
942e4a2b
SH
905 *
906 * Bottom half has to be disabled to prevent deadlock
907 * if new softirq were to run and call ipt_do_table
31836064 908 */
942e4a2b 909 local_bh_disable();
31836064 910 i = 0;
0559518b
JE
911 xt_entry_foreach(iter, t->entries[curcpu], t->size) {
912 SET_COUNTER(counters[i], iter->counters.bcnt,
6b4ff2d7 913 iter->counters.pcnt);
0559518b
JE
914 ++i;
915 }
24b36f01
ED
916 local_bh_enable();
917 /* Processing counters from other cpus, we can let bottom half enabled,
918 * (preemption is disabled)
919 */
1da177e4 920
6f912042 921 for_each_possible_cpu(cpu) {
31836064
ED
922 if (cpu == curcpu)
923 continue;
1da177e4 924 i = 0;
001389b9 925 local_bh_disable();
942e4a2b 926 xt_info_wrlock(cpu);
0559518b
JE
927 xt_entry_foreach(iter, t->entries[cpu], t->size) {
928 ADD_COUNTER(counters[i], iter->counters.bcnt,
6b4ff2d7 929 iter->counters.pcnt);
0559518b
JE
930 ++i;
931 }
942e4a2b 932 xt_info_wrunlock(cpu);
001389b9 933 local_bh_enable();
1da177e4 934 }
24b36f01 935 put_cpu();
78454473
SH
936}
937
d5d1baa1 938static struct xt_counters *alloc_counters(const struct xt_table *table)
1da177e4 939{
ed1a6f5e 940 unsigned int countersize;
2e4e6a17 941 struct xt_counters *counters;
d5d1baa1 942 const struct xt_table_info *private = table->private;
1da177e4
LT
943
944 /* We need atomic snapshot of counters: rest doesn't change
945 (other than comefrom, which userspace doesn't care
946 about). */
2e4e6a17 947 countersize = sizeof(struct xt_counters) * private->number;
e12f8e29 948 counters = vmalloc(countersize);
1da177e4
LT
949
950 if (counters == NULL)
942e4a2b 951 return ERR_PTR(-ENOMEM);
78454473 952
942e4a2b 953 get_counters(private, counters);
78454473 954
49a88d18 955 return counters;
ed1a6f5e
PM
956}
957
958static int
959copy_entries_to_user(unsigned int total_size,
d5d1baa1 960 const struct xt_table *table,
ed1a6f5e
PM
961 void __user *userptr)
962{
963 unsigned int off, num;
d5d1baa1 964 const struct ip6t_entry *e;
ed1a6f5e 965 struct xt_counters *counters;
5452e425 966 const struct xt_table_info *private = table->private;
ed1a6f5e 967 int ret = 0;
5452e425 968 const void *loc_cpu_entry;
ed1a6f5e
PM
969
970 counters = alloc_counters(table);
971 if (IS_ERR(counters))
972 return PTR_ERR(counters);
973
9c547959
PM
974 /* choose the copy that is on our node/cpu, ...
975 * This choice is lazy (because current thread is
976 * allowed to migrate to another cpu)
977 */
2e4e6a17 978 loc_cpu_entry = private->entries[raw_smp_processor_id()];
31836064 979 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
1da177e4
LT
980 ret = -EFAULT;
981 goto free_counters;
982 }
983
984 /* FIXME: use iterator macros --RR */
985 /* ... then go back and fix counters and names */
986 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
987 unsigned int i;
87a2e70d
JE
988 const struct xt_entry_match *m;
989 const struct xt_entry_target *t;
1da177e4 990
31836064 991 e = (struct ip6t_entry *)(loc_cpu_entry + off);
1da177e4
LT
992 if (copy_to_user(userptr + off
993 + offsetof(struct ip6t_entry, counters),
994 &counters[num],
995 sizeof(counters[num])) != 0) {
996 ret = -EFAULT;
997 goto free_counters;
998 }
999
1000 for (i = sizeof(struct ip6t_entry);
1001 i < e->target_offset;
1002 i += m->u.match_size) {
1003 m = (void *)e + i;
1004
1005 if (copy_to_user(userptr + off + i
87a2e70d 1006 + offsetof(struct xt_entry_match,
1da177e4
LT
1007 u.user.name),
1008 m->u.kernel.match->name,
1009 strlen(m->u.kernel.match->name)+1)
1010 != 0) {
1011 ret = -EFAULT;
1012 goto free_counters;
1013 }
1014 }
1015
d5d1baa1 1016 t = ip6t_get_target_c(e);
1da177e4 1017 if (copy_to_user(userptr + off + e->target_offset
87a2e70d 1018 + offsetof(struct xt_entry_target,
1da177e4
LT
1019 u.user.name),
1020 t->u.kernel.target->name,
1021 strlen(t->u.kernel.target->name)+1) != 0) {
1022 ret = -EFAULT;
1023 goto free_counters;
1024 }
1025 }
1026
1027 free_counters:
1028 vfree(counters);
1029 return ret;
1030}
1031
3bc3fe5e 1032#ifdef CONFIG_COMPAT
739674fb 1033static void compat_standard_from_user(void *dst, const void *src)
3bc3fe5e
PM
1034{
1035 int v = *(compat_int_t *)src;
1036
1037 if (v > 0)
1038 v += xt_compat_calc_jump(AF_INET6, v);
1039 memcpy(dst, &v, sizeof(v));
1040}
1041
739674fb 1042static int compat_standard_to_user(void __user *dst, const void *src)
3bc3fe5e
PM
1043{
1044 compat_int_t cv = *(int *)src;
1045
1046 if (cv > 0)
1047 cv -= xt_compat_calc_jump(AF_INET6, cv);
1048 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1049}
1050
d5d1baa1 1051static int compat_calc_entry(const struct ip6t_entry *e,
3bc3fe5e 1052 const struct xt_table_info *info,
d5d1baa1 1053 const void *base, struct xt_table_info *newinfo)
3bc3fe5e 1054{
dcea992a 1055 const struct xt_entry_match *ematch;
87a2e70d 1056 const struct xt_entry_target *t;
3bc3fe5e
PM
1057 unsigned int entry_offset;
1058 int off, i, ret;
1059
1060 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1061 entry_offset = (void *)e - base;
dcea992a 1062 xt_ematch_foreach(ematch, e)
6bdb331b 1063 off += xt_compat_match_offset(ematch->u.kernel.match);
d5d1baa1 1064 t = ip6t_get_target_c(e);
3bc3fe5e
PM
1065 off += xt_compat_target_offset(t->u.kernel.target);
1066 newinfo->size -= off;
1067 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1068 if (ret)
1069 return ret;
1070
1071 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1072 if (info->hook_entry[i] &&
1073 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1074 newinfo->hook_entry[i] -= off;
1075 if (info->underflow[i] &&
1076 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1077 newinfo->underflow[i] -= off;
1078 }
1079 return 0;
1080}
1081
1082static int compat_table_info(const struct xt_table_info *info,
1083 struct xt_table_info *newinfo)
1084{
72b2b1dd 1085 struct ip6t_entry *iter;
3bc3fe5e 1086 void *loc_cpu_entry;
0559518b 1087 int ret;
3bc3fe5e
PM
1088
1089 if (!newinfo || !info)
1090 return -EINVAL;
1091
1092 /* we dont care about newinfo->entries[] */
1093 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1094 newinfo->initial_entries = 0;
1095 loc_cpu_entry = info->entries[raw_smp_processor_id()];
72b2b1dd
JE
1096 xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1097 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1098 if (ret != 0)
0559518b 1099 return ret;
72b2b1dd 1100 }
0559518b 1101 return 0;
3bc3fe5e
PM
1102}
1103#endif
1104
d5d1baa1
JE
1105static int get_info(struct net *net, void __user *user,
1106 const int *len, int compat)
433665c9 1107{
12b00c2c 1108 char name[XT_TABLE_MAXNAMELEN];
433665c9
PM
1109 struct xt_table *t;
1110 int ret;
1111
1112 if (*len != sizeof(struct ip6t_getinfo)) {
c9d8fe13 1113 duprintf("length %u != %zu\n", *len,
433665c9
PM
1114 sizeof(struct ip6t_getinfo));
1115 return -EINVAL;
1116 }
1117
1118 if (copy_from_user(name, user, sizeof(name)) != 0)
1119 return -EFAULT;
1120
12b00c2c 1121 name[XT_TABLE_MAXNAMELEN-1] = '\0';
3bc3fe5e
PM
1122#ifdef CONFIG_COMPAT
1123 if (compat)
1124 xt_compat_lock(AF_INET6);
1125#endif
336b517f 1126 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
433665c9
PM
1127 "ip6table_%s", name);
1128 if (t && !IS_ERR(t)) {
1129 struct ip6t_getinfo info;
5452e425 1130 const struct xt_table_info *private = t->private;
3bc3fe5e 1131#ifdef CONFIG_COMPAT
14c7dbe0
AD
1132 struct xt_table_info tmp;
1133
3bc3fe5e 1134 if (compat) {
3bc3fe5e
PM
1135 ret = compat_table_info(private, &tmp);
1136 xt_compat_flush_offsets(AF_INET6);
1137 private = &tmp;
1138 }
1139#endif
cccbe5ef 1140 memset(&info, 0, sizeof(info));
433665c9
PM
1141 info.valid_hooks = t->valid_hooks;
1142 memcpy(info.hook_entry, private->hook_entry,
1143 sizeof(info.hook_entry));
1144 memcpy(info.underflow, private->underflow,
1145 sizeof(info.underflow));
1146 info.num_entries = private->number;
1147 info.size = private->size;
b5dd674b 1148 strcpy(info.name, name);
433665c9
PM
1149
1150 if (copy_to_user(user, &info, *len) != 0)
1151 ret = -EFAULT;
1152 else
1153 ret = 0;
1154
1155 xt_table_unlock(t);
1156 module_put(t->me);
1157 } else
1158 ret = t ? PTR_ERR(t) : -ENOENT;
3bc3fe5e
PM
1159#ifdef CONFIG_COMPAT
1160 if (compat)
1161 xt_compat_unlock(AF_INET6);
1162#endif
433665c9
PM
1163 return ret;
1164}
1165
1da177e4 1166static int
d5d1baa1
JE
1167get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1168 const int *len)
1da177e4
LT
1169{
1170 int ret;
d924357c 1171 struct ip6t_get_entries get;
2e4e6a17 1172 struct xt_table *t;
1da177e4 1173
d924357c 1174 if (*len < sizeof(get)) {
c9d8fe13 1175 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
d924357c
PM
1176 return -EINVAL;
1177 }
1178 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1179 return -EFAULT;
1180 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
c9d8fe13
PM
1181 duprintf("get_entries: %u != %zu\n",
1182 *len, sizeof(get) + get.size);
d924357c
PM
1183 return -EINVAL;
1184 }
1185
336b517f 1186 t = xt_find_table_lock(net, AF_INET6, get.name);
6b7d31fc 1187 if (t && !IS_ERR(t)) {
2e4e6a17
HW
1188 struct xt_table_info *private = t->private;
1189 duprintf("t->private->number = %u\n", private->number);
d924357c 1190 if (get.size == private->size)
2e4e6a17 1191 ret = copy_entries_to_user(private->size,
1da177e4
LT
1192 t, uptr->entrytable);
1193 else {
1194 duprintf("get_entries: I've got %u not %u!\n",
9c547959 1195 private->size, get.size);
544473c1 1196 ret = -EAGAIN;
1da177e4 1197 }
6b7d31fc 1198 module_put(t->me);
2e4e6a17 1199 xt_table_unlock(t);
1da177e4 1200 } else
6b7d31fc 1201 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4
LT
1202
1203 return ret;
1204}
1205
1206static int
336b517f 1207__do_replace(struct net *net, const char *name, unsigned int valid_hooks,
3bc3fe5e
PM
1208 struct xt_table_info *newinfo, unsigned int num_counters,
1209 void __user *counters_ptr)
1da177e4
LT
1210{
1211 int ret;
2e4e6a17 1212 struct xt_table *t;
3bc3fe5e 1213 struct xt_table_info *oldinfo;
2e4e6a17 1214 struct xt_counters *counters;
5452e425 1215 const void *loc_cpu_old_entry;
72b2b1dd 1216 struct ip6t_entry *iter;
1da177e4 1217
3bc3fe5e 1218 ret = 0;
e12f8e29 1219 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1da177e4
LT
1220 if (!counters) {
1221 ret = -ENOMEM;
3bc3fe5e 1222 goto out;
1da177e4 1223 }
1da177e4 1224
336b517f 1225 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
3bc3fe5e 1226 "ip6table_%s", name);
6b7d31fc
HW
1227 if (!t || IS_ERR(t)) {
1228 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4 1229 goto free_newinfo_counters_untrans;
6b7d31fc 1230 }
1da177e4
LT
1231
1232 /* You lied! */
3bc3fe5e 1233 if (valid_hooks != t->valid_hooks) {
1da177e4 1234 duprintf("Valid hook crap: %08X vs %08X\n",
3bc3fe5e 1235 valid_hooks, t->valid_hooks);
1da177e4 1236 ret = -EINVAL;
6b7d31fc 1237 goto put_module;
1da177e4
LT
1238 }
1239
3bc3fe5e 1240 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1da177e4
LT
1241 if (!oldinfo)
1242 goto put_module;
1243
1244 /* Update module usage count based on number of rules */
1245 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1246 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1ab1457c
YH
1247 if ((oldinfo->number > oldinfo->initial_entries) ||
1248 (newinfo->number <= oldinfo->initial_entries))
1da177e4
LT
1249 module_put(t->me);
1250 if ((oldinfo->number > oldinfo->initial_entries) &&
1251 (newinfo->number <= oldinfo->initial_entries))
1252 module_put(t->me);
1253
942e4a2b 1254 /* Get the old counters, and synchronize with replace */
1da177e4 1255 get_counters(oldinfo, counters);
942e4a2b 1256
1da177e4 1257 /* Decrease module usage counts and free resource */
31836064 1258 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
72b2b1dd 1259 xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
0559518b 1260 cleanup_entry(iter, net);
72b2b1dd 1261
2e4e6a17 1262 xt_free_table_info(oldinfo);
3bc3fe5e
PM
1263 if (copy_to_user(counters_ptr, counters,
1264 sizeof(struct xt_counters) * num_counters) != 0)
1da177e4
LT
1265 ret = -EFAULT;
1266 vfree(counters);
2e4e6a17 1267 xt_table_unlock(t);
1da177e4
LT
1268 return ret;
1269
1270 put_module:
1271 module_put(t->me);
2e4e6a17 1272 xt_table_unlock(t);
1da177e4 1273 free_newinfo_counters_untrans:
1da177e4 1274 vfree(counters);
3bc3fe5e
PM
1275 out:
1276 return ret;
1277}
1278
1279static int
d5d1baa1 1280do_replace(struct net *net, const void __user *user, unsigned int len)
3bc3fe5e
PM
1281{
1282 int ret;
1283 struct ip6t_replace tmp;
1284 struct xt_table_info *newinfo;
1285 void *loc_cpu_entry;
72b2b1dd 1286 struct ip6t_entry *iter;
3bc3fe5e
PM
1287
1288 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1289 return -EFAULT;
1290
1291 /* overflow check */
1292 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1293 return -ENOMEM;
1294
1295 newinfo = xt_alloc_table_info(tmp.size);
1296 if (!newinfo)
1297 return -ENOMEM;
1298
1299 /* choose the copy that is on our node/cpu */
1300 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1301 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1302 tmp.size) != 0) {
1303 ret = -EFAULT;
1304 goto free_newinfo;
1305 }
1306
0f234214 1307 ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
3bc3fe5e
PM
1308 if (ret != 0)
1309 goto free_newinfo;
1310
1311 duprintf("ip_tables: Translated table\n");
1312
336b517f 1313 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
3bc3fe5e
PM
1314 tmp.num_counters, tmp.counters);
1315 if (ret)
1316 goto free_newinfo_untrans;
1317 return 0;
1318
1319 free_newinfo_untrans:
72b2b1dd 1320 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
0559518b 1321 cleanup_entry(iter, net);
1da177e4 1322 free_newinfo:
2e4e6a17 1323 xt_free_table_info(newinfo);
1da177e4
LT
1324 return ret;
1325}
1326
1da177e4 1327static int
d5d1baa1 1328do_add_counters(struct net *net, const void __user *user, unsigned int len,
336b517f 1329 int compat)
1da177e4 1330{
942e4a2b 1331 unsigned int i, curcpu;
3bc3fe5e
PM
1332 struct xt_counters_info tmp;
1333 struct xt_counters *paddc;
1334 unsigned int num_counters;
1335 char *name;
1336 int size;
1337 void *ptmp;
2e4e6a17 1338 struct xt_table *t;
5452e425 1339 const struct xt_table_info *private;
6b7d31fc 1340 int ret = 0;
5452e425 1341 const void *loc_cpu_entry;
72b2b1dd 1342 struct ip6t_entry *iter;
3bc3fe5e
PM
1343#ifdef CONFIG_COMPAT
1344 struct compat_xt_counters_info compat_tmp;
1da177e4 1345
3bc3fe5e
PM
1346 if (compat) {
1347 ptmp = &compat_tmp;
1348 size = sizeof(struct compat_xt_counters_info);
1349 } else
1350#endif
1351 {
1352 ptmp = &tmp;
1353 size = sizeof(struct xt_counters_info);
1354 }
1355
1356 if (copy_from_user(ptmp, user, size) != 0)
1da177e4
LT
1357 return -EFAULT;
1358
3bc3fe5e
PM
1359#ifdef CONFIG_COMPAT
1360 if (compat) {
1361 num_counters = compat_tmp.num_counters;
1362 name = compat_tmp.name;
1363 } else
1364#endif
1365 {
1366 num_counters = tmp.num_counters;
1367 name = tmp.name;
1368 }
1369
1370 if (len != size + num_counters * sizeof(struct xt_counters))
1da177e4
LT
1371 return -EINVAL;
1372
e12f8e29 1373 paddc = vmalloc(len - size);
1da177e4
LT
1374 if (!paddc)
1375 return -ENOMEM;
1376
3bc3fe5e 1377 if (copy_from_user(paddc, user + size, len - size) != 0) {
1da177e4
LT
1378 ret = -EFAULT;
1379 goto free;
1380 }
1381
336b517f 1382 t = xt_find_table_lock(net, AF_INET6, name);
6b7d31fc
HW
1383 if (!t || IS_ERR(t)) {
1384 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4 1385 goto free;
6b7d31fc 1386 }
1da177e4 1387
942e4a2b
SH
1388
1389 local_bh_disable();
2e4e6a17 1390 private = t->private;
3bc3fe5e 1391 if (private->number != num_counters) {
1da177e4
LT
1392 ret = -EINVAL;
1393 goto unlock_up_free;
1394 }
1395
1396 i = 0;
31836064 1397 /* Choose the copy that is on our node */
942e4a2b
SH
1398 curcpu = smp_processor_id();
1399 xt_info_wrlock(curcpu);
1400 loc_cpu_entry = private->entries[curcpu];
0559518b
JE
1401 xt_entry_foreach(iter, loc_cpu_entry, private->size) {
1402 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
1403 ++i;
1404 }
942e4a2b
SH
1405 xt_info_wrunlock(curcpu);
1406
1da177e4 1407 unlock_up_free:
942e4a2b 1408 local_bh_enable();
2e4e6a17 1409 xt_table_unlock(t);
6b7d31fc 1410 module_put(t->me);
1da177e4
LT
1411 free:
1412 vfree(paddc);
1413
1414 return ret;
1415}
1416
3bc3fe5e
PM
1417#ifdef CONFIG_COMPAT
1418struct compat_ip6t_replace {
12b00c2c 1419 char name[XT_TABLE_MAXNAMELEN];
3bc3fe5e
PM
1420 u32 valid_hooks;
1421 u32 num_entries;
1422 u32 size;
1423 u32 hook_entry[NF_INET_NUMHOOKS];
1424 u32 underflow[NF_INET_NUMHOOKS];
1425 u32 num_counters;
87a2e70d 1426 compat_uptr_t counters; /* struct xt_counters * */
3bc3fe5e
PM
1427 struct compat_ip6t_entry entries[0];
1428};
1429
1430static int
1431compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
b0a6363c 1432 unsigned int *size, struct xt_counters *counters,
0559518b 1433 unsigned int i)
3bc3fe5e 1434{
87a2e70d 1435 struct xt_entry_target *t;
3bc3fe5e
PM
1436 struct compat_ip6t_entry __user *ce;
1437 u_int16_t target_offset, next_offset;
1438 compat_uint_t origsize;
dcea992a
JE
1439 const struct xt_entry_match *ematch;
1440 int ret = 0;
3bc3fe5e 1441
3bc3fe5e
PM
1442 origsize = *size;
1443 ce = (struct compat_ip6t_entry __user *)*dstptr;
0559518b
JE
1444 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1445 copy_to_user(&ce->counters, &counters[i],
1446 sizeof(counters[i])) != 0)
1447 return -EFAULT;
3bc3fe5e
PM
1448
1449 *dstptr += sizeof(struct compat_ip6t_entry);
1450 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1451
dcea992a
JE
1452 xt_ematch_foreach(ematch, e) {
1453 ret = xt_compat_match_to_user(ematch, dstptr, size);
1454 if (ret != 0)
6bdb331b 1455 return ret;
dcea992a 1456 }
3bc3fe5e 1457 target_offset = e->target_offset - (origsize - *size);
3bc3fe5e
PM
1458 t = ip6t_get_target(e);
1459 ret = xt_compat_target_to_user(t, dstptr, size);
1460 if (ret)
0559518b 1461 return ret;
3bc3fe5e 1462 next_offset = e->next_offset - (origsize - *size);
0559518b
JE
1463 if (put_user(target_offset, &ce->target_offset) != 0 ||
1464 put_user(next_offset, &ce->next_offset) != 0)
1465 return -EFAULT;
3bc3fe5e 1466 return 0;
3bc3fe5e
PM
1467}
1468
022748a9 1469static int
87a2e70d 1470compat_find_calc_match(struct xt_entry_match *m,
3bc3fe5e
PM
1471 const char *name,
1472 const struct ip6t_ip6 *ipv6,
1473 unsigned int hookmask,
6bdb331b 1474 int *size)
3bc3fe5e
PM
1475{
1476 struct xt_match *match;
1477
fd0ec0e6
JE
1478 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1479 m->u.user.revision);
1480 if (IS_ERR(match)) {
3bc3fe5e
PM
1481 duprintf("compat_check_calc_match: `%s' not found\n",
1482 m->u.user.name);
fd0ec0e6 1483 return PTR_ERR(match);
3bc3fe5e
PM
1484 }
1485 m->u.kernel.match = match;
1486 *size += xt_compat_match_offset(match);
3bc3fe5e
PM
1487 return 0;
1488}
1489
0559518b 1490static void compat_release_entry(struct compat_ip6t_entry *e)
3bc3fe5e 1491{
87a2e70d 1492 struct xt_entry_target *t;
dcea992a 1493 struct xt_entry_match *ematch;
3bc3fe5e 1494
3bc3fe5e 1495 /* Cleanup all matches */
dcea992a 1496 xt_ematch_foreach(ematch, e)
6bdb331b 1497 module_put(ematch->u.kernel.match->me);
3bc3fe5e
PM
1498 t = compat_ip6t_get_target(e);
1499 module_put(t->u.kernel.target->me);
3bc3fe5e
PM
1500}
1501
022748a9 1502static int
3bc3fe5e
PM
1503check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1504 struct xt_table_info *newinfo,
1505 unsigned int *size,
d5d1baa1
JE
1506 const unsigned char *base,
1507 const unsigned char *limit,
1508 const unsigned int *hook_entries,
1509 const unsigned int *underflows,
3bc3fe5e
PM
1510 const char *name)
1511{
dcea992a 1512 struct xt_entry_match *ematch;
87a2e70d 1513 struct xt_entry_target *t;
3bc3fe5e
PM
1514 struct xt_target *target;
1515 unsigned int entry_offset;
b0a6363c
PM
1516 unsigned int j;
1517 int ret, off, h;
3bc3fe5e
PM
1518
1519 duprintf("check_compat_entry_size_and_hooks %p\n", e);
3666ed1c
JP
1520 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1521 (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
3bc3fe5e
PM
1522 duprintf("Bad offset %p, limit = %p\n", e, limit);
1523 return -EINVAL;
1524 }
1525
1526 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1527 sizeof(struct compat_xt_entry_target)) {
1528 duprintf("checking: element %p size %u\n",
1529 e, e->next_offset);
1530 return -EINVAL;
1531 }
1532
1533 /* For purposes of check_entry casting the compat entry is fine */
1534 ret = check_entry((struct ip6t_entry *)e, name);
1535 if (ret)
1536 return ret;
1537
1538 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1539 entry_offset = (void *)e - (void *)base;
1540 j = 0;
dcea992a
JE
1541 xt_ematch_foreach(ematch, e) {
1542 ret = compat_find_calc_match(ematch, name,
6b4ff2d7 1543 &e->ipv6, e->comefrom, &off);
dcea992a 1544 if (ret != 0)
6bdb331b
JE
1545 goto release_matches;
1546 ++j;
dcea992a 1547 }
3bc3fe5e
PM
1548
1549 t = compat_ip6t_get_target(e);
d2a7b6ba
JE
1550 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1551 t->u.user.revision);
1552 if (IS_ERR(target)) {
3bc3fe5e
PM
1553 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1554 t->u.user.name);
d2a7b6ba 1555 ret = PTR_ERR(target);
3bc3fe5e
PM
1556 goto release_matches;
1557 }
1558 t->u.kernel.target = target;
1559
1560 off += xt_compat_target_offset(target);
1561 *size += off;
1562 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1563 if (ret)
1564 goto out;
1565
1566 /* Check hooks & underflows */
1567 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1568 if ((unsigned char *)e - base == hook_entries[h])
1569 newinfo->hook_entry[h] = hook_entries[h];
1570 if ((unsigned char *)e - base == underflows[h])
1571 newinfo->underflow[h] = underflows[h];
1572 }
1573
1574 /* Clear counters and comefrom */
1575 memset(&e->counters, 0, sizeof(e->counters));
1576 e->comefrom = 0;
3bc3fe5e
PM
1577 return 0;
1578
1579out:
1580 module_put(t->u.kernel.target->me);
1581release_matches:
6bdb331b
JE
1582 xt_ematch_foreach(ematch, e) {
1583 if (j-- == 0)
dcea992a 1584 break;
6bdb331b
JE
1585 module_put(ematch->u.kernel.match->me);
1586 }
3bc3fe5e
PM
1587 return ret;
1588}
1589
1590static int
1591compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1592 unsigned int *size, const char *name,
1593 struct xt_table_info *newinfo, unsigned char *base)
1594{
87a2e70d 1595 struct xt_entry_target *t;
3bc3fe5e
PM
1596 struct xt_target *target;
1597 struct ip6t_entry *de;
1598 unsigned int origsize;
1599 int ret, h;
dcea992a 1600 struct xt_entry_match *ematch;
3bc3fe5e
PM
1601
1602 ret = 0;
1603 origsize = *size;
1604 de = (struct ip6t_entry *)*dstptr;
1605 memcpy(de, e, sizeof(struct ip6t_entry));
1606 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1607
1608 *dstptr += sizeof(struct ip6t_entry);
1609 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1610
dcea992a
JE
1611 xt_ematch_foreach(ematch, e) {
1612 ret = xt_compat_match_from_user(ematch, dstptr, size);
1613 if (ret != 0)
6bdb331b 1614 return ret;
dcea992a 1615 }
3bc3fe5e
PM
1616 de->target_offset = e->target_offset - (origsize - *size);
1617 t = compat_ip6t_get_target(e);
1618 target = t->u.kernel.target;
1619 xt_compat_target_from_user(t, dstptr, size);
1620
1621 de->next_offset = e->next_offset - (origsize - *size);
1622 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1623 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1624 newinfo->hook_entry[h] -= origsize - *size;
1625 if ((unsigned char *)de - base < newinfo->underflow[h])
1626 newinfo->underflow[h] -= origsize - *size;
1627 }
1628 return ret;
1629}
1630
f54e9367 1631static int compat_check_entry(struct ip6t_entry *e, struct net *net,
0559518b 1632 const char *name)
3bc3fe5e 1633{
b0a6363c 1634 unsigned int j;
dcea992a 1635 int ret = 0;
9b4fce7a 1636 struct xt_mtchk_param mtpar;
dcea992a 1637 struct xt_entry_match *ematch;
3bc3fe5e
PM
1638
1639 j = 0;
f54e9367 1640 mtpar.net = net;
9b4fce7a
JE
1641 mtpar.table = name;
1642 mtpar.entryinfo = &e->ipv6;
1643 mtpar.hook_mask = e->comefrom;
916a917d 1644 mtpar.family = NFPROTO_IPV6;
dcea992a 1645 xt_ematch_foreach(ematch, e) {
6bdb331b 1646 ret = check_match(ematch, &mtpar);
dcea992a 1647 if (ret != 0)
6bdb331b
JE
1648 goto cleanup_matches;
1649 ++j;
dcea992a 1650 }
3bc3fe5e 1651
add67461 1652 ret = check_target(e, net, name);
3bc3fe5e
PM
1653 if (ret)
1654 goto cleanup_matches;
3bc3fe5e
PM
1655 return 0;
1656
1657 cleanup_matches:
6bdb331b
JE
1658 xt_ematch_foreach(ematch, e) {
1659 if (j-- == 0)
dcea992a 1660 break;
6bdb331b
JE
1661 cleanup_match(ematch, net);
1662 }
3bc3fe5e
PM
1663 return ret;
1664}
1665
1666static int
f54e9367
AD
1667translate_compat_table(struct net *net,
1668 const char *name,
3bc3fe5e
PM
1669 unsigned int valid_hooks,
1670 struct xt_table_info **pinfo,
1671 void **pentry0,
1672 unsigned int total_size,
1673 unsigned int number,
1674 unsigned int *hook_entries,
1675 unsigned int *underflows)
1676{
1677 unsigned int i, j;
1678 struct xt_table_info *newinfo, *info;
1679 void *pos, *entry0, *entry1;
72b2b1dd
JE
1680 struct compat_ip6t_entry *iter0;
1681 struct ip6t_entry *iter1;
3bc3fe5e 1682 unsigned int size;
72b2b1dd 1683 int ret = 0;
3bc3fe5e
PM
1684
1685 info = *pinfo;
1686 entry0 = *pentry0;
1687 size = total_size;
1688 info->number = number;
1689
1690 /* Init all hooks to impossible value. */
1691 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1692 info->hook_entry[i] = 0xFFFFFFFF;
1693 info->underflow[i] = 0xFFFFFFFF;
1694 }
1695
1696 duprintf("translate_compat_table: size %u\n", info->size);
1697 j = 0;
1698 xt_compat_lock(AF_INET6);
1699 /* Walk through entries, checking offsets. */
72b2b1dd
JE
1700 xt_entry_foreach(iter0, entry0, total_size) {
1701 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
6b4ff2d7
JE
1702 entry0,
1703 entry0 + total_size,
1704 hook_entries,
1705 underflows,
1706 name);
72b2b1dd 1707 if (ret != 0)
0559518b
JE
1708 goto out_unlock;
1709 ++j;
72b2b1dd 1710 }
3bc3fe5e
PM
1711
1712 ret = -EINVAL;
1713 if (j != number) {
1714 duprintf("translate_compat_table: %u not %u entries\n",
1715 j, number);
1716 goto out_unlock;
1717 }
1718
1719 /* Check hooks all assigned */
1720 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1721 /* Only hooks which are valid */
1722 if (!(valid_hooks & (1 << i)))
1723 continue;
1724 if (info->hook_entry[i] == 0xFFFFFFFF) {
1725 duprintf("Invalid hook entry %u %u\n",
1726 i, hook_entries[i]);
1727 goto out_unlock;
1728 }
1729 if (info->underflow[i] == 0xFFFFFFFF) {
1730 duprintf("Invalid underflow %u %u\n",
1731 i, underflows[i]);
1732 goto out_unlock;
1733 }
1734 }
1735
1736 ret = -ENOMEM;
1737 newinfo = xt_alloc_table_info(size);
1738 if (!newinfo)
1739 goto out_unlock;
1740
1741 newinfo->number = number;
1742 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1743 newinfo->hook_entry[i] = info->hook_entry[i];
1744 newinfo->underflow[i] = info->underflow[i];
1745 }
1746 entry1 = newinfo->entries[raw_smp_processor_id()];
1747 pos = entry1;
1748 size = total_size;
72b2b1dd 1749 xt_entry_foreach(iter0, entry0, total_size) {
6b4ff2d7
JE
1750 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1751 name, newinfo, entry1);
72b2b1dd
JE
1752 if (ret != 0)
1753 break;
1754 }
3bc3fe5e
PM
1755 xt_compat_flush_offsets(AF_INET6);
1756 xt_compat_unlock(AF_INET6);
1757 if (ret)
1758 goto free_newinfo;
1759
1760 ret = -ELOOP;
1761 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1762 goto free_newinfo;
1763
1764 i = 0;
72b2b1dd 1765 xt_entry_foreach(iter1, entry1, newinfo->size) {
0559518b 1766 ret = compat_check_entry(iter1, net, name);
72b2b1dd
JE
1767 if (ret != 0)
1768 break;
0559518b 1769 ++i;
cca77b7c
FW
1770 if (strcmp(ip6t_get_target(iter1)->u.user.name,
1771 XT_ERROR_TARGET) == 0)
1772 ++newinfo->stacksize;
72b2b1dd 1773 }
3bc3fe5e 1774 if (ret) {
72b2b1dd
JE
1775 /*
1776 * The first i matches need cleanup_entry (calls ->destroy)
1777 * because they had called ->check already. The other j-i
1778 * entries need only release.
1779 */
1780 int skip = i;
3bc3fe5e 1781 j -= i;
72b2b1dd
JE
1782 xt_entry_foreach(iter0, entry0, newinfo->size) {
1783 if (skip-- > 0)
1784 continue;
0559518b 1785 if (j-- == 0)
72b2b1dd 1786 break;
0559518b 1787 compat_release_entry(iter0);
72b2b1dd 1788 }
0559518b
JE
1789 xt_entry_foreach(iter1, entry1, newinfo->size) {
1790 if (i-- == 0)
72b2b1dd 1791 break;
0559518b
JE
1792 cleanup_entry(iter1, net);
1793 }
3bc3fe5e
PM
1794 xt_free_table_info(newinfo);
1795 return ret;
1796 }
1797
1798 /* And one copy for every other CPU */
1799 for_each_possible_cpu(i)
1800 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1801 memcpy(newinfo->entries[i], entry1, newinfo->size);
1802
1803 *pinfo = newinfo;
1804 *pentry0 = entry1;
1805 xt_free_table_info(info);
1806 return 0;
1807
1808free_newinfo:
1809 xt_free_table_info(newinfo);
1810out:
0559518b
JE
1811 xt_entry_foreach(iter0, entry0, total_size) {
1812 if (j-- == 0)
72b2b1dd 1813 break;
0559518b
JE
1814 compat_release_entry(iter0);
1815 }
3bc3fe5e
PM
1816 return ret;
1817out_unlock:
1818 xt_compat_flush_offsets(AF_INET6);
1819 xt_compat_unlock(AF_INET6);
1820 goto out;
1821}
1822
1823static int
336b517f 1824compat_do_replace(struct net *net, void __user *user, unsigned int len)
3bc3fe5e
PM
1825{
1826 int ret;
1827 struct compat_ip6t_replace tmp;
1828 struct xt_table_info *newinfo;
1829 void *loc_cpu_entry;
72b2b1dd 1830 struct ip6t_entry *iter;
3bc3fe5e
PM
1831
1832 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1833 return -EFAULT;
1834
1835 /* overflow check */
1836 if (tmp.size >= INT_MAX / num_possible_cpus())
1837 return -ENOMEM;
1838 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1839 return -ENOMEM;
1840
1841 newinfo = xt_alloc_table_info(tmp.size);
1842 if (!newinfo)
1843 return -ENOMEM;
1844
9c547959 1845 /* choose the copy that is on our node/cpu */
3bc3fe5e
PM
1846 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1847 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1848 tmp.size) != 0) {
1849 ret = -EFAULT;
1850 goto free_newinfo;
1851 }
1852
f54e9367 1853 ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
3bc3fe5e
PM
1854 &newinfo, &loc_cpu_entry, tmp.size,
1855 tmp.num_entries, tmp.hook_entry,
1856 tmp.underflow);
1857 if (ret != 0)
1858 goto free_newinfo;
1859
1860 duprintf("compat_do_replace: Translated table\n");
1861
336b517f 1862 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
3bc3fe5e
PM
1863 tmp.num_counters, compat_ptr(tmp.counters));
1864 if (ret)
1865 goto free_newinfo_untrans;
1866 return 0;
1867
1868 free_newinfo_untrans:
72b2b1dd 1869 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
0559518b 1870 cleanup_entry(iter, net);
3bc3fe5e
PM
1871 free_newinfo:
1872 xt_free_table_info(newinfo);
1873 return ret;
1874}
1875
1876static int
1877compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1878 unsigned int len)
1879{
1880 int ret;
1881
1882 if (!capable(CAP_NET_ADMIN))
1883 return -EPERM;
1884
1885 switch (cmd) {
1886 case IP6T_SO_SET_REPLACE:
3b1e0a65 1887 ret = compat_do_replace(sock_net(sk), user, len);
3bc3fe5e
PM
1888 break;
1889
1890 case IP6T_SO_SET_ADD_COUNTERS:
3b1e0a65 1891 ret = do_add_counters(sock_net(sk), user, len, 1);
3bc3fe5e
PM
1892 break;
1893
1894 default:
1895 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1896 ret = -EINVAL;
1897 }
1898
1899 return ret;
1900}
1901
1902struct compat_ip6t_get_entries {
12b00c2c 1903 char name[XT_TABLE_MAXNAMELEN];
3bc3fe5e
PM
1904 compat_uint_t size;
1905 struct compat_ip6t_entry entrytable[0];
1906};
1907
1908static int
1909compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1910 void __user *userptr)
1911{
1912 struct xt_counters *counters;
5452e425 1913 const struct xt_table_info *private = table->private;
3bc3fe5e
PM
1914 void __user *pos;
1915 unsigned int size;
1916 int ret = 0;
5452e425 1917 const void *loc_cpu_entry;
3bc3fe5e 1918 unsigned int i = 0;
72b2b1dd 1919 struct ip6t_entry *iter;
3bc3fe5e
PM
1920
1921 counters = alloc_counters(table);
1922 if (IS_ERR(counters))
1923 return PTR_ERR(counters);
1924
1925 /* choose the copy that is on our node/cpu, ...
1926 * This choice is lazy (because current thread is
1927 * allowed to migrate to another cpu)
1928 */
1929 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1930 pos = userptr;
1931 size = total_size;
72b2b1dd
JE
1932 xt_entry_foreach(iter, loc_cpu_entry, total_size) {
1933 ret = compat_copy_entry_to_user(iter, &pos,
6b4ff2d7 1934 &size, counters, i++);
72b2b1dd
JE
1935 if (ret != 0)
1936 break;
1937 }
3bc3fe5e
PM
1938
1939 vfree(counters);
1940 return ret;
1941}
1942
1943static int
336b517f
AD
1944compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1945 int *len)
3bc3fe5e
PM
1946{
1947 int ret;
1948 struct compat_ip6t_get_entries get;
1949 struct xt_table *t;
1950
1951 if (*len < sizeof(get)) {
c9d8fe13 1952 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
3bc3fe5e
PM
1953 return -EINVAL;
1954 }
1955
1956 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1957 return -EFAULT;
1958
1959 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
c9d8fe13
PM
1960 duprintf("compat_get_entries: %u != %zu\n",
1961 *len, sizeof(get) + get.size);
3bc3fe5e
PM
1962 return -EINVAL;
1963 }
1964
1965 xt_compat_lock(AF_INET6);
336b517f 1966 t = xt_find_table_lock(net, AF_INET6, get.name);
3bc3fe5e 1967 if (t && !IS_ERR(t)) {
5452e425 1968 const struct xt_table_info *private = t->private;
3bc3fe5e 1969 struct xt_table_info info;
9c547959 1970 duprintf("t->private->number = %u\n", private->number);
3bc3fe5e
PM
1971 ret = compat_table_info(private, &info);
1972 if (!ret && get.size == info.size) {
1973 ret = compat_copy_entries_to_user(private->size,
1974 t, uptr->entrytable);
1975 } else if (!ret) {
1976 duprintf("compat_get_entries: I've got %u not %u!\n",
9c547959 1977 private->size, get.size);
544473c1 1978 ret = -EAGAIN;
3bc3fe5e
PM
1979 }
1980 xt_compat_flush_offsets(AF_INET6);
1981 module_put(t->me);
1982 xt_table_unlock(t);
1983 } else
1984 ret = t ? PTR_ERR(t) : -ENOENT;
1985
1986 xt_compat_unlock(AF_INET6);
1987 return ret;
1988}
1989
1990static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1991
1992static int
1993compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1994{
1995 int ret;
1996
1997 if (!capable(CAP_NET_ADMIN))
1998 return -EPERM;
1999
2000 switch (cmd) {
2001 case IP6T_SO_GET_INFO:
3b1e0a65 2002 ret = get_info(sock_net(sk), user, len, 1);
3bc3fe5e
PM
2003 break;
2004 case IP6T_SO_GET_ENTRIES:
3b1e0a65 2005 ret = compat_get_entries(sock_net(sk), user, len);
3bc3fe5e
PM
2006 break;
2007 default:
2008 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2009 }
2010 return ret;
2011}
2012#endif
2013
1da177e4
LT
2014static int
2015do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2016{
2017 int ret;
2018
2019 if (!capable(CAP_NET_ADMIN))
2020 return -EPERM;
2021
2022 switch (cmd) {
2023 case IP6T_SO_SET_REPLACE:
3b1e0a65 2024 ret = do_replace(sock_net(sk), user, len);
1da177e4
LT
2025 break;
2026
2027 case IP6T_SO_SET_ADD_COUNTERS:
3b1e0a65 2028 ret = do_add_counters(sock_net(sk), user, len, 0);
1da177e4
LT
2029 break;
2030
2031 default:
2032 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2033 ret = -EINVAL;
2034 }
2035
2036 return ret;
2037}
2038
2039static int
2040do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2041{
2042 int ret;
2043
2044 if (!capable(CAP_NET_ADMIN))
2045 return -EPERM;
2046
2047 switch (cmd) {
433665c9 2048 case IP6T_SO_GET_INFO:
3b1e0a65 2049 ret = get_info(sock_net(sk), user, len, 0);
433665c9 2050 break;
1da177e4 2051
d924357c 2052 case IP6T_SO_GET_ENTRIES:
3b1e0a65 2053 ret = get_entries(sock_net(sk), user, len);
1da177e4 2054 break;
1da177e4 2055
6b7d31fc
HW
2056 case IP6T_SO_GET_REVISION_MATCH:
2057 case IP6T_SO_GET_REVISION_TARGET: {
12b00c2c 2058 struct xt_get_revision rev;
2e4e6a17 2059 int target;
6b7d31fc
HW
2060
2061 if (*len != sizeof(rev)) {
2062 ret = -EINVAL;
2063 break;
2064 }
2065 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2066 ret = -EFAULT;
2067 break;
2068 }
2069
2070 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2e4e6a17 2071 target = 1;
6b7d31fc 2072 else
2e4e6a17 2073 target = 0;
6b7d31fc 2074
2e4e6a17
HW
2075 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2076 rev.revision,
2077 target, &ret),
6b7d31fc
HW
2078 "ip6t_%s", rev.name);
2079 break;
2080 }
2081
1da177e4
LT
2082 default:
2083 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2084 ret = -EINVAL;
2085 }
2086
2087 return ret;
2088}
2089
35aad0ff
JE
2090struct xt_table *ip6t_register_table(struct net *net,
2091 const struct xt_table *table,
336b517f 2092 const struct ip6t_replace *repl)
1da177e4
LT
2093{
2094 int ret;
2e4e6a17 2095 struct xt_table_info *newinfo;
f3c5c1bf 2096 struct xt_table_info bootstrap = {0};
31836064 2097 void *loc_cpu_entry;
a98da11d 2098 struct xt_table *new_table;
1da177e4 2099
2e4e6a17 2100 newinfo = xt_alloc_table_info(repl->size);
44d34e72
AD
2101 if (!newinfo) {
2102 ret = -ENOMEM;
2103 goto out;
2104 }
1da177e4 2105
9c547959 2106 /* choose the copy on our node/cpu, but dont care about preemption */
31836064
ED
2107 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2108 memcpy(loc_cpu_entry, repl->entries, repl->size);
1da177e4 2109
0f234214 2110 ret = translate_table(net, newinfo, loc_cpu_entry, repl);
44d34e72
AD
2111 if (ret != 0)
2112 goto out_free;
1da177e4 2113
336b517f 2114 new_table = xt_register_table(net, table, &bootstrap, newinfo);
a98da11d 2115 if (IS_ERR(new_table)) {
44d34e72
AD
2116 ret = PTR_ERR(new_table);
2117 goto out_free;
1da177e4 2118 }
44d34e72 2119 return new_table;
1da177e4 2120
44d34e72
AD
2121out_free:
2122 xt_free_table_info(newinfo);
2123out:
2124 return ERR_PTR(ret);
1da177e4
LT
2125}
2126
f54e9367 2127void ip6t_unregister_table(struct net *net, struct xt_table *table)
1da177e4 2128{
2e4e6a17 2129 struct xt_table_info *private;
31836064 2130 void *loc_cpu_entry;
df200969 2131 struct module *table_owner = table->me;
72b2b1dd 2132 struct ip6t_entry *iter;
31836064 2133
2e4e6a17 2134 private = xt_unregister_table(table);
1da177e4
LT
2135
2136 /* Decrease module usage counts and free resources */
2e4e6a17 2137 loc_cpu_entry = private->entries[raw_smp_processor_id()];
72b2b1dd 2138 xt_entry_foreach(iter, loc_cpu_entry, private->size)
0559518b 2139 cleanup_entry(iter, net);
df200969
AD
2140 if (private->number > private->initial_entries)
2141 module_put(table_owner);
2e4e6a17 2142 xt_free_table_info(private);
1da177e4
LT
2143}
2144
2145/* Returns 1 if the type and code is matched by the range, 0 otherwise */
ccb79bdc 2146static inline bool
1da177e4
LT
2147icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2148 u_int8_t type, u_int8_t code,
ccb79bdc 2149 bool invert)
1da177e4
LT
2150{
2151 return (type == test_type && code >= min_code && code <= max_code)
2152 ^ invert;
2153}
2154
1d93a9cb 2155static bool
62fc8051 2156icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
1da177e4 2157{
5452e425
JE
2158 const struct icmp6hdr *ic;
2159 struct icmp6hdr _icmph;
f7108a20 2160 const struct ip6t_icmp *icmpinfo = par->matchinfo;
1da177e4
LT
2161
2162 /* Must not be a fragment. */
f7108a20 2163 if (par->fragoff != 0)
1d93a9cb 2164 return false;
1da177e4 2165
f7108a20 2166 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
1da177e4
LT
2167 if (ic == NULL) {
2168 /* We've been asked to examine this packet, and we
9c547959
PM
2169 * can't. Hence, no choice but to drop.
2170 */
1da177e4 2171 duprintf("Dropping evil ICMP tinygram.\n");
b4ba2611 2172 par->hotdrop = true;
1d93a9cb 2173 return false;
1da177e4
LT
2174 }
2175
2176 return icmp6_type_code_match(icmpinfo->type,
2177 icmpinfo->code[0],
2178 icmpinfo->code[1],
2179 ic->icmp6_type, ic->icmp6_code,
2180 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2181}
2182
2183/* Called when user tries to insert an entry of this type. */
b0f38452 2184static int icmp6_checkentry(const struct xt_mtchk_param *par)
1da177e4 2185{
9b4fce7a 2186 const struct ip6t_icmp *icmpinfo = par->matchinfo;
1da177e4 2187
7f939713 2188 /* Must specify no unknown invflags */
bd414ee6 2189 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
1da177e4
LT
2190}
2191
2192/* The built-in targets: standard (NULL) and error. */
4538506b
JE
2193static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2194 {
243bf6e2 2195 .name = XT_STANDARD_TARGET,
4538506b
JE
2196 .targetsize = sizeof(int),
2197 .family = NFPROTO_IPV6,
3bc3fe5e 2198#ifdef CONFIG_COMPAT
4538506b
JE
2199 .compatsize = sizeof(compat_int_t),
2200 .compat_from_user = compat_standard_from_user,
2201 .compat_to_user = compat_standard_to_user,
3bc3fe5e 2202#endif
4538506b
JE
2203 },
2204 {
243bf6e2 2205 .name = XT_ERROR_TARGET,
4538506b 2206 .target = ip6t_error,
12b00c2c 2207 .targetsize = XT_FUNCTION_MAXNAMELEN,
4538506b
JE
2208 .family = NFPROTO_IPV6,
2209 },
1da177e4
LT
2210};
2211
2212static struct nf_sockopt_ops ip6t_sockopts = {
2213 .pf = PF_INET6,
2214 .set_optmin = IP6T_BASE_CTL,
2215 .set_optmax = IP6T_SO_SET_MAX+1,
2216 .set = do_ip6t_set_ctl,
3bc3fe5e
PM
2217#ifdef CONFIG_COMPAT
2218 .compat_set = compat_do_ip6t_set_ctl,
2219#endif
1da177e4
LT
2220 .get_optmin = IP6T_BASE_CTL,
2221 .get_optmax = IP6T_SO_GET_MAX+1,
2222 .get = do_ip6t_get_ctl,
3bc3fe5e
PM
2223#ifdef CONFIG_COMPAT
2224 .compat_get = compat_do_ip6t_get_ctl,
2225#endif
16fcec35 2226 .owner = THIS_MODULE,
1da177e4
LT
2227};
2228
4538506b
JE
2229static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2230 {
2231 .name = "icmp6",
2232 .match = icmp6_match,
2233 .matchsize = sizeof(struct ip6t_icmp),
2234 .checkentry = icmp6_checkentry,
2235 .proto = IPPROTO_ICMPV6,
2236 .family = NFPROTO_IPV6,
2237 },
1da177e4
LT
2238};
2239
3cb609d5
AD
2240static int __net_init ip6_tables_net_init(struct net *net)
2241{
383ca5b8 2242 return xt_proto_init(net, NFPROTO_IPV6);
3cb609d5
AD
2243}
2244
2245static void __net_exit ip6_tables_net_exit(struct net *net)
2246{
383ca5b8 2247 xt_proto_fini(net, NFPROTO_IPV6);
3cb609d5
AD
2248}
2249
2250static struct pernet_operations ip6_tables_net_ops = {
2251 .init = ip6_tables_net_init,
2252 .exit = ip6_tables_net_exit,
2253};
2254
65b4b4e8 2255static int __init ip6_tables_init(void)
1da177e4
LT
2256{
2257 int ret;
2258
3cb609d5 2259 ret = register_pernet_subsys(&ip6_tables_net_ops);
0eff66e6
PM
2260 if (ret < 0)
2261 goto err1;
2e4e6a17 2262
1da177e4 2263 /* Noone else will be downing sem now, so we won't sleep */
4538506b 2264 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
0eff66e6
PM
2265 if (ret < 0)
2266 goto err2;
4538506b 2267 ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
0eff66e6
PM
2268 if (ret < 0)
2269 goto err4;
1da177e4
LT
2270
2271 /* Register setsockopt */
2272 ret = nf_register_sockopt(&ip6t_sockopts);
0eff66e6
PM
2273 if (ret < 0)
2274 goto err5;
1da177e4 2275
ff67e4e4 2276 pr_info("(C) 2000-2006 Netfilter Core Team\n");
1da177e4 2277 return 0;
0eff66e6
PM
2278
2279err5:
4538506b 2280 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
0eff66e6 2281err4:
4538506b 2282 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
0eff66e6 2283err2:
3cb609d5 2284 unregister_pernet_subsys(&ip6_tables_net_ops);
0eff66e6
PM
2285err1:
2286 return ret;
1da177e4
LT
2287}
2288
65b4b4e8 2289static void __exit ip6_tables_fini(void)
1da177e4
LT
2290{
2291 nf_unregister_sockopt(&ip6t_sockopts);
9c547959 2292
4538506b
JE
2293 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2294 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
3cb609d5 2295 unregister_pernet_subsys(&ip6_tables_net_ops);
1da177e4
LT
2296}
2297
e674d0f3 2298/*
b777e0ce
PM
2299 * find the offset to specified header or the protocol number of last header
2300 * if target < 0. "last header" is transport protocol header, ESP, or
2301 * "No next header".
2302 *
2303 * If target header is found, its offset is set in *offset and return protocol
2304 * number. Otherwise, return -1.
2305 *
6d381634
PM
2306 * If the first fragment doesn't contain the final protocol header or
2307 * NEXTHDR_NONE it is considered invalid.
2308 *
b777e0ce
PM
2309 * Note that non-1st fragment is special case that "the protocol number
2310 * of last header" is "next header" field in Fragment header. In this case,
2311 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2312 * isn't NULL.
e674d0f3 2313 *
e674d0f3 2314 */
b777e0ce
PM
2315int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2316 int target, unsigned short *fragoff)
e674d0f3 2317{
6b88dd96 2318 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
0660e03f 2319 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
e674d0f3
YK
2320 unsigned int len = skb->len - start;
2321
b777e0ce
PM
2322 if (fragoff)
2323 *fragoff = 0;
2324
e674d0f3
YK
2325 while (nexthdr != target) {
2326 struct ipv6_opt_hdr _hdr, *hp;
2327 unsigned int hdrlen;
2328
b777e0ce
PM
2329 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2330 if (target < 0)
2331 break;
6d381634 2332 return -ENOENT;
b777e0ce
PM
2333 }
2334
e674d0f3
YK
2335 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2336 if (hp == NULL)
6d381634 2337 return -EBADMSG;
e674d0f3 2338 if (nexthdr == NEXTHDR_FRAGMENT) {
e69a4adc
AV
2339 unsigned short _frag_off;
2340 __be16 *fp;
e674d0f3
YK
2341 fp = skb_header_pointer(skb,
2342 start+offsetof(struct frag_hdr,
2343 frag_off),
2344 sizeof(_frag_off),
2345 &_frag_off);
2346 if (fp == NULL)
6d381634 2347 return -EBADMSG;
e674d0f3 2348
b777e0ce
PM
2349 _frag_off = ntohs(*fp) & ~0x7;
2350 if (_frag_off) {
2351 if (target < 0 &&
2352 ((!ipv6_ext_hdr(hp->nexthdr)) ||
337dde79 2353 hp->nexthdr == NEXTHDR_NONE)) {
b777e0ce
PM
2354 if (fragoff)
2355 *fragoff = _frag_off;
2356 return hp->nexthdr;
2357 }
6d381634 2358 return -ENOENT;
b777e0ce 2359 }
e674d0f3
YK
2360 hdrlen = 8;
2361 } else if (nexthdr == NEXTHDR_AUTH)
1ab1457c 2362 hdrlen = (hp->hdrlen + 2) << 2;
e674d0f3 2363 else
1ab1457c 2364 hdrlen = ipv6_optlen(hp);
e674d0f3
YK
2365
2366 nexthdr = hp->nexthdr;
2367 len -= hdrlen;
2368 start += hdrlen;
2369 }
2370
2371 *offset = start;
b777e0ce 2372 return nexthdr;
e674d0f3
YK
2373}
2374
1da177e4
LT
2375EXPORT_SYMBOL(ip6t_register_table);
2376EXPORT_SYMBOL(ip6t_unregister_table);
2377EXPORT_SYMBOL(ip6t_do_table);
1da177e4 2378EXPORT_SYMBOL(ip6t_ext_hdr);
e674d0f3 2379EXPORT_SYMBOL(ipv6_find_hdr);
1da177e4 2380
65b4b4e8
AM
2381module_init(ip6_tables_init);
2382module_exit(ip6_tables_fini);