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