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