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