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