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