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