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