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