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