netfilter: xtables: use memcmp in unconditional check
[safe/jmp/linux-2.6] / net / ipv6 / netfilter / ip6_tables.c
1 /*
2  * Packet matching code.
3  *
4  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5  * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/capability.h>
13 #include <linux/in.h>
14 #include <linux/skbuff.h>
15 #include <linux/kmod.h>
16 #include <linux/vmalloc.h>
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <linux/poison.h>
20 #include <linux/icmpv6.h>
21 #include <net/ipv6.h>
22 #include <net/compat.h>
23 #include <asm/uaccess.h>
24 #include <linux/mutex.h>
25 #include <linux/proc_fs.h>
26 #include <linux/err.h>
27 #include <linux/cpumask.h>
28
29 #include <linux/netfilter_ipv6/ip6_tables.h>
30 #include <linux/netfilter/x_tables.h>
31 #include <net/netfilter/nf_log.h>
32
33 MODULE_LICENSE("GPL");
34 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
35 MODULE_DESCRIPTION("IPv6 packet filter");
36
37 /*#define DEBUG_IP_FIREWALL*/
38 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
39 /*#define DEBUG_IP_FIREWALL_USER*/
40
41 #ifdef DEBUG_IP_FIREWALL
42 #define dprintf(format, args...)  printk(format , ## args)
43 #else
44 #define dprintf(format, args...)
45 #endif
46
47 #ifdef DEBUG_IP_FIREWALL_USER
48 #define duprintf(format, args...) printk(format , ## args)
49 #else
50 #define duprintf(format, args...)
51 #endif
52
53 #ifdef CONFIG_NETFILTER_DEBUG
54 #define IP_NF_ASSERT(x)                                         \
55 do {                                                            \
56         if (!(x))                                               \
57                 printk("IP_NF_ASSERT: %s:%s:%u\n",              \
58                        __func__, __FILE__, __LINE__);   \
59 } while(0)
60 #else
61 #define IP_NF_ASSERT(x)
62 #endif
63
64 #if 0
65 /* All the better to debug you with... */
66 #define static
67 #define inline
68 #endif
69
70 /*
71    We keep a set of rules for each CPU, so we can avoid write-locking
72    them in the softirq when updating the counters and therefore
73    only need to read-lock in the softirq; doing a write_lock_bh() in user
74    context stops packets coming through and allows user context to read
75    the counters or update the rules.
76
77    Hence the start of any table is given by get_table() below.  */
78
79 /* Check for an extension */
80 int
81 ip6t_ext_hdr(u8 nexthdr)
82 {
83         return ( (nexthdr == IPPROTO_HOPOPTS)   ||
84                  (nexthdr == IPPROTO_ROUTING)   ||
85                  (nexthdr == IPPROTO_FRAGMENT)  ||
86                  (nexthdr == IPPROTO_ESP)       ||
87                  (nexthdr == IPPROTO_AH)        ||
88                  (nexthdr == IPPROTO_NONE)      ||
89                  (nexthdr == IPPROTO_DSTOPTS) );
90 }
91
92 /* 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 int
744 check_entry_size_and_hooks(struct ip6t_entry *e,
745                            struct xt_table_info *newinfo,
746                            unsigned char *base,
747                            unsigned char *limit,
748                            const unsigned int *hook_entries,
749                            const unsigned int *underflows,
750                            unsigned int *i)
751 {
752         unsigned int h;
753
754         if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
755             || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
756                 duprintf("Bad offset %p\n", e);
757                 return -EINVAL;
758         }
759
760         if (e->next_offset
761             < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
762                 duprintf("checking: element %p size %u\n",
763                          e, e->next_offset);
764                 return -EINVAL;
765         }
766
767         /* Check hooks & underflows */
768         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
769                 if ((unsigned char *)e - base == hook_entries[h])
770                         newinfo->hook_entry[h] = hook_entries[h];
771                 if ((unsigned char *)e - base == underflows[h])
772                         newinfo->underflow[h] = underflows[h];
773         }
774
775         /* FIXME: underflows must be unconditional, standard verdicts
776            < 0 (not IP6T_RETURN). --RR */
777
778         /* Clear counters and comefrom */
779         e->counters = ((struct xt_counters) { 0, 0 });
780         e->comefrom = 0;
781
782         (*i)++;
783         return 0;
784 }
785
786 static int
787 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
788 {
789         struct xt_tgdtor_param par;
790         struct ip6t_entry_target *t;
791
792         if (i && (*i)-- == 0)
793                 return 1;
794
795         /* Cleanup all matches */
796         IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
797         t = ip6t_get_target(e);
798
799         par.target   = t->u.kernel.target;
800         par.targinfo = t->data;
801         par.family   = NFPROTO_IPV6;
802         if (par.target->destroy != NULL)
803                 par.target->destroy(&par);
804         module_put(par.target->me);
805         return 0;
806 }
807
808 /* Checks and translates the user-supplied table segment (held in
809    newinfo) */
810 static int
811 translate_table(const char *name,
812                 unsigned int valid_hooks,
813                 struct xt_table_info *newinfo,
814                 void *entry0,
815                 unsigned int size,
816                 unsigned int number,
817                 const unsigned int *hook_entries,
818                 const unsigned int *underflows)
819 {
820         unsigned int i;
821         int ret;
822
823         newinfo->size = size;
824         newinfo->number = number;
825
826         /* Init all hooks to impossible value. */
827         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
828                 newinfo->hook_entry[i] = 0xFFFFFFFF;
829                 newinfo->underflow[i] = 0xFFFFFFFF;
830         }
831
832         duprintf("translate_table: size %u\n", newinfo->size);
833         i = 0;
834         /* Walk through entries, checking offsets. */
835         ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
836                                 check_entry_size_and_hooks,
837                                 newinfo,
838                                 entry0,
839                                 entry0 + size,
840                                 hook_entries, underflows, &i);
841         if (ret != 0)
842                 return ret;
843
844         if (i != number) {
845                 duprintf("translate_table: %u not %u entries\n",
846                          i, number);
847                 return -EINVAL;
848         }
849
850         /* Check hooks all assigned */
851         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
852                 /* Only hooks which are valid */
853                 if (!(valid_hooks & (1 << i)))
854                         continue;
855                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
856                         duprintf("Invalid hook entry %u %u\n",
857                                  i, hook_entries[i]);
858                         return -EINVAL;
859                 }
860                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
861                         duprintf("Invalid underflow %u %u\n",
862                                  i, underflows[i]);
863                         return -EINVAL;
864                 }
865         }
866
867         if (!mark_source_chains(newinfo, valid_hooks, entry0))
868                 return -ELOOP;
869
870         /* Finally, each sanity check must pass */
871         i = 0;
872         ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
873                                 find_check_entry, name, size, &i);
874
875         if (ret != 0) {
876                 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
877                                    cleanup_entry, &i);
878                 return ret;
879         }
880
881         /* And one copy for every other CPU */
882         for_each_possible_cpu(i) {
883                 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
884                         memcpy(newinfo->entries[i], entry0, newinfo->size);
885         }
886
887         return ret;
888 }
889
890 /* Gets counters. */
891 static inline int
892 add_entry_to_counter(const struct ip6t_entry *e,
893                      struct xt_counters total[],
894                      unsigned int *i)
895 {
896         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
897
898         (*i)++;
899         return 0;
900 }
901
902 static inline int
903 set_entry_to_counter(const struct ip6t_entry *e,
904                      struct ip6t_counters total[],
905                      unsigned int *i)
906 {
907         SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
908
909         (*i)++;
910         return 0;
911 }
912
913 static void
914 get_counters(const struct xt_table_info *t,
915              struct xt_counters counters[])
916 {
917         unsigned int cpu;
918         unsigned int i;
919         unsigned int curcpu;
920
921         /* Instead of clearing (by a previous call to memset())
922          * the counters and using adds, we set the counters
923          * with data used by 'current' CPU
924          *
925          * Bottom half has to be disabled to prevent deadlock
926          * if new softirq were to run and call ipt_do_table
927          */
928         local_bh_disable();
929         curcpu = smp_processor_id();
930
931         i = 0;
932         IP6T_ENTRY_ITERATE(t->entries[curcpu],
933                            t->size,
934                            set_entry_to_counter,
935                            counters,
936                            &i);
937
938         for_each_possible_cpu(cpu) {
939                 if (cpu == curcpu)
940                         continue;
941                 i = 0;
942                 xt_info_wrlock(cpu);
943                 IP6T_ENTRY_ITERATE(t->entries[cpu],
944                                   t->size,
945                                   add_entry_to_counter,
946                                   counters,
947                                   &i);
948                 xt_info_wrunlock(cpu);
949         }
950         local_bh_enable();
951 }
952
953 static struct xt_counters *alloc_counters(struct xt_table *table)
954 {
955         unsigned int countersize;
956         struct xt_counters *counters;
957         struct xt_table_info *private = table->private;
958
959         /* We need atomic snapshot of counters: rest doesn't change
960            (other than comefrom, which userspace doesn't care
961            about). */
962         countersize = sizeof(struct xt_counters) * private->number;
963         counters = vmalloc_node(countersize, numa_node_id());
964
965         if (counters == NULL)
966                 return ERR_PTR(-ENOMEM);
967
968         get_counters(private, counters);
969
970         return counters;
971 }
972
973 static int
974 copy_entries_to_user(unsigned int total_size,
975                      struct xt_table *table,
976                      void __user *userptr)
977 {
978         unsigned int off, num;
979         struct ip6t_entry *e;
980         struct xt_counters *counters;
981         const struct xt_table_info *private = table->private;
982         int ret = 0;
983         const void *loc_cpu_entry;
984
985         counters = alloc_counters(table);
986         if (IS_ERR(counters))
987                 return PTR_ERR(counters);
988
989         /* choose the copy that is on our node/cpu, ...
990          * This choice is lazy (because current thread is
991          * allowed to migrate to another cpu)
992          */
993         loc_cpu_entry = private->entries[raw_smp_processor_id()];
994         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
995                 ret = -EFAULT;
996                 goto free_counters;
997         }
998
999         /* FIXME: use iterator macros --RR */
1000         /* ... then go back and fix counters and names */
1001         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1002                 unsigned int i;
1003                 const struct ip6t_entry_match *m;
1004                 const struct ip6t_entry_target *t;
1005
1006                 e = (struct ip6t_entry *)(loc_cpu_entry + off);
1007                 if (copy_to_user(userptr + off
1008                                  + offsetof(struct ip6t_entry, counters),
1009                                  &counters[num],
1010                                  sizeof(counters[num])) != 0) {
1011                         ret = -EFAULT;
1012                         goto free_counters;
1013                 }
1014
1015                 for (i = sizeof(struct ip6t_entry);
1016                      i < e->target_offset;
1017                      i += m->u.match_size) {
1018                         m = (void *)e + i;
1019
1020                         if (copy_to_user(userptr + off + i
1021                                          + offsetof(struct ip6t_entry_match,
1022                                                     u.user.name),
1023                                          m->u.kernel.match->name,
1024                                          strlen(m->u.kernel.match->name)+1)
1025                             != 0) {
1026                                 ret = -EFAULT;
1027                                 goto free_counters;
1028                         }
1029                 }
1030
1031                 t = ip6t_get_target(e);
1032                 if (copy_to_user(userptr + off + e->target_offset
1033                                  + offsetof(struct ip6t_entry_target,
1034                                             u.user.name),
1035                                  t->u.kernel.target->name,
1036                                  strlen(t->u.kernel.target->name)+1) != 0) {
1037                         ret = -EFAULT;
1038                         goto free_counters;
1039                 }
1040         }
1041
1042  free_counters:
1043         vfree(counters);
1044         return ret;
1045 }
1046
1047 #ifdef CONFIG_COMPAT
1048 static void compat_standard_from_user(void *dst, void *src)
1049 {
1050         int v = *(compat_int_t *)src;
1051
1052         if (v > 0)
1053                 v += xt_compat_calc_jump(AF_INET6, v);
1054         memcpy(dst, &v, sizeof(v));
1055 }
1056
1057 static int compat_standard_to_user(void __user *dst, void *src)
1058 {
1059         compat_int_t cv = *(int *)src;
1060
1061         if (cv > 0)
1062                 cv -= xt_compat_calc_jump(AF_INET6, cv);
1063         return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1064 }
1065
1066 static inline int
1067 compat_calc_match(struct ip6t_entry_match *m, int *size)
1068 {
1069         *size += xt_compat_match_offset(m->u.kernel.match);
1070         return 0;
1071 }
1072
1073 static int compat_calc_entry(struct ip6t_entry *e,
1074                              const struct xt_table_info *info,
1075                              void *base, struct xt_table_info *newinfo)
1076 {
1077         struct ip6t_entry_target *t;
1078         unsigned int entry_offset;
1079         int off, i, ret;
1080
1081         off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1082         entry_offset = (void *)e - base;
1083         IP6T_MATCH_ITERATE(e, compat_calc_match, &off);
1084         t = ip6t_get_target(e);
1085         off += xt_compat_target_offset(t->u.kernel.target);
1086         newinfo->size -= off;
1087         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1088         if (ret)
1089                 return ret;
1090
1091         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1092                 if (info->hook_entry[i] &&
1093                     (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1094                         newinfo->hook_entry[i] -= off;
1095                 if (info->underflow[i] &&
1096                     (e < (struct ip6t_entry *)(base + info->underflow[i])))
1097                         newinfo->underflow[i] -= off;
1098         }
1099         return 0;
1100 }
1101
1102 static int compat_table_info(const struct xt_table_info *info,
1103                              struct xt_table_info *newinfo)
1104 {
1105         void *loc_cpu_entry;
1106
1107         if (!newinfo || !info)
1108                 return -EINVAL;
1109
1110         /* we dont care about newinfo->entries[] */
1111         memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1112         newinfo->initial_entries = 0;
1113         loc_cpu_entry = info->entries[raw_smp_processor_id()];
1114         return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size,
1115                                   compat_calc_entry, info, loc_cpu_entry,
1116                                   newinfo);
1117 }
1118 #endif
1119
1120 static int get_info(struct net *net, void __user *user, int *len, int compat)
1121 {
1122         char name[IP6T_TABLE_MAXNAMELEN];
1123         struct xt_table *t;
1124         int ret;
1125
1126         if (*len != sizeof(struct ip6t_getinfo)) {
1127                 duprintf("length %u != %zu\n", *len,
1128                          sizeof(struct ip6t_getinfo));
1129                 return -EINVAL;
1130         }
1131
1132         if (copy_from_user(name, user, sizeof(name)) != 0)
1133                 return -EFAULT;
1134
1135         name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1136 #ifdef CONFIG_COMPAT
1137         if (compat)
1138                 xt_compat_lock(AF_INET6);
1139 #endif
1140         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1141                                     "ip6table_%s", name);
1142         if (t && !IS_ERR(t)) {
1143                 struct ip6t_getinfo info;
1144                 const struct xt_table_info *private = t->private;
1145
1146 #ifdef CONFIG_COMPAT
1147                 if (compat) {
1148                         struct xt_table_info tmp;
1149                         ret = compat_table_info(private, &tmp);
1150                         xt_compat_flush_offsets(AF_INET6);
1151                         private = &tmp;
1152                 }
1153 #endif
1154                 info.valid_hooks = t->valid_hooks;
1155                 memcpy(info.hook_entry, private->hook_entry,
1156                        sizeof(info.hook_entry));
1157                 memcpy(info.underflow, private->underflow,
1158                        sizeof(info.underflow));
1159                 info.num_entries = private->number;
1160                 info.size = private->size;
1161                 strcpy(info.name, name);
1162
1163                 if (copy_to_user(user, &info, *len) != 0)
1164                         ret = -EFAULT;
1165                 else
1166                         ret = 0;
1167
1168                 xt_table_unlock(t);
1169                 module_put(t->me);
1170         } else
1171                 ret = t ? PTR_ERR(t) : -ENOENT;
1172 #ifdef CONFIG_COMPAT
1173         if (compat)
1174                 xt_compat_unlock(AF_INET6);
1175 #endif
1176         return ret;
1177 }
1178
1179 static int
1180 get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
1181 {
1182         int ret;
1183         struct ip6t_get_entries get;
1184         struct xt_table *t;
1185
1186         if (*len < sizeof(get)) {
1187                 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1188                 return -EINVAL;
1189         }
1190         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1191                 return -EFAULT;
1192         if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1193                 duprintf("get_entries: %u != %zu\n",
1194                          *len, sizeof(get) + get.size);
1195                 return -EINVAL;
1196         }
1197
1198         t = xt_find_table_lock(net, AF_INET6, get.name);
1199         if (t && !IS_ERR(t)) {
1200                 struct xt_table_info *private = t->private;
1201                 duprintf("t->private->number = %u\n", private->number);
1202                 if (get.size == private->size)
1203                         ret = copy_entries_to_user(private->size,
1204                                                    t, uptr->entrytable);
1205                 else {
1206                         duprintf("get_entries: I've got %u not %u!\n",
1207                                  private->size, get.size);
1208                         ret = -EAGAIN;
1209                 }
1210                 module_put(t->me);
1211                 xt_table_unlock(t);
1212         } else
1213                 ret = t ? PTR_ERR(t) : -ENOENT;
1214
1215         return ret;
1216 }
1217
1218 static int
1219 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1220              struct xt_table_info *newinfo, unsigned int num_counters,
1221              void __user *counters_ptr)
1222 {
1223         int ret;
1224         struct xt_table *t;
1225         struct xt_table_info *oldinfo;
1226         struct xt_counters *counters;
1227         const void *loc_cpu_old_entry;
1228
1229         ret = 0;
1230         counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
1231                                 numa_node_id());
1232         if (!counters) {
1233                 ret = -ENOMEM;
1234                 goto out;
1235         }
1236
1237         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1238                                     "ip6table_%s", name);
1239         if (!t || IS_ERR(t)) {
1240                 ret = t ? PTR_ERR(t) : -ENOENT;
1241                 goto free_newinfo_counters_untrans;
1242         }
1243
1244         /* You lied! */
1245         if (valid_hooks != t->valid_hooks) {
1246                 duprintf("Valid hook crap: %08X vs %08X\n",
1247                          valid_hooks, t->valid_hooks);
1248                 ret = -EINVAL;
1249                 goto put_module;
1250         }
1251
1252         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1253         if (!oldinfo)
1254                 goto put_module;
1255
1256         /* Update module usage count based on number of rules */
1257         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1258                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1259         if ((oldinfo->number > oldinfo->initial_entries) ||
1260             (newinfo->number <= oldinfo->initial_entries))
1261                 module_put(t->me);
1262         if ((oldinfo->number > oldinfo->initial_entries) &&
1263             (newinfo->number <= oldinfo->initial_entries))
1264                 module_put(t->me);
1265
1266         /* Get the old counters, and synchronize with replace */
1267         get_counters(oldinfo, counters);
1268
1269         /* Decrease module usage counts and free resource */
1270         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1271         IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1272                            NULL);
1273         xt_free_table_info(oldinfo);
1274         if (copy_to_user(counters_ptr, counters,
1275                          sizeof(struct xt_counters) * num_counters) != 0)
1276                 ret = -EFAULT;
1277         vfree(counters);
1278         xt_table_unlock(t);
1279         return ret;
1280
1281  put_module:
1282         module_put(t->me);
1283         xt_table_unlock(t);
1284  free_newinfo_counters_untrans:
1285         vfree(counters);
1286  out:
1287         return ret;
1288 }
1289
1290 static int
1291 do_replace(struct net *net, void __user *user, unsigned int len)
1292 {
1293         int ret;
1294         struct ip6t_replace tmp;
1295         struct xt_table_info *newinfo;
1296         void *loc_cpu_entry;
1297
1298         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1299                 return -EFAULT;
1300
1301         /* overflow check */
1302         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1303                 return -ENOMEM;
1304
1305         newinfo = xt_alloc_table_info(tmp.size);
1306         if (!newinfo)
1307                 return -ENOMEM;
1308
1309         /* choose the copy that is on our node/cpu */
1310         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1311         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1312                            tmp.size) != 0) {
1313                 ret = -EFAULT;
1314                 goto free_newinfo;
1315         }
1316
1317         ret = translate_table(tmp.name, tmp.valid_hooks,
1318                               newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1319                               tmp.hook_entry, tmp.underflow);
1320         if (ret != 0)
1321                 goto free_newinfo;
1322
1323         duprintf("ip_tables: Translated table\n");
1324
1325         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1326                            tmp.num_counters, tmp.counters);
1327         if (ret)
1328                 goto free_newinfo_untrans;
1329         return 0;
1330
1331  free_newinfo_untrans:
1332         IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1333  free_newinfo:
1334         xt_free_table_info(newinfo);
1335         return ret;
1336 }
1337
1338 /* We're lazy, and add to the first CPU; overflow works its fey magic
1339  * and everything is OK. */
1340 static int
1341 add_counter_to_entry(struct ip6t_entry *e,
1342                      const struct xt_counters addme[],
1343                      unsigned int *i)
1344 {
1345         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1346
1347         (*i)++;
1348         return 0;
1349 }
1350
1351 static int
1352 do_add_counters(struct net *net, void __user *user, unsigned int len,
1353                 int compat)
1354 {
1355         unsigned int i, curcpu;
1356         struct xt_counters_info tmp;
1357         struct xt_counters *paddc;
1358         unsigned int num_counters;
1359         char *name;
1360         int size;
1361         void *ptmp;
1362         struct xt_table *t;
1363         const struct xt_table_info *private;
1364         int ret = 0;
1365         const void *loc_cpu_entry;
1366 #ifdef CONFIG_COMPAT
1367         struct compat_xt_counters_info compat_tmp;
1368
1369         if (compat) {
1370                 ptmp = &compat_tmp;
1371                 size = sizeof(struct compat_xt_counters_info);
1372         } else
1373 #endif
1374         {
1375                 ptmp = &tmp;
1376                 size = sizeof(struct xt_counters_info);
1377         }
1378
1379         if (copy_from_user(ptmp, user, size) != 0)
1380                 return -EFAULT;
1381
1382 #ifdef CONFIG_COMPAT
1383         if (compat) {
1384                 num_counters = compat_tmp.num_counters;
1385                 name = compat_tmp.name;
1386         } else
1387 #endif
1388         {
1389                 num_counters = tmp.num_counters;
1390                 name = tmp.name;
1391         }
1392
1393         if (len != size + num_counters * sizeof(struct xt_counters))
1394                 return -EINVAL;
1395
1396         paddc = vmalloc_node(len - size, numa_node_id());
1397         if (!paddc)
1398                 return -ENOMEM;
1399
1400         if (copy_from_user(paddc, user + size, len - size) != 0) {
1401                 ret = -EFAULT;
1402                 goto free;
1403         }
1404
1405         t = xt_find_table_lock(net, AF_INET6, name);
1406         if (!t || IS_ERR(t)) {
1407                 ret = t ? PTR_ERR(t) : -ENOENT;
1408                 goto free;
1409         }
1410
1411
1412         local_bh_disable();
1413         private = t->private;
1414         if (private->number != num_counters) {
1415                 ret = -EINVAL;
1416                 goto unlock_up_free;
1417         }
1418
1419         i = 0;
1420         /* Choose the copy that is on our node */
1421         curcpu = smp_processor_id();
1422         xt_info_wrlock(curcpu);
1423         loc_cpu_entry = private->entries[curcpu];
1424         IP6T_ENTRY_ITERATE(loc_cpu_entry,
1425                           private->size,
1426                           add_counter_to_entry,
1427                           paddc,
1428                           &i);
1429         xt_info_wrunlock(curcpu);
1430
1431  unlock_up_free:
1432         local_bh_enable();
1433         xt_table_unlock(t);
1434         module_put(t->me);
1435  free:
1436         vfree(paddc);
1437
1438         return ret;
1439 }
1440
1441 #ifdef CONFIG_COMPAT
1442 struct compat_ip6t_replace {
1443         char                    name[IP6T_TABLE_MAXNAMELEN];
1444         u32                     valid_hooks;
1445         u32                     num_entries;
1446         u32                     size;
1447         u32                     hook_entry[NF_INET_NUMHOOKS];
1448         u32                     underflow[NF_INET_NUMHOOKS];
1449         u32                     num_counters;
1450         compat_uptr_t           counters;       /* struct ip6t_counters * */
1451         struct compat_ip6t_entry entries[0];
1452 };
1453
1454 static int
1455 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1456                           unsigned int *size, struct xt_counters *counters,
1457                           unsigned int *i)
1458 {
1459         struct ip6t_entry_target *t;
1460         struct compat_ip6t_entry __user *ce;
1461         u_int16_t target_offset, next_offset;
1462         compat_uint_t origsize;
1463         int ret;
1464
1465         ret = -EFAULT;
1466         origsize = *size;
1467         ce = (struct compat_ip6t_entry __user *)*dstptr;
1468         if (copy_to_user(ce, e, sizeof(struct ip6t_entry)))
1469                 goto out;
1470
1471         if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1472                 goto out;
1473
1474         *dstptr += sizeof(struct compat_ip6t_entry);
1475         *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1476
1477         ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1478         target_offset = e->target_offset - (origsize - *size);
1479         if (ret)
1480                 goto out;
1481         t = ip6t_get_target(e);
1482         ret = xt_compat_target_to_user(t, dstptr, size);
1483         if (ret)
1484                 goto out;
1485         ret = -EFAULT;
1486         next_offset = e->next_offset - (origsize - *size);
1487         if (put_user(target_offset, &ce->target_offset))
1488                 goto out;
1489         if (put_user(next_offset, &ce->next_offset))
1490                 goto out;
1491
1492         (*i)++;
1493         return 0;
1494 out:
1495         return ret;
1496 }
1497
1498 static int
1499 compat_find_calc_match(struct ip6t_entry_match *m,
1500                        const char *name,
1501                        const struct ip6t_ip6 *ipv6,
1502                        unsigned int hookmask,
1503                        int *size, unsigned int *i)
1504 {
1505         struct xt_match *match;
1506
1507         match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
1508                                                       m->u.user.revision),
1509                                         "ip6t_%s", m->u.user.name);
1510         if (IS_ERR(match) || !match) {
1511                 duprintf("compat_check_calc_match: `%s' not found\n",
1512                          m->u.user.name);
1513                 return match ? PTR_ERR(match) : -ENOENT;
1514         }
1515         m->u.kernel.match = match;
1516         *size += xt_compat_match_offset(match);
1517
1518         (*i)++;
1519         return 0;
1520 }
1521
1522 static int
1523 compat_release_match(struct ip6t_entry_match *m, unsigned int *i)
1524 {
1525         if (i && (*i)-- == 0)
1526                 return 1;
1527
1528         module_put(m->u.kernel.match->me);
1529         return 0;
1530 }
1531
1532 static int
1533 compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i)
1534 {
1535         struct ip6t_entry_target *t;
1536
1537         if (i && (*i)-- == 0)
1538                 return 1;
1539
1540         /* Cleanup all matches */
1541         COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL);
1542         t = compat_ip6t_get_target(e);
1543         module_put(t->u.kernel.target->me);
1544         return 0;
1545 }
1546
1547 static int
1548 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1549                                   struct xt_table_info *newinfo,
1550                                   unsigned int *size,
1551                                   unsigned char *base,
1552                                   unsigned char *limit,
1553                                   unsigned int *hook_entries,
1554                                   unsigned int *underflows,
1555                                   unsigned int *i,
1556                                   const char *name)
1557 {
1558         struct ip6t_entry_target *t;
1559         struct xt_target *target;
1560         unsigned int entry_offset;
1561         unsigned int j;
1562         int ret, off, h;
1563
1564         duprintf("check_compat_entry_size_and_hooks %p\n", e);
1565         if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0
1566             || (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1567                 duprintf("Bad offset %p, limit = %p\n", e, limit);
1568                 return -EINVAL;
1569         }
1570
1571         if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1572                              sizeof(struct compat_xt_entry_target)) {
1573                 duprintf("checking: element %p size %u\n",
1574                          e, e->next_offset);
1575                 return -EINVAL;
1576         }
1577
1578         /* For purposes of check_entry casting the compat entry is fine */
1579         ret = check_entry((struct ip6t_entry *)e, name);
1580         if (ret)
1581                 return ret;
1582
1583         off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1584         entry_offset = (void *)e - (void *)base;
1585         j = 0;
1586         ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name,
1587                                         &e->ipv6, e->comefrom, &off, &j);
1588         if (ret != 0)
1589                 goto release_matches;
1590
1591         t = compat_ip6t_get_target(e);
1592         target = try_then_request_module(xt_find_target(AF_INET6,
1593                                                         t->u.user.name,
1594                                                         t->u.user.revision),
1595                                          "ip6t_%s", t->u.user.name);
1596         if (IS_ERR(target) || !target) {
1597                 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1598                          t->u.user.name);
1599                 ret = target ? PTR_ERR(target) : -ENOENT;
1600                 goto release_matches;
1601         }
1602         t->u.kernel.target = target;
1603
1604         off += xt_compat_target_offset(target);
1605         *size += off;
1606         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1607         if (ret)
1608                 goto out;
1609
1610         /* Check hooks & underflows */
1611         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1612                 if ((unsigned char *)e - base == hook_entries[h])
1613                         newinfo->hook_entry[h] = hook_entries[h];
1614                 if ((unsigned char *)e - base == underflows[h])
1615                         newinfo->underflow[h] = underflows[h];
1616         }
1617
1618         /* Clear counters and comefrom */
1619         memset(&e->counters, 0, sizeof(e->counters));
1620         e->comefrom = 0;
1621
1622         (*i)++;
1623         return 0;
1624
1625 out:
1626         module_put(t->u.kernel.target->me);
1627 release_matches:
1628         IP6T_MATCH_ITERATE(e, compat_release_match, &j);
1629         return ret;
1630 }
1631
1632 static int
1633 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1634                             unsigned int *size, const char *name,
1635                             struct xt_table_info *newinfo, unsigned char *base)
1636 {
1637         struct ip6t_entry_target *t;
1638         struct xt_target *target;
1639         struct ip6t_entry *de;
1640         unsigned int origsize;
1641         int ret, h;
1642
1643         ret = 0;
1644         origsize = *size;
1645         de = (struct ip6t_entry *)*dstptr;
1646         memcpy(de, e, sizeof(struct ip6t_entry));
1647         memcpy(&de->counters, &e->counters, sizeof(e->counters));
1648
1649         *dstptr += sizeof(struct ip6t_entry);
1650         *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1651
1652         ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user,
1653                                         dstptr, size);
1654         if (ret)
1655                 return ret;
1656         de->target_offset = e->target_offset - (origsize - *size);
1657         t = compat_ip6t_get_target(e);
1658         target = t->u.kernel.target;
1659         xt_compat_target_from_user(t, dstptr, size);
1660
1661         de->next_offset = e->next_offset - (origsize - *size);
1662         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1663                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1664                         newinfo->hook_entry[h] -= origsize - *size;
1665                 if ((unsigned char *)de - base < newinfo->underflow[h])
1666                         newinfo->underflow[h] -= origsize - *size;
1667         }
1668         return ret;
1669 }
1670
1671 static int compat_check_entry(struct ip6t_entry *e, const char *name,
1672                                      unsigned int *i)
1673 {
1674         unsigned int j;
1675         int ret;
1676         struct xt_mtchk_param mtpar;
1677
1678         j = 0;
1679         mtpar.table     = name;
1680         mtpar.entryinfo = &e->ipv6;
1681         mtpar.hook_mask = e->comefrom;
1682         mtpar.family    = NFPROTO_IPV6;
1683         ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j);
1684         if (ret)
1685                 goto cleanup_matches;
1686
1687         ret = check_target(e, name);
1688         if (ret)
1689                 goto cleanup_matches;
1690
1691         (*i)++;
1692         return 0;
1693
1694  cleanup_matches:
1695         IP6T_MATCH_ITERATE(e, cleanup_match, &j);
1696         return ret;
1697 }
1698
1699 static int
1700 translate_compat_table(const char *name,
1701                        unsigned int valid_hooks,
1702                        struct xt_table_info **pinfo,
1703                        void **pentry0,
1704                        unsigned int total_size,
1705                        unsigned int number,
1706                        unsigned int *hook_entries,
1707                        unsigned int *underflows)
1708 {
1709         unsigned int i, j;
1710         struct xt_table_info *newinfo, *info;
1711         void *pos, *entry0, *entry1;
1712         unsigned int size;
1713         int ret;
1714
1715         info = *pinfo;
1716         entry0 = *pentry0;
1717         size = total_size;
1718         info->number = number;
1719
1720         /* Init all hooks to impossible value. */
1721         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1722                 info->hook_entry[i] = 0xFFFFFFFF;
1723                 info->underflow[i] = 0xFFFFFFFF;
1724         }
1725
1726         duprintf("translate_compat_table: size %u\n", info->size);
1727         j = 0;
1728         xt_compat_lock(AF_INET6);
1729         /* Walk through entries, checking offsets. */
1730         ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size,
1731                                         check_compat_entry_size_and_hooks,
1732                                         info, &size, entry0,
1733                                         entry0 + total_size,
1734                                         hook_entries, underflows, &j, name);
1735         if (ret != 0)
1736                 goto out_unlock;
1737
1738         ret = -EINVAL;
1739         if (j != number) {
1740                 duprintf("translate_compat_table: %u not %u entries\n",
1741                          j, number);
1742                 goto out_unlock;
1743         }
1744
1745         /* Check hooks all assigned */
1746         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1747                 /* Only hooks which are valid */
1748                 if (!(valid_hooks & (1 << i)))
1749                         continue;
1750                 if (info->hook_entry[i] == 0xFFFFFFFF) {
1751                         duprintf("Invalid hook entry %u %u\n",
1752                                  i, hook_entries[i]);
1753                         goto out_unlock;
1754                 }
1755                 if (info->underflow[i] == 0xFFFFFFFF) {
1756                         duprintf("Invalid underflow %u %u\n",
1757                                  i, underflows[i]);
1758                         goto out_unlock;
1759                 }
1760         }
1761
1762         ret = -ENOMEM;
1763         newinfo = xt_alloc_table_info(size);
1764         if (!newinfo)
1765                 goto out_unlock;
1766
1767         newinfo->number = number;
1768         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1769                 newinfo->hook_entry[i] = info->hook_entry[i];
1770                 newinfo->underflow[i] = info->underflow[i];
1771         }
1772         entry1 = newinfo->entries[raw_smp_processor_id()];
1773         pos = entry1;
1774         size = total_size;
1775         ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size,
1776                                         compat_copy_entry_from_user,
1777                                         &pos, &size, name, newinfo, entry1);
1778         xt_compat_flush_offsets(AF_INET6);
1779         xt_compat_unlock(AF_INET6);
1780         if (ret)
1781                 goto free_newinfo;
1782
1783         ret = -ELOOP;
1784         if (!mark_source_chains(newinfo, valid_hooks, entry1))
1785                 goto free_newinfo;
1786
1787         i = 0;
1788         ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1789                                  name, &i);
1790         if (ret) {
1791                 j -= i;
1792                 COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1793                                                    compat_release_entry, &j);
1794                 IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1795                 xt_free_table_info(newinfo);
1796                 return ret;
1797         }
1798
1799         /* And one copy for every other CPU */
1800         for_each_possible_cpu(i)
1801                 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1802                         memcpy(newinfo->entries[i], entry1, newinfo->size);
1803
1804         *pinfo = newinfo;
1805         *pentry0 = entry1;
1806         xt_free_table_info(info);
1807         return 0;
1808
1809 free_newinfo:
1810         xt_free_table_info(newinfo);
1811 out:
1812         COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1813         return ret;
1814 out_unlock:
1815         xt_compat_flush_offsets(AF_INET6);
1816         xt_compat_unlock(AF_INET6);
1817         goto out;
1818 }
1819
1820 static int
1821 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1822 {
1823         int ret;
1824         struct compat_ip6t_replace tmp;
1825         struct xt_table_info *newinfo;
1826         void *loc_cpu_entry;
1827
1828         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1829                 return -EFAULT;
1830
1831         /* overflow check */
1832         if (tmp.size >= INT_MAX / num_possible_cpus())
1833                 return -ENOMEM;
1834         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1835                 return -ENOMEM;
1836
1837         newinfo = xt_alloc_table_info(tmp.size);
1838         if (!newinfo)
1839                 return -ENOMEM;
1840
1841         /* choose the copy that is on our node/cpu */
1842         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1843         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1844                            tmp.size) != 0) {
1845                 ret = -EFAULT;
1846                 goto free_newinfo;
1847         }
1848
1849         ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1850                                      &newinfo, &loc_cpu_entry, tmp.size,
1851                                      tmp.num_entries, tmp.hook_entry,
1852                                      tmp.underflow);
1853         if (ret != 0)
1854                 goto free_newinfo;
1855
1856         duprintf("compat_do_replace: Translated table\n");
1857
1858         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1859                            tmp.num_counters, compat_ptr(tmp.counters));
1860         if (ret)
1861                 goto free_newinfo_untrans;
1862         return 0;
1863
1864  free_newinfo_untrans:
1865         IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1866  free_newinfo:
1867         xt_free_table_info(newinfo);
1868         return ret;
1869 }
1870
1871 static int
1872 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1873                        unsigned int len)
1874 {
1875         int ret;
1876
1877         if (!capable(CAP_NET_ADMIN))
1878                 return -EPERM;
1879
1880         switch (cmd) {
1881         case IP6T_SO_SET_REPLACE:
1882                 ret = compat_do_replace(sock_net(sk), user, len);
1883                 break;
1884
1885         case IP6T_SO_SET_ADD_COUNTERS:
1886                 ret = do_add_counters(sock_net(sk), user, len, 1);
1887                 break;
1888
1889         default:
1890                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1891                 ret = -EINVAL;
1892         }
1893
1894         return ret;
1895 }
1896
1897 struct compat_ip6t_get_entries {
1898         char name[IP6T_TABLE_MAXNAMELEN];
1899         compat_uint_t size;
1900         struct compat_ip6t_entry entrytable[0];
1901 };
1902
1903 static int
1904 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1905                             void __user *userptr)
1906 {
1907         struct xt_counters *counters;
1908         const struct xt_table_info *private = table->private;
1909         void __user *pos;
1910         unsigned int size;
1911         int ret = 0;
1912         const void *loc_cpu_entry;
1913         unsigned int i = 0;
1914
1915         counters = alloc_counters(table);
1916         if (IS_ERR(counters))
1917                 return PTR_ERR(counters);
1918
1919         /* choose the copy that is on our node/cpu, ...
1920          * This choice is lazy (because current thread is
1921          * allowed to migrate to another cpu)
1922          */
1923         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1924         pos = userptr;
1925         size = total_size;
1926         ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size,
1927                                  compat_copy_entry_to_user,
1928                                  &pos, &size, counters, &i);
1929
1930         vfree(counters);
1931         return ret;
1932 }
1933
1934 static int
1935 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1936                    int *len)
1937 {
1938         int ret;
1939         struct compat_ip6t_get_entries get;
1940         struct xt_table *t;
1941
1942         if (*len < sizeof(get)) {
1943                 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1944                 return -EINVAL;
1945         }
1946
1947         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1948                 return -EFAULT;
1949
1950         if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1951                 duprintf("compat_get_entries: %u != %zu\n",
1952                          *len, sizeof(get) + get.size);
1953                 return -EINVAL;
1954         }
1955
1956         xt_compat_lock(AF_INET6);
1957         t = xt_find_table_lock(net, AF_INET6, get.name);
1958         if (t && !IS_ERR(t)) {
1959                 const struct xt_table_info *private = t->private;
1960                 struct xt_table_info info;
1961                 duprintf("t->private->number = %u\n", private->number);
1962                 ret = compat_table_info(private, &info);
1963                 if (!ret && get.size == info.size) {
1964                         ret = compat_copy_entries_to_user(private->size,
1965                                                           t, uptr->entrytable);
1966                 } else if (!ret) {
1967                         duprintf("compat_get_entries: I've got %u not %u!\n",
1968                                  private->size, get.size);
1969                         ret = -EAGAIN;
1970                 }
1971                 xt_compat_flush_offsets(AF_INET6);
1972                 module_put(t->me);
1973                 xt_table_unlock(t);
1974         } else
1975                 ret = t ? PTR_ERR(t) : -ENOENT;
1976
1977         xt_compat_unlock(AF_INET6);
1978         return ret;
1979 }
1980
1981 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1982
1983 static int
1984 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1985 {
1986         int ret;
1987
1988         if (!capable(CAP_NET_ADMIN))
1989                 return -EPERM;
1990
1991         switch (cmd) {
1992         case IP6T_SO_GET_INFO:
1993                 ret = get_info(sock_net(sk), user, len, 1);
1994                 break;
1995         case IP6T_SO_GET_ENTRIES:
1996                 ret = compat_get_entries(sock_net(sk), user, len);
1997                 break;
1998         default:
1999                 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2000         }
2001         return ret;
2002 }
2003 #endif
2004
2005 static int
2006 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2007 {
2008         int ret;
2009
2010         if (!capable(CAP_NET_ADMIN))
2011                 return -EPERM;
2012
2013         switch (cmd) {
2014         case IP6T_SO_SET_REPLACE:
2015                 ret = do_replace(sock_net(sk), user, len);
2016                 break;
2017
2018         case IP6T_SO_SET_ADD_COUNTERS:
2019                 ret = do_add_counters(sock_net(sk), user, len, 0);
2020                 break;
2021
2022         default:
2023                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
2024                 ret = -EINVAL;
2025         }
2026
2027         return ret;
2028 }
2029
2030 static int
2031 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2032 {
2033         int ret;
2034
2035         if (!capable(CAP_NET_ADMIN))
2036                 return -EPERM;
2037
2038         switch (cmd) {
2039         case IP6T_SO_GET_INFO:
2040                 ret = get_info(sock_net(sk), user, len, 0);
2041                 break;
2042
2043         case IP6T_SO_GET_ENTRIES:
2044                 ret = get_entries(sock_net(sk), user, len);
2045                 break;
2046
2047         case IP6T_SO_GET_REVISION_MATCH:
2048         case IP6T_SO_GET_REVISION_TARGET: {
2049                 struct ip6t_get_revision rev;
2050                 int target;
2051
2052                 if (*len != sizeof(rev)) {
2053                         ret = -EINVAL;
2054                         break;
2055                 }
2056                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2057                         ret = -EFAULT;
2058                         break;
2059                 }
2060
2061                 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2062                         target = 1;
2063                 else
2064                         target = 0;
2065
2066                 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2067                                                          rev.revision,
2068                                                          target, &ret),
2069                                         "ip6t_%s", rev.name);
2070                 break;
2071         }
2072
2073         default:
2074                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2075                 ret = -EINVAL;
2076         }
2077
2078         return ret;
2079 }
2080
2081 struct xt_table *ip6t_register_table(struct net *net, struct xt_table *table,
2082                                      const struct ip6t_replace *repl)
2083 {
2084         int ret;
2085         struct xt_table_info *newinfo;
2086         struct xt_table_info bootstrap
2087                 = { 0, 0, 0, { 0 }, { 0 }, { } };
2088         void *loc_cpu_entry;
2089         struct xt_table *new_table;
2090
2091         newinfo = xt_alloc_table_info(repl->size);
2092         if (!newinfo) {
2093                 ret = -ENOMEM;
2094                 goto out;
2095         }
2096
2097         /* choose the copy on our node/cpu, but dont care about preemption */
2098         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2099         memcpy(loc_cpu_entry, repl->entries, repl->size);
2100
2101         ret = translate_table(table->name, table->valid_hooks,
2102                               newinfo, loc_cpu_entry, repl->size,
2103                               repl->num_entries,
2104                               repl->hook_entry,
2105                               repl->underflow);
2106         if (ret != 0)
2107                 goto out_free;
2108
2109         new_table = xt_register_table(net, table, &bootstrap, newinfo);
2110         if (IS_ERR(new_table)) {
2111                 ret = PTR_ERR(new_table);
2112                 goto out_free;
2113         }
2114         return new_table;
2115
2116 out_free:
2117         xt_free_table_info(newinfo);
2118 out:
2119         return ERR_PTR(ret);
2120 }
2121
2122 void ip6t_unregister_table(struct xt_table *table)
2123 {
2124         struct xt_table_info *private;
2125         void *loc_cpu_entry;
2126         struct module *table_owner = table->me;
2127
2128         private = xt_unregister_table(table);
2129
2130         /* Decrease module usage counts and free resources */
2131         loc_cpu_entry = private->entries[raw_smp_processor_id()];
2132         IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2133         if (private->number > private->initial_entries)
2134                 module_put(table_owner);
2135         xt_free_table_info(private);
2136 }
2137
2138 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2139 static inline bool
2140 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2141                      u_int8_t type, u_int8_t code,
2142                      bool invert)
2143 {
2144         return (type == test_type && code >= min_code && code <= max_code)
2145                 ^ invert;
2146 }
2147
2148 static bool
2149 icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
2150 {
2151         const struct icmp6hdr *ic;
2152         struct icmp6hdr _icmph;
2153         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2154
2155         /* Must not be a fragment. */
2156         if (par->fragoff != 0)
2157                 return false;
2158
2159         ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2160         if (ic == NULL) {
2161                 /* We've been asked to examine this packet, and we
2162                  * can't.  Hence, no choice but to drop.
2163                  */
2164                 duprintf("Dropping evil ICMP tinygram.\n");
2165                 *par->hotdrop = true;
2166                 return false;
2167         }
2168
2169         return icmp6_type_code_match(icmpinfo->type,
2170                                      icmpinfo->code[0],
2171                                      icmpinfo->code[1],
2172                                      ic->icmp6_type, ic->icmp6_code,
2173                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
2174 }
2175
2176 /* Called when user tries to insert an entry of this type. */
2177 static bool icmp6_checkentry(const struct xt_mtchk_param *par)
2178 {
2179         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2180
2181         /* Must specify no unknown invflags */
2182         return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
2183 }
2184
2185 /* The built-in targets: standard (NULL) and error. */
2186 static struct xt_target ip6t_standard_target __read_mostly = {
2187         .name           = IP6T_STANDARD_TARGET,
2188         .targetsize     = sizeof(int),
2189         .family         = NFPROTO_IPV6,
2190 #ifdef CONFIG_COMPAT
2191         .compatsize     = sizeof(compat_int_t),
2192         .compat_from_user = compat_standard_from_user,
2193         .compat_to_user = compat_standard_to_user,
2194 #endif
2195 };
2196
2197 static struct xt_target ip6t_error_target __read_mostly = {
2198         .name           = IP6T_ERROR_TARGET,
2199         .target         = ip6t_error,
2200         .targetsize     = IP6T_FUNCTION_MAXNAMELEN,
2201         .family         = NFPROTO_IPV6,
2202 };
2203
2204 static struct nf_sockopt_ops ip6t_sockopts = {
2205         .pf             = PF_INET6,
2206         .set_optmin     = IP6T_BASE_CTL,
2207         .set_optmax     = IP6T_SO_SET_MAX+1,
2208         .set            = do_ip6t_set_ctl,
2209 #ifdef CONFIG_COMPAT
2210         .compat_set     = compat_do_ip6t_set_ctl,
2211 #endif
2212         .get_optmin     = IP6T_BASE_CTL,
2213         .get_optmax     = IP6T_SO_GET_MAX+1,
2214         .get            = do_ip6t_get_ctl,
2215 #ifdef CONFIG_COMPAT
2216         .compat_get     = compat_do_ip6t_get_ctl,
2217 #endif
2218         .owner          = THIS_MODULE,
2219 };
2220
2221 static struct xt_match icmp6_matchstruct __read_mostly = {
2222         .name           = "icmp6",
2223         .match          = icmp6_match,
2224         .matchsize      = sizeof(struct ip6t_icmp),
2225         .checkentry     = icmp6_checkentry,
2226         .proto          = IPPROTO_ICMPV6,
2227         .family         = NFPROTO_IPV6,
2228 };
2229
2230 static int __net_init ip6_tables_net_init(struct net *net)
2231 {
2232         return xt_proto_init(net, NFPROTO_IPV6);
2233 }
2234
2235 static void __net_exit ip6_tables_net_exit(struct net *net)
2236 {
2237         xt_proto_fini(net, NFPROTO_IPV6);
2238 }
2239
2240 static struct pernet_operations ip6_tables_net_ops = {
2241         .init = ip6_tables_net_init,
2242         .exit = ip6_tables_net_exit,
2243 };
2244
2245 static int __init ip6_tables_init(void)
2246 {
2247         int ret;
2248
2249         ret = register_pernet_subsys(&ip6_tables_net_ops);
2250         if (ret < 0)
2251                 goto err1;
2252
2253         /* Noone else will be downing sem now, so we won't sleep */
2254         ret = xt_register_target(&ip6t_standard_target);
2255         if (ret < 0)
2256                 goto err2;
2257         ret = xt_register_target(&ip6t_error_target);
2258         if (ret < 0)
2259                 goto err3;
2260         ret = xt_register_match(&icmp6_matchstruct);
2261         if (ret < 0)
2262                 goto err4;
2263
2264         /* Register setsockopt */
2265         ret = nf_register_sockopt(&ip6t_sockopts);
2266         if (ret < 0)
2267                 goto err5;
2268
2269         printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
2270         return 0;
2271
2272 err5:
2273         xt_unregister_match(&icmp6_matchstruct);
2274 err4:
2275         xt_unregister_target(&ip6t_error_target);
2276 err3:
2277         xt_unregister_target(&ip6t_standard_target);
2278 err2:
2279         unregister_pernet_subsys(&ip6_tables_net_ops);
2280 err1:
2281         return ret;
2282 }
2283
2284 static void __exit ip6_tables_fini(void)
2285 {
2286         nf_unregister_sockopt(&ip6t_sockopts);
2287
2288         xt_unregister_match(&icmp6_matchstruct);
2289         xt_unregister_target(&ip6t_error_target);
2290         xt_unregister_target(&ip6t_standard_target);
2291
2292         unregister_pernet_subsys(&ip6_tables_net_ops);
2293 }
2294
2295 /*
2296  * find the offset to specified header or the protocol number of last header
2297  * if target < 0. "last header" is transport protocol header, ESP, or
2298  * "No next header".
2299  *
2300  * If target header is found, its offset is set in *offset and return protocol
2301  * number. Otherwise, return -1.
2302  *
2303  * If the first fragment doesn't contain the final protocol header or
2304  * NEXTHDR_NONE it is considered invalid.
2305  *
2306  * Note that non-1st fragment is special case that "the protocol number
2307  * of last header" is "next header" field in Fragment header. In this case,
2308  * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2309  * isn't NULL.
2310  *
2311  */
2312 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2313                   int target, unsigned short *fragoff)
2314 {
2315         unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2316         u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2317         unsigned int len = skb->len - start;
2318
2319         if (fragoff)
2320                 *fragoff = 0;
2321
2322         while (nexthdr != target) {
2323                 struct ipv6_opt_hdr _hdr, *hp;
2324                 unsigned int hdrlen;
2325
2326                 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2327                         if (target < 0)
2328                                 break;
2329                         return -ENOENT;
2330                 }
2331
2332                 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2333                 if (hp == NULL)
2334                         return -EBADMSG;
2335                 if (nexthdr == NEXTHDR_FRAGMENT) {
2336                         unsigned short _frag_off;
2337                         __be16 *fp;
2338                         fp = skb_header_pointer(skb,
2339                                                 start+offsetof(struct frag_hdr,
2340                                                                frag_off),
2341                                                 sizeof(_frag_off),
2342                                                 &_frag_off);
2343                         if (fp == NULL)
2344                                 return -EBADMSG;
2345
2346                         _frag_off = ntohs(*fp) & ~0x7;
2347                         if (_frag_off) {
2348                                 if (target < 0 &&
2349                                     ((!ipv6_ext_hdr(hp->nexthdr)) ||
2350                                      hp->nexthdr == NEXTHDR_NONE)) {
2351                                         if (fragoff)
2352                                                 *fragoff = _frag_off;
2353                                         return hp->nexthdr;
2354                                 }
2355                                 return -ENOENT;
2356                         }
2357                         hdrlen = 8;
2358                 } else if (nexthdr == NEXTHDR_AUTH)
2359                         hdrlen = (hp->hdrlen + 2) << 2;
2360                 else
2361                         hdrlen = ipv6_optlen(hp);
2362
2363                 nexthdr = hp->nexthdr;
2364                 len -= hdrlen;
2365                 start += hdrlen;
2366         }
2367
2368         *offset = start;
2369         return nexthdr;
2370 }
2371
2372 EXPORT_SYMBOL(ip6t_register_table);
2373 EXPORT_SYMBOL(ip6t_unregister_table);
2374 EXPORT_SYMBOL(ip6t_do_table);
2375 EXPORT_SYMBOL(ip6t_ext_hdr);
2376 EXPORT_SYMBOL(ipv6_find_hdr);
2377
2378 module_init(ip6_tables_init);
2379 module_exit(ip6_tables_fini);