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