[NETFILTER]: ip6_tables: use vmalloc_node()
[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 <asm/uaccess.h>
23 #include <linux/mutex.h>
24 #include <linux/proc_fs.h>
25 #include <linux/cpumask.h>
26
27 #include <linux/netfilter_ipv6/ip6_tables.h>
28 #include <linux/netfilter/x_tables.h>
29
30 MODULE_LICENSE("GPL");
31 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
32 MODULE_DESCRIPTION("IPv6 packet filter");
33
34 /*#define DEBUG_IP_FIREWALL*/
35 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
36 /*#define DEBUG_IP_FIREWALL_USER*/
37
38 #ifdef DEBUG_IP_FIREWALL
39 #define dprintf(format, args...)  printk(format , ## args)
40 #else
41 #define dprintf(format, args...)
42 #endif
43
44 #ifdef DEBUG_IP_FIREWALL_USER
45 #define duprintf(format, args...) printk(format , ## args)
46 #else
47 #define duprintf(format, args...)
48 #endif
49
50 #ifdef CONFIG_NETFILTER_DEBUG
51 #define IP_NF_ASSERT(x)                                         \
52 do {                                                            \
53         if (!(x))                                               \
54                 printk("IP_NF_ASSERT: %s:%s:%u\n",              \
55                        __FUNCTION__, __FILE__, __LINE__);       \
56 } while(0)
57 #else
58 #define IP_NF_ASSERT(x)
59 #endif
60
61 #if 0
62 /* All the better to debug you with... */
63 #define static
64 #define inline
65 #endif
66
67 /*
68    We keep a set of rules for each CPU, so we can avoid write-locking
69    them in the softirq when updating the counters and therefore
70    only need to read-lock in the softirq; doing a write_lock_bh() in user
71    context stops packets coming through and allows user context to read
72    the counters or update the rules.
73
74    Hence the start of any table is given by get_table() below.  */
75
76 /* Check for an extension */
77 int
78 ip6t_ext_hdr(u8 nexthdr)
79 {
80         return ( (nexthdr == IPPROTO_HOPOPTS)   ||
81                  (nexthdr == IPPROTO_ROUTING)   ||
82                  (nexthdr == IPPROTO_FRAGMENT)  ||
83                  (nexthdr == IPPROTO_ESP)       ||
84                  (nexthdr == IPPROTO_AH)        ||
85                  (nexthdr == IPPROTO_NONE)      ||
86                  (nexthdr == IPPROTO_DSTOPTS) );
87 }
88
89 /* Returns whether matches rule or not. */
90 static inline bool
91 ip6_packet_match(const struct sk_buff *skb,
92                  const char *indev,
93                  const char *outdev,
94                  const struct ip6t_ip6 *ip6info,
95                  unsigned int *protoff,
96                  int *fragoff, bool *hotdrop)
97 {
98         size_t i;
99         unsigned long ret;
100         const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
101
102 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
103
104         if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
105                                        &ip6info->src), IP6T_INV_SRCIP)
106             || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
107                                           &ip6info->dst), IP6T_INV_DSTIP)) {
108                 dprintf("Source or dest mismatch.\n");
109 /*
110                 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
111                         ipinfo->smsk.s_addr, ipinfo->src.s_addr,
112                         ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
113                 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
114                         ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
115                         ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
116                 return false;
117         }
118
119         /* Look for ifname matches; this should unroll nicely. */
120         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
121                 ret |= (((const unsigned long *)indev)[i]
122                         ^ ((const unsigned long *)ip6info->iniface)[i])
123                         & ((const unsigned long *)ip6info->iniface_mask)[i];
124         }
125
126         if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
127                 dprintf("VIA in mismatch (%s vs %s).%s\n",
128                         indev, ip6info->iniface,
129                         ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
130                 return false;
131         }
132
133         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
134                 ret |= (((const unsigned long *)outdev)[i]
135                         ^ ((const unsigned long *)ip6info->outiface)[i])
136                         & ((const unsigned long *)ip6info->outiface_mask)[i];
137         }
138
139         if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
140                 dprintf("VIA out mismatch (%s vs %s).%s\n",
141                         outdev, ip6info->outiface,
142                         ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
143                 return false;
144         }
145
146 /* ... might want to do something with class and flowlabel here ... */
147
148         /* look for the desired protocol header */
149         if((ip6info->flags & IP6T_F_PROTO)) {
150                 int protohdr;
151                 unsigned short _frag_off;
152
153                 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
154                 if (protohdr < 0) {
155                         if (_frag_off == 0)
156                                 *hotdrop = true;
157                         return false;
158                 }
159                 *fragoff = _frag_off;
160
161                 dprintf("Packet protocol %hi ?= %s%hi.\n",
162                                 protohdr,
163                                 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
164                                 ip6info->proto);
165
166                 if (ip6info->proto == protohdr) {
167                         if(ip6info->invflags & IP6T_INV_PROTO) {
168                                 return false;
169                         }
170                         return true;
171                 }
172
173                 /* We need match for the '-p all', too! */
174                 if ((ip6info->proto != 0) &&
175                         !(ip6info->invflags & IP6T_INV_PROTO))
176                         return false;
177         }
178         return true;
179 }
180
181 /* should be ip6 safe */
182 static inline bool
183 ip6_checkentry(const struct ip6t_ip6 *ipv6)
184 {
185         if (ipv6->flags & ~IP6T_F_MASK) {
186                 duprintf("Unknown flag bits set: %08X\n",
187                          ipv6->flags & ~IP6T_F_MASK);
188                 return false;
189         }
190         if (ipv6->invflags & ~IP6T_INV_MASK) {
191                 duprintf("Unknown invflag bits set: %08X\n",
192                          ipv6->invflags & ~IP6T_INV_MASK);
193                 return false;
194         }
195         return true;
196 }
197
198 static unsigned int
199 ip6t_error(struct sk_buff *skb,
200           const struct net_device *in,
201           const struct net_device *out,
202           unsigned int hooknum,
203           const struct xt_target *target,
204           const void *targinfo)
205 {
206         if (net_ratelimit())
207                 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
208
209         return NF_DROP;
210 }
211
212 static inline
213 bool do_match(struct ip6t_entry_match *m,
214               const struct sk_buff *skb,
215               const struct net_device *in,
216               const struct net_device *out,
217               int offset,
218               unsigned int protoff,
219               bool *hotdrop)
220 {
221         /* Stop iteration if it doesn't match */
222         if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
223                                       offset, protoff, hotdrop))
224                 return true;
225         else
226                 return false;
227 }
228
229 static inline struct ip6t_entry *
230 get_entry(void *base, unsigned int offset)
231 {
232         return (struct ip6t_entry *)(base + offset);
233 }
234
235 /* All zeroes == unconditional rule. */
236 static inline int
237 unconditional(const struct ip6t_ip6 *ipv6)
238 {
239         unsigned int i;
240
241         for (i = 0; i < sizeof(*ipv6); i++)
242                 if (((char *)ipv6)[i])
243                         break;
244
245         return (i == sizeof(*ipv6));
246 }
247
248 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
249     defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
250 /* This cries for unification! */
251 static const char *hooknames[] = {
252         [NF_INET_PRE_ROUTING]           = "PREROUTING",
253         [NF_INET_LOCAL_IN]              = "INPUT",
254         [NF_INET_FORWARD]               = "FORWARD",
255         [NF_INET_LOCAL_OUT]             = "OUTPUT",
256         [NF_INET_POST_ROUTING]          = "POSTROUTING",
257 };
258
259 enum nf_ip_trace_comments {
260         NF_IP6_TRACE_COMMENT_RULE,
261         NF_IP6_TRACE_COMMENT_RETURN,
262         NF_IP6_TRACE_COMMENT_POLICY,
263 };
264
265 static const char *comments[] = {
266         [NF_IP6_TRACE_COMMENT_RULE]     = "rule",
267         [NF_IP6_TRACE_COMMENT_RETURN]   = "return",
268         [NF_IP6_TRACE_COMMENT_POLICY]   = "policy",
269 };
270
271 static struct nf_loginfo trace_loginfo = {
272         .type = NF_LOG_TYPE_LOG,
273         .u = {
274                 .log = {
275                         .level = 4,
276                         .logflags = NF_LOG_MASK,
277                 },
278         },
279 };
280
281 static inline int
282 get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
283                       char *hookname, char **chainname,
284                       char **comment, unsigned int *rulenum)
285 {
286         struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
287
288         if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
289                 /* Head of user chain: ERROR target with chainname */
290                 *chainname = t->target.data;
291                 (*rulenum) = 0;
292         } else if (s == e) {
293                 (*rulenum)++;
294
295                 if (s->target_offset == sizeof(struct ip6t_entry)
296                    && strcmp(t->target.u.kernel.target->name,
297                              IP6T_STANDARD_TARGET) == 0
298                    && t->verdict < 0
299                    && unconditional(&s->ipv6)) {
300                         /* Tail of chains: STANDARD target (return/policy) */
301                         *comment = *chainname == hookname
302                                 ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY]
303                                 : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN];
304                 }
305                 return 1;
306         } else
307                 (*rulenum)++;
308
309         return 0;
310 }
311
312 static void trace_packet(struct sk_buff *skb,
313                          unsigned int hook,
314                          const struct net_device *in,
315                          const struct net_device *out,
316                          char *tablename,
317                          struct xt_table_info *private,
318                          struct ip6t_entry *e)
319 {
320         void *table_base;
321         struct ip6t_entry *root;
322         char *hookname, *chainname, *comment;
323         unsigned int rulenum = 0;
324
325         table_base = (void *)private->entries[smp_processor_id()];
326         root = get_entry(table_base, private->hook_entry[hook]);
327
328         hookname = chainname = (char *)hooknames[hook];
329         comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE];
330
331         IP6T_ENTRY_ITERATE(root,
332                            private->size - private->hook_entry[hook],
333                            get_chainname_rulenum,
334                            e, hookname, &chainname, &comment, &rulenum);
335
336         nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
337                       "TRACE: %s:%s:%s:%u ",
338                       tablename, chainname, comment, rulenum);
339 }
340 #endif
341
342 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
343 unsigned int
344 ip6t_do_table(struct sk_buff *skb,
345               unsigned int hook,
346               const struct net_device *in,
347               const struct net_device *out,
348               struct xt_table *table)
349 {
350         static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
351         int offset = 0;
352         unsigned int protoff = 0;
353         bool hotdrop = false;
354         /* Initializing verdict to NF_DROP keeps gcc happy. */
355         unsigned int verdict = NF_DROP;
356         const char *indev, *outdev;
357         void *table_base;
358         struct ip6t_entry *e, *back;
359         struct xt_table_info *private;
360
361         /* Initialization */
362         indev = in ? in->name : nulldevname;
363         outdev = out ? out->name : nulldevname;
364         /* We handle fragments by dealing with the first fragment as
365          * if it was a normal packet.  All other fragments are treated
366          * normally, except that they will NEVER match rules that ask
367          * things we don't know, ie. tcp syn flag or ports).  If the
368          * rule is also a fragment-specific rule, non-fragments won't
369          * match it. */
370
371         read_lock_bh(&table->lock);
372         private = table->private;
373         IP_NF_ASSERT(table->valid_hooks & (1 << hook));
374         table_base = (void *)private->entries[smp_processor_id()];
375         e = get_entry(table_base, private->hook_entry[hook]);
376
377         /* For return from builtin chain */
378         back = get_entry(table_base, private->underflow[hook]);
379
380         do {
381                 IP_NF_ASSERT(e);
382                 IP_NF_ASSERT(back);
383                 if (ip6_packet_match(skb, indev, outdev, &e->ipv6,
384                         &protoff, &offset, &hotdrop)) {
385                         struct ip6t_entry_target *t;
386
387                         if (IP6T_MATCH_ITERATE(e, do_match,
388                                                skb, in, out,
389                                                offset, protoff, &hotdrop) != 0)
390                                 goto no_match;
391
392                         ADD_COUNTER(e->counters,
393                                     ntohs(ipv6_hdr(skb)->payload_len) +
394                                     sizeof(struct ipv6hdr), 1);
395
396                         t = ip6t_get_target(e);
397                         IP_NF_ASSERT(t->u.kernel.target);
398
399 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
400     defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
401                         /* The packet is traced: log it */
402                         if (unlikely(skb->nf_trace))
403                                 trace_packet(skb, hook, in, out,
404                                              table->name, private, e);
405 #endif
406                         /* Standard target? */
407                         if (!t->u.kernel.target->target) {
408                                 int v;
409
410                                 v = ((struct ip6t_standard_target *)t)->verdict;
411                                 if (v < 0) {
412                                         /* Pop from stack? */
413                                         if (v != IP6T_RETURN) {
414                                                 verdict = (unsigned)(-v) - 1;
415                                                 break;
416                                         }
417                                         e = back;
418                                         back = get_entry(table_base,
419                                                          back->comefrom);
420                                         continue;
421                                 }
422                                 if (table_base + v != (void *)e + e->next_offset
423                                     && !(e->ipv6.flags & IP6T_F_GOTO)) {
424                                         /* Save old back ptr in next entry */
425                                         struct ip6t_entry *next
426                                                 = (void *)e + e->next_offset;
427                                         next->comefrom
428                                                 = (void *)back - table_base;
429                                         /* set back pointer to next entry */
430                                         back = next;
431                                 }
432
433                                 e = get_entry(table_base, v);
434                         } else {
435                                 /* Targets which reenter must return
436                                    abs. verdicts */
437 #ifdef CONFIG_NETFILTER_DEBUG
438                                 ((struct ip6t_entry *)table_base)->comefrom
439                                         = 0xeeeeeeec;
440 #endif
441                                 verdict = t->u.kernel.target->target(skb,
442                                                                      in, out,
443                                                                      hook,
444                                                                      t->u.kernel.target,
445                                                                      t->data);
446
447 #ifdef CONFIG_NETFILTER_DEBUG
448                                 if (((struct ip6t_entry *)table_base)->comefrom
449                                     != 0xeeeeeeec
450                                     && verdict == IP6T_CONTINUE) {
451                                         printk("Target %s reentered!\n",
452                                                t->u.kernel.target->name);
453                                         verdict = NF_DROP;
454                                 }
455                                 ((struct ip6t_entry *)table_base)->comefrom
456                                         = 0x57acc001;
457 #endif
458                                 if (verdict == IP6T_CONTINUE)
459                                         e = (void *)e + e->next_offset;
460                                 else
461                                         /* Verdict */
462                                         break;
463                         }
464                 } else {
465
466                 no_match:
467                         e = (void *)e + e->next_offset;
468                 }
469         } while (!hotdrop);
470
471 #ifdef CONFIG_NETFILTER_DEBUG
472         ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
473 #endif
474         read_unlock_bh(&table->lock);
475
476 #ifdef DEBUG_ALLOW_ALL
477         return NF_ACCEPT;
478 #else
479         if (hotdrop)
480                 return NF_DROP;
481         else return verdict;
482 #endif
483 }
484
485 /* Figures out from what hook each rule can be called: returns 0 if
486    there are loops.  Puts hook bitmask in comefrom. */
487 static int
488 mark_source_chains(struct xt_table_info *newinfo,
489                    unsigned int valid_hooks, void *entry0)
490 {
491         unsigned int hook;
492
493         /* No recursion; use packet counter to save back ptrs (reset
494            to 0 as we leave), and comefrom to save source hook bitmask */
495         for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
496                 unsigned int pos = newinfo->hook_entry[hook];
497                 struct ip6t_entry *e
498                         = (struct ip6t_entry *)(entry0 + pos);
499                 int visited = e->comefrom & (1 << hook);
500
501                 if (!(valid_hooks & (1 << hook)))
502                         continue;
503
504                 /* Set initial back pointer. */
505                 e->counters.pcnt = pos;
506
507                 for (;;) {
508                         struct ip6t_standard_target *t
509                                 = (void *)ip6t_get_target(e);
510
511                         if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
512                                 printk("iptables: loop hook %u pos %u %08X.\n",
513                                        hook, pos, e->comefrom);
514                                 return 0;
515                         }
516                         e->comefrom
517                                 |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
518
519                         /* Unconditional return/END. */
520                         if ((e->target_offset == sizeof(struct ip6t_entry)
521                             && (strcmp(t->target.u.user.name,
522                                        IP6T_STANDARD_TARGET) == 0)
523                             && t->verdict < 0
524                             && unconditional(&e->ipv6)) || visited) {
525                                 unsigned int oldpos, size;
526
527                                 if (t->verdict < -NF_MAX_VERDICT - 1) {
528                                         duprintf("mark_source_chains: bad "
529                                                 "negative verdict (%i)\n",
530                                                                 t->verdict);
531                                         return 0;
532                                 }
533
534                                 /* Return: backtrack through the last
535                                    big jump. */
536                                 do {
537                                         e->comefrom ^= (1<<NF_INET_NUMHOOKS);
538 #ifdef DEBUG_IP_FIREWALL_USER
539                                         if (e->comefrom
540                                             & (1 << NF_INET_NUMHOOKS)) {
541                                                 duprintf("Back unset "
542                                                          "on hook %u "
543                                                          "rule %u\n",
544                                                          hook, pos);
545                                         }
546 #endif
547                                         oldpos = pos;
548                                         pos = e->counters.pcnt;
549                                         e->counters.pcnt = 0;
550
551                                         /* We're at the start. */
552                                         if (pos == oldpos)
553                                                 goto next;
554
555                                         e = (struct ip6t_entry *)
556                                                 (entry0 + pos);
557                                 } while (oldpos == pos + e->next_offset);
558
559                                 /* Move along one */
560                                 size = e->next_offset;
561                                 e = (struct ip6t_entry *)
562                                         (entry0 + pos + size);
563                                 e->counters.pcnt = pos;
564                                 pos += size;
565                         } else {
566                                 int newpos = t->verdict;
567
568                                 if (strcmp(t->target.u.user.name,
569                                            IP6T_STANDARD_TARGET) == 0
570                                     && newpos >= 0) {
571                                         if (newpos > newinfo->size -
572                                                 sizeof(struct ip6t_entry)) {
573                                                 duprintf("mark_source_chains: "
574                                                         "bad verdict (%i)\n",
575                                                                 newpos);
576                                                 return 0;
577                                         }
578                                         /* This a jump; chase it. */
579                                         duprintf("Jump rule %u -> %u\n",
580                                                  pos, newpos);
581                                 } else {
582                                         /* ... this is a fallthru */
583                                         newpos = pos + e->next_offset;
584                                 }
585                                 e = (struct ip6t_entry *)
586                                         (entry0 + newpos);
587                                 e->counters.pcnt = pos;
588                                 pos = newpos;
589                         }
590                 }
591                 next:
592                 duprintf("Finished chain %u\n", hook);
593         }
594         return 1;
595 }
596
597 static inline int
598 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
599 {
600         if (i && (*i)-- == 0)
601                 return 1;
602
603         if (m->u.kernel.match->destroy)
604                 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
605         module_put(m->u.kernel.match->me);
606         return 0;
607 }
608
609 static inline int
610 check_entry(struct ip6t_entry *e, const char *name)
611 {
612         struct ip6t_entry_target *t;
613
614         if (!ip6_checkentry(&e->ipv6)) {
615                 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
616                 return -EINVAL;
617         }
618
619         if (e->target_offset + sizeof(struct ip6t_entry_target) >
620             e->next_offset)
621                 return -EINVAL;
622
623         t = ip6t_get_target(e);
624         if (e->target_offset + t->u.target_size > e->next_offset)
625                 return -EINVAL;
626
627         return 0;
628 }
629
630 static inline int check_match(struct ip6t_entry_match *m, const char *name,
631                               const struct ip6t_ip6 *ipv6,
632                               unsigned int hookmask, unsigned int *i)
633 {
634         struct xt_match *match;
635         int ret;
636
637         match = m->u.kernel.match;
638         ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
639                              name, hookmask, ipv6->proto,
640                              ipv6->invflags & IP6T_INV_PROTO);
641         if (!ret && m->u.kernel.match->checkentry
642             && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
643                                               hookmask)) {
644                 duprintf("ip_tables: check failed for `%s'.\n",
645                          m->u.kernel.match->name);
646                 ret = -EINVAL;
647         }
648         if (!ret)
649                 (*i)++;
650         return ret;
651 }
652
653 static inline int
654 find_check_match(struct ip6t_entry_match *m,
655                  const char *name,
656                  const struct ip6t_ip6 *ipv6,
657                  unsigned int hookmask,
658                  unsigned int *i)
659 {
660         struct xt_match *match;
661         int ret;
662
663         match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
664                                         m->u.user.revision),
665                                         "ip6t_%s", m->u.user.name);
666         if (IS_ERR(match) || !match) {
667                 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
668                 return match ? PTR_ERR(match) : -ENOENT;
669         }
670         m->u.kernel.match = match;
671
672         ret = check_match(m, name, ipv6, hookmask, i);
673         if (ret)
674                 goto err;
675
676         return 0;
677 err:
678         module_put(m->u.kernel.match->me);
679         return ret;
680 }
681
682 static inline int check_target(struct ip6t_entry *e, const char *name)
683 {
684         struct ip6t_entry_target *t;
685         struct xt_target *target;
686         int ret;
687
688         t = ip6t_get_target(e);
689         target = t->u.kernel.target;
690         ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
691                               name, e->comefrom, e->ipv6.proto,
692                               e->ipv6.invflags & IP6T_INV_PROTO);
693         if (!ret && t->u.kernel.target->checkentry
694             && !t->u.kernel.target->checkentry(name, e, target, t->data,
695                                                e->comefrom)) {
696                 duprintf("ip_tables: check failed for `%s'.\n",
697                          t->u.kernel.target->name);
698                 ret = -EINVAL;
699         }
700         return ret;
701 }
702
703 static inline int
704 find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
705                  unsigned int *i)
706 {
707         struct ip6t_entry_target *t;
708         struct xt_target *target;
709         int ret;
710         unsigned int j;
711
712         ret = check_entry(e, name);
713         if (ret)
714                 return ret;
715
716         j = 0;
717         ret = IP6T_MATCH_ITERATE(e, find_check_match, name, &e->ipv6,
718                                  e->comefrom, &j);
719         if (ret != 0)
720                 goto cleanup_matches;
721
722         t = ip6t_get_target(e);
723         target = try_then_request_module(xt_find_target(AF_INET6,
724                                                         t->u.user.name,
725                                                         t->u.user.revision),
726                                          "ip6t_%s", t->u.user.name);
727         if (IS_ERR(target) || !target) {
728                 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
729                 ret = target ? PTR_ERR(target) : -ENOENT;
730                 goto cleanup_matches;
731         }
732         t->u.kernel.target = target;
733
734         ret = check_target(e, name);
735         if (ret)
736                 goto err;
737
738         (*i)++;
739         return 0;
740  err:
741         module_put(t->u.kernel.target->me);
742  cleanup_matches:
743         IP6T_MATCH_ITERATE(e, cleanup_match, &j);
744         return ret;
745 }
746
747 static inline int
748 check_entry_size_and_hooks(struct ip6t_entry *e,
749                            struct xt_table_info *newinfo,
750                            unsigned char *base,
751                            unsigned char *limit,
752                            const unsigned int *hook_entries,
753                            const unsigned int *underflows,
754                            unsigned int *i)
755 {
756         unsigned int h;
757
758         if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
759             || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
760                 duprintf("Bad offset %p\n", e);
761                 return -EINVAL;
762         }
763
764         if (e->next_offset
765             < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
766                 duprintf("checking: element %p size %u\n",
767                          e, e->next_offset);
768                 return -EINVAL;
769         }
770
771         /* Check hooks & underflows */
772         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
773                 if ((unsigned char *)e - base == hook_entries[h])
774                         newinfo->hook_entry[h] = hook_entries[h];
775                 if ((unsigned char *)e - base == underflows[h])
776                         newinfo->underflow[h] = underflows[h];
777         }
778
779         /* FIXME: underflows must be unconditional, standard verdicts
780            < 0 (not IP6T_RETURN). --RR */
781
782         /* Clear counters and comefrom */
783         e->counters = ((struct xt_counters) { 0, 0 });
784         e->comefrom = 0;
785
786         (*i)++;
787         return 0;
788 }
789
790 static inline int
791 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
792 {
793         struct ip6t_entry_target *t;
794
795         if (i && (*i)-- == 0)
796                 return 1;
797
798         /* Cleanup all matches */
799         IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
800         t = ip6t_get_target(e);
801         if (t->u.kernel.target->destroy)
802                 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
803         module_put(t->u.kernel.target->me);
804         return 0;
805 }
806
807 /* Checks and translates the user-supplied table segment (held in
808    newinfo) */
809 static int
810 translate_table(const char *name,
811                 unsigned int valid_hooks,
812                 struct xt_table_info *newinfo,
813                 void *entry0,
814                 unsigned int size,
815                 unsigned int number,
816                 const unsigned int *hook_entries,
817                 const unsigned int *underflows)
818 {
819         unsigned int i;
820         int ret;
821
822         newinfo->size = size;
823         newinfo->number = number;
824
825         /* Init all hooks to impossible value. */
826         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
827                 newinfo->hook_entry[i] = 0xFFFFFFFF;
828                 newinfo->underflow[i] = 0xFFFFFFFF;
829         }
830
831         duprintf("translate_table: size %u\n", newinfo->size);
832         i = 0;
833         /* Walk through entries, checking offsets. */
834         ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
835                                 check_entry_size_and_hooks,
836                                 newinfo,
837                                 entry0,
838                                 entry0 + size,
839                                 hook_entries, underflows, &i);
840         if (ret != 0)
841                 return ret;
842
843         if (i != number) {
844                 duprintf("translate_table: %u not %u entries\n",
845                          i, number);
846                 return -EINVAL;
847         }
848
849         /* Check hooks all assigned */
850         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
851                 /* Only hooks which are valid */
852                 if (!(valid_hooks & (1 << i)))
853                         continue;
854                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
855                         duprintf("Invalid hook entry %u %u\n",
856                                  i, hook_entries[i]);
857                         return -EINVAL;
858                 }
859                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
860                         duprintf("Invalid underflow %u %u\n",
861                                  i, underflows[i]);
862                         return -EINVAL;
863                 }
864         }
865
866         if (!mark_source_chains(newinfo, valid_hooks, entry0))
867                 return -ELOOP;
868
869         /* Finally, each sanity check must pass */
870         i = 0;
871         ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
872                                 find_check_entry, name, size, &i);
873
874         if (ret != 0) {
875                 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
876                                    cleanup_entry, &i);
877                 return ret;
878         }
879
880         /* And one copy for every other CPU */
881         for_each_possible_cpu(i) {
882                 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
883                         memcpy(newinfo->entries[i], entry0, newinfo->size);
884         }
885
886         return 0;
887 }
888
889 /* Gets counters. */
890 static inline int
891 add_entry_to_counter(const struct ip6t_entry *e,
892                      struct xt_counters total[],
893                      unsigned int *i)
894 {
895         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
896
897         (*i)++;
898         return 0;
899 }
900
901 static inline int
902 set_entry_to_counter(const struct ip6t_entry *e,
903                      struct ip6t_counters total[],
904                      unsigned int *i)
905 {
906         SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
907
908         (*i)++;
909         return 0;
910 }
911
912 static void
913 get_counters(const struct xt_table_info *t,
914              struct xt_counters counters[])
915 {
916         unsigned int cpu;
917         unsigned int i;
918         unsigned int curcpu;
919
920         /* Instead of clearing (by a previous call to memset())
921          * the counters and using adds, we set the counters
922          * with data used by 'current' CPU
923          * We dont care about preemption here.
924          */
925         curcpu = raw_smp_processor_id();
926
927         i = 0;
928         IP6T_ENTRY_ITERATE(t->entries[curcpu],
929                            t->size,
930                            set_entry_to_counter,
931                            counters,
932                            &i);
933
934         for_each_possible_cpu(cpu) {
935                 if (cpu == curcpu)
936                         continue;
937                 i = 0;
938                 IP6T_ENTRY_ITERATE(t->entries[cpu],
939                                   t->size,
940                                   add_entry_to_counter,
941                                   counters,
942                                   &i);
943         }
944 }
945
946 static int
947 copy_entries_to_user(unsigned int total_size,
948                      struct xt_table *table,
949                      void __user *userptr)
950 {
951         unsigned int off, num, countersize;
952         struct ip6t_entry *e;
953         struct xt_counters *counters;
954         struct xt_table_info *private = table->private;
955         int ret = 0;
956         void *loc_cpu_entry;
957
958         /* We need atomic snapshot of counters: rest doesn't change
959            (other than comefrom, which userspace doesn't care
960            about). */
961         countersize = sizeof(struct xt_counters) * private->number;
962         counters = vmalloc_node(countersize, numa_node_id());
963
964         if (counters == NULL)
965                 return -ENOMEM;
966
967         /* First, sum counters... */
968         write_lock_bh(&table->lock);
969         get_counters(private, counters);
970         write_unlock_bh(&table->lock);
971
972         /* choose the copy that is on ourc node/cpu */
973         loc_cpu_entry = private->entries[raw_smp_processor_id()];
974         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
975                 ret = -EFAULT;
976                 goto free_counters;
977         }
978
979         /* FIXME: use iterator macros --RR */
980         /* ... then go back and fix counters and names */
981         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
982                 unsigned int i;
983                 struct ip6t_entry_match *m;
984                 struct ip6t_entry_target *t;
985
986                 e = (struct ip6t_entry *)(loc_cpu_entry + off);
987                 if (copy_to_user(userptr + off
988                                  + offsetof(struct ip6t_entry, counters),
989                                  &counters[num],
990                                  sizeof(counters[num])) != 0) {
991                         ret = -EFAULT;
992                         goto free_counters;
993                 }
994
995                 for (i = sizeof(struct ip6t_entry);
996                      i < e->target_offset;
997                      i += m->u.match_size) {
998                         m = (void *)e + i;
999
1000                         if (copy_to_user(userptr + off + i
1001                                          + offsetof(struct ip6t_entry_match,
1002                                                     u.user.name),
1003                                          m->u.kernel.match->name,
1004                                          strlen(m->u.kernel.match->name)+1)
1005                             != 0) {
1006                                 ret = -EFAULT;
1007                                 goto free_counters;
1008                         }
1009                 }
1010
1011                 t = ip6t_get_target(e);
1012                 if (copy_to_user(userptr + off + e->target_offset
1013                                  + offsetof(struct ip6t_entry_target,
1014                                             u.user.name),
1015                                  t->u.kernel.target->name,
1016                                  strlen(t->u.kernel.target->name)+1) != 0) {
1017                         ret = -EFAULT;
1018                         goto free_counters;
1019                 }
1020         }
1021
1022  free_counters:
1023         vfree(counters);
1024         return ret;
1025 }
1026
1027 static int
1028 get_entries(const struct ip6t_get_entries *entries,
1029             struct ip6t_get_entries __user *uptr)
1030 {
1031         int ret;
1032         struct xt_table *t;
1033
1034         t = xt_find_table_lock(AF_INET6, entries->name);
1035         if (t && !IS_ERR(t)) {
1036                 struct xt_table_info *private = t->private;
1037                 duprintf("t->private->number = %u\n", private->number);
1038                 if (entries->size == private->size)
1039                         ret = copy_entries_to_user(private->size,
1040                                                    t, uptr->entrytable);
1041                 else {
1042                         duprintf("get_entries: I've got %u not %u!\n",
1043                                  private->size, entries->size);
1044                         ret = -EINVAL;
1045                 }
1046                 module_put(t->me);
1047                 xt_table_unlock(t);
1048         } else
1049                 ret = t ? PTR_ERR(t) : -ENOENT;
1050
1051         return ret;
1052 }
1053
1054 static int
1055 do_replace(void __user *user, unsigned int len)
1056 {
1057         int ret;
1058         struct ip6t_replace tmp;
1059         struct xt_table *t;
1060         struct xt_table_info *newinfo, *oldinfo;
1061         struct xt_counters *counters;
1062         void *loc_cpu_entry, *loc_cpu_old_entry;
1063
1064         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1065                 return -EFAULT;
1066
1067         /* overflow check */
1068         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1069                 return -ENOMEM;
1070
1071         newinfo = xt_alloc_table_info(tmp.size);
1072         if (!newinfo)
1073                 return -ENOMEM;
1074
1075         /* choose the copy that is on our node/cpu */
1076         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1077         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1078                            tmp.size) != 0) {
1079                 ret = -EFAULT;
1080                 goto free_newinfo;
1081         }
1082
1083         counters = vmalloc_node(tmp.num_counters * sizeof(struct xt_counters),
1084                                 numa_node_id());
1085         if (!counters) {
1086                 ret = -ENOMEM;
1087                 goto free_newinfo;
1088         }
1089
1090         ret = translate_table(tmp.name, tmp.valid_hooks,
1091                               newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1092                               tmp.hook_entry, tmp.underflow);
1093         if (ret != 0)
1094                 goto free_newinfo_counters;
1095
1096         duprintf("ip_tables: Translated table\n");
1097
1098         t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1099                                     "ip6table_%s", tmp.name);
1100         if (!t || IS_ERR(t)) {
1101                 ret = t ? PTR_ERR(t) : -ENOENT;
1102                 goto free_newinfo_counters_untrans;
1103         }
1104
1105         /* You lied! */
1106         if (tmp.valid_hooks != t->valid_hooks) {
1107                 duprintf("Valid hook crap: %08X vs %08X\n",
1108                          tmp.valid_hooks, t->valid_hooks);
1109                 ret = -EINVAL;
1110                 goto put_module;
1111         }
1112
1113         oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1114         if (!oldinfo)
1115                 goto put_module;
1116
1117         /* Update module usage count based on number of rules */
1118         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1119                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1120         if ((oldinfo->number > oldinfo->initial_entries) ||
1121             (newinfo->number <= oldinfo->initial_entries))
1122                 module_put(t->me);
1123         if ((oldinfo->number > oldinfo->initial_entries) &&
1124             (newinfo->number <= oldinfo->initial_entries))
1125                 module_put(t->me);
1126
1127         /* Get the old counters. */
1128         get_counters(oldinfo, counters);
1129         /* Decrease module usage counts and free resource */
1130         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1131         IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1132         xt_free_table_info(oldinfo);
1133         if (copy_to_user(tmp.counters, counters,
1134                          sizeof(struct xt_counters) * tmp.num_counters) != 0)
1135                 ret = -EFAULT;
1136         vfree(counters);
1137         xt_table_unlock(t);
1138         return ret;
1139
1140  put_module:
1141         module_put(t->me);
1142         xt_table_unlock(t);
1143  free_newinfo_counters_untrans:
1144         IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1145  free_newinfo_counters:
1146         vfree(counters);
1147  free_newinfo:
1148         xt_free_table_info(newinfo);
1149         return ret;
1150 }
1151
1152 /* We're lazy, and add to the first CPU; overflow works its fey magic
1153  * and everything is OK. */
1154 static inline int
1155 add_counter_to_entry(struct ip6t_entry *e,
1156                      const struct xt_counters addme[],
1157                      unsigned int *i)
1158 {
1159 #if 0
1160         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1161                  *i,
1162                  (long unsigned int)e->counters.pcnt,
1163                  (long unsigned int)e->counters.bcnt,
1164                  (long unsigned int)addme[*i].pcnt,
1165                  (long unsigned int)addme[*i].bcnt);
1166 #endif
1167
1168         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1169
1170         (*i)++;
1171         return 0;
1172 }
1173
1174 static int
1175 do_add_counters(void __user *user, unsigned int len)
1176 {
1177         unsigned int i;
1178         struct xt_counters_info tmp, *paddc;
1179         struct xt_table_info *private;
1180         struct xt_table *t;
1181         int ret = 0;
1182         void *loc_cpu_entry;
1183
1184         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1185                 return -EFAULT;
1186
1187         if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1188                 return -EINVAL;
1189
1190         paddc = vmalloc_node(len, numa_node_id());
1191         if (!paddc)
1192                 return -ENOMEM;
1193
1194         if (copy_from_user(paddc, user, len) != 0) {
1195                 ret = -EFAULT;
1196                 goto free;
1197         }
1198
1199         t = xt_find_table_lock(AF_INET6, tmp.name);
1200         if (!t || IS_ERR(t)) {
1201                 ret = t ? PTR_ERR(t) : -ENOENT;
1202                 goto free;
1203         }
1204
1205         write_lock_bh(&t->lock);
1206         private = t->private;
1207         if (private->number != tmp.num_counters) {
1208                 ret = -EINVAL;
1209                 goto unlock_up_free;
1210         }
1211
1212         i = 0;
1213         /* Choose the copy that is on our node */
1214         loc_cpu_entry = private->entries[smp_processor_id()];
1215         IP6T_ENTRY_ITERATE(loc_cpu_entry,
1216                           private->size,
1217                           add_counter_to_entry,
1218                           paddc->counters,
1219                           &i);
1220  unlock_up_free:
1221         write_unlock_bh(&t->lock);
1222         xt_table_unlock(t);
1223         module_put(t->me);
1224  free:
1225         vfree(paddc);
1226
1227         return ret;
1228 }
1229
1230 static int
1231 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1232 {
1233         int ret;
1234
1235         if (!capable(CAP_NET_ADMIN))
1236                 return -EPERM;
1237
1238         switch (cmd) {
1239         case IP6T_SO_SET_REPLACE:
1240                 ret = do_replace(user, len);
1241                 break;
1242
1243         case IP6T_SO_SET_ADD_COUNTERS:
1244                 ret = do_add_counters(user, len);
1245                 break;
1246
1247         default:
1248                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1249                 ret = -EINVAL;
1250         }
1251
1252         return ret;
1253 }
1254
1255 static int
1256 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1257 {
1258         int ret;
1259
1260         if (!capable(CAP_NET_ADMIN))
1261                 return -EPERM;
1262
1263         switch (cmd) {
1264         case IP6T_SO_GET_INFO: {
1265                 char name[IP6T_TABLE_MAXNAMELEN];
1266                 struct xt_table *t;
1267
1268                 if (*len != sizeof(struct ip6t_getinfo)) {
1269                         duprintf("length %u != %u\n", *len,
1270                                  sizeof(struct ip6t_getinfo));
1271                         ret = -EINVAL;
1272                         break;
1273                 }
1274
1275                 if (copy_from_user(name, user, sizeof(name)) != 0) {
1276                         ret = -EFAULT;
1277                         break;
1278                 }
1279                 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1280
1281                 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1282                                             "ip6table_%s", name);
1283                 if (t && !IS_ERR(t)) {
1284                         struct ip6t_getinfo info;
1285                         struct xt_table_info *private = t->private;
1286
1287                         info.valid_hooks = t->valid_hooks;
1288                         memcpy(info.hook_entry, private->hook_entry,
1289                                sizeof(info.hook_entry));
1290                         memcpy(info.underflow, private->underflow,
1291                                sizeof(info.underflow));
1292                         info.num_entries = private->number;
1293                         info.size = private->size;
1294                         memcpy(info.name, name, sizeof(info.name));
1295
1296                         if (copy_to_user(user, &info, *len) != 0)
1297                                 ret = -EFAULT;
1298                         else
1299                                 ret = 0;
1300                         xt_table_unlock(t);
1301                         module_put(t->me);
1302                 } else
1303                         ret = t ? PTR_ERR(t) : -ENOENT;
1304         }
1305         break;
1306
1307         case IP6T_SO_GET_ENTRIES: {
1308                 struct ip6t_get_entries get;
1309
1310                 if (*len < sizeof(get)) {
1311                         duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1312                         ret = -EINVAL;
1313                 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1314                         ret = -EFAULT;
1315                 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1316                         duprintf("get_entries: %u != %u\n", *len,
1317                                  sizeof(struct ip6t_get_entries) + get.size);
1318                         ret = -EINVAL;
1319                 } else
1320                         ret = get_entries(&get, user);
1321                 break;
1322         }
1323
1324         case IP6T_SO_GET_REVISION_MATCH:
1325         case IP6T_SO_GET_REVISION_TARGET: {
1326                 struct ip6t_get_revision rev;
1327                 int target;
1328
1329                 if (*len != sizeof(rev)) {
1330                         ret = -EINVAL;
1331                         break;
1332                 }
1333                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1334                         ret = -EFAULT;
1335                         break;
1336                 }
1337
1338                 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1339                         target = 1;
1340                 else
1341                         target = 0;
1342
1343                 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1344                                                          rev.revision,
1345                                                          target, &ret),
1346                                         "ip6t_%s", rev.name);
1347                 break;
1348         }
1349
1350         default:
1351                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1352                 ret = -EINVAL;
1353         }
1354
1355         return ret;
1356 }
1357
1358 int ip6t_register_table(struct xt_table *table,
1359                         const struct ip6t_replace *repl)
1360 {
1361         int ret;
1362         struct xt_table_info *newinfo;
1363         struct xt_table_info bootstrap
1364                 = { 0, 0, 0, { 0 }, { 0 }, { } };
1365         void *loc_cpu_entry;
1366
1367         newinfo = xt_alloc_table_info(repl->size);
1368         if (!newinfo)
1369                 return -ENOMEM;
1370
1371         /* choose the copy on our node/cpu */
1372         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1373         memcpy(loc_cpu_entry, repl->entries, repl->size);
1374
1375         ret = translate_table(table->name, table->valid_hooks,
1376                               newinfo, loc_cpu_entry, repl->size,
1377                               repl->num_entries,
1378                               repl->hook_entry,
1379                               repl->underflow);
1380         if (ret != 0) {
1381                 xt_free_table_info(newinfo);
1382                 return ret;
1383         }
1384
1385         ret = xt_register_table(table, &bootstrap, newinfo);
1386         if (ret != 0) {
1387                 xt_free_table_info(newinfo);
1388                 return ret;
1389         }
1390
1391         return 0;
1392 }
1393
1394 void ip6t_unregister_table(struct xt_table *table)
1395 {
1396         struct xt_table_info *private;
1397         void *loc_cpu_entry;
1398
1399         private = xt_unregister_table(table);
1400
1401         /* Decrease module usage counts and free resources */
1402         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1403         IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1404         xt_free_table_info(private);
1405 }
1406
1407 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1408 static inline bool
1409 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1410                      u_int8_t type, u_int8_t code,
1411                      bool invert)
1412 {
1413         return (type == test_type && code >= min_code && code <= max_code)
1414                 ^ invert;
1415 }
1416
1417 static bool
1418 icmp6_match(const struct sk_buff *skb,
1419            const struct net_device *in,
1420            const struct net_device *out,
1421            const struct xt_match *match,
1422            const void *matchinfo,
1423            int offset,
1424            unsigned int protoff,
1425            bool *hotdrop)
1426 {
1427         struct icmp6hdr _icmp, *ic;
1428         const struct ip6t_icmp *icmpinfo = matchinfo;
1429
1430         /* Must not be a fragment. */
1431         if (offset)
1432                 return false;
1433
1434         ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1435         if (ic == NULL) {
1436                 /* We've been asked to examine this packet, and we
1437                    can't.  Hence, no choice but to drop. */
1438                 duprintf("Dropping evil ICMP tinygram.\n");
1439                 *hotdrop = true;
1440                 return false;
1441         }
1442
1443         return icmp6_type_code_match(icmpinfo->type,
1444                                      icmpinfo->code[0],
1445                                      icmpinfo->code[1],
1446                                      ic->icmp6_type, ic->icmp6_code,
1447                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
1448 }
1449
1450 /* Called when user tries to insert an entry of this type. */
1451 static bool
1452 icmp6_checkentry(const char *tablename,
1453            const void *entry,
1454            const struct xt_match *match,
1455            void *matchinfo,
1456            unsigned int hook_mask)
1457 {
1458         const struct ip6t_icmp *icmpinfo = matchinfo;
1459
1460         /* Must specify no unknown invflags */
1461         return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1462 }
1463
1464 /* The built-in targets: standard (NULL) and error. */
1465 static struct xt_target ip6t_standard_target __read_mostly = {
1466         .name           = IP6T_STANDARD_TARGET,
1467         .targetsize     = sizeof(int),
1468         .family         = AF_INET6,
1469 };
1470
1471 static struct xt_target ip6t_error_target __read_mostly = {
1472         .name           = IP6T_ERROR_TARGET,
1473         .target         = ip6t_error,
1474         .targetsize     = IP6T_FUNCTION_MAXNAMELEN,
1475         .family         = AF_INET6,
1476 };
1477
1478 static struct nf_sockopt_ops ip6t_sockopts = {
1479         .pf             = PF_INET6,
1480         .set_optmin     = IP6T_BASE_CTL,
1481         .set_optmax     = IP6T_SO_SET_MAX+1,
1482         .set            = do_ip6t_set_ctl,
1483         .get_optmin     = IP6T_BASE_CTL,
1484         .get_optmax     = IP6T_SO_GET_MAX+1,
1485         .get            = do_ip6t_get_ctl,
1486         .owner          = THIS_MODULE,
1487 };
1488
1489 static struct xt_match icmp6_matchstruct __read_mostly = {
1490         .name           = "icmp6",
1491         .match          = &icmp6_match,
1492         .matchsize      = sizeof(struct ip6t_icmp),
1493         .checkentry     = icmp6_checkentry,
1494         .proto          = IPPROTO_ICMPV6,
1495         .family         = AF_INET6,
1496 };
1497
1498 static int __init ip6_tables_init(void)
1499 {
1500         int ret;
1501
1502         ret = xt_proto_init(AF_INET6);
1503         if (ret < 0)
1504                 goto err1;
1505
1506         /* Noone else will be downing sem now, so we won't sleep */
1507         ret = xt_register_target(&ip6t_standard_target);
1508         if (ret < 0)
1509                 goto err2;
1510         ret = xt_register_target(&ip6t_error_target);
1511         if (ret < 0)
1512                 goto err3;
1513         ret = xt_register_match(&icmp6_matchstruct);
1514         if (ret < 0)
1515                 goto err4;
1516
1517         /* Register setsockopt */
1518         ret = nf_register_sockopt(&ip6t_sockopts);
1519         if (ret < 0)
1520                 goto err5;
1521
1522         printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1523         return 0;
1524
1525 err5:
1526         xt_unregister_match(&icmp6_matchstruct);
1527 err4:
1528         xt_unregister_target(&ip6t_error_target);
1529 err3:
1530         xt_unregister_target(&ip6t_standard_target);
1531 err2:
1532         xt_proto_fini(AF_INET6);
1533 err1:
1534         return ret;
1535 }
1536
1537 static void __exit ip6_tables_fini(void)
1538 {
1539         nf_unregister_sockopt(&ip6t_sockopts);
1540         xt_unregister_match(&icmp6_matchstruct);
1541         xt_unregister_target(&ip6t_error_target);
1542         xt_unregister_target(&ip6t_standard_target);
1543         xt_proto_fini(AF_INET6);
1544 }
1545
1546 /*
1547  * find the offset to specified header or the protocol number of last header
1548  * if target < 0. "last header" is transport protocol header, ESP, or
1549  * "No next header".
1550  *
1551  * If target header is found, its offset is set in *offset and return protocol
1552  * number. Otherwise, return -1.
1553  *
1554  * If the first fragment doesn't contain the final protocol header or
1555  * NEXTHDR_NONE it is considered invalid.
1556  *
1557  * Note that non-1st fragment is special case that "the protocol number
1558  * of last header" is "next header" field in Fragment header. In this case,
1559  * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1560  * isn't NULL.
1561  *
1562  */
1563 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1564                   int target, unsigned short *fragoff)
1565 {
1566         unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
1567         u8 nexthdr = ipv6_hdr(skb)->nexthdr;
1568         unsigned int len = skb->len - start;
1569
1570         if (fragoff)
1571                 *fragoff = 0;
1572
1573         while (nexthdr != target) {
1574                 struct ipv6_opt_hdr _hdr, *hp;
1575                 unsigned int hdrlen;
1576
1577                 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1578                         if (target < 0)
1579                                 break;
1580                         return -ENOENT;
1581                 }
1582
1583                 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1584                 if (hp == NULL)
1585                         return -EBADMSG;
1586                 if (nexthdr == NEXTHDR_FRAGMENT) {
1587                         unsigned short _frag_off;
1588                         __be16 *fp;
1589                         fp = skb_header_pointer(skb,
1590                                                 start+offsetof(struct frag_hdr,
1591                                                                frag_off),
1592                                                 sizeof(_frag_off),
1593                                                 &_frag_off);
1594                         if (fp == NULL)
1595                                 return -EBADMSG;
1596
1597                         _frag_off = ntohs(*fp) & ~0x7;
1598                         if (_frag_off) {
1599                                 if (target < 0 &&
1600                                     ((!ipv6_ext_hdr(hp->nexthdr)) ||
1601                                      hp->nexthdr == NEXTHDR_NONE)) {
1602                                         if (fragoff)
1603                                                 *fragoff = _frag_off;
1604                                         return hp->nexthdr;
1605                                 }
1606                                 return -ENOENT;
1607                         }
1608                         hdrlen = 8;
1609                 } else if (nexthdr == NEXTHDR_AUTH)
1610                         hdrlen = (hp->hdrlen + 2) << 2;
1611                 else
1612                         hdrlen = ipv6_optlen(hp);
1613
1614                 nexthdr = hp->nexthdr;
1615                 len -= hdrlen;
1616                 start += hdrlen;
1617         }
1618
1619         *offset = start;
1620         return nexthdr;
1621 }
1622
1623 EXPORT_SYMBOL(ip6t_register_table);
1624 EXPORT_SYMBOL(ip6t_unregister_table);
1625 EXPORT_SYMBOL(ip6t_do_table);
1626 EXPORT_SYMBOL(ip6t_ext_hdr);
1627 EXPORT_SYMBOL(ipv6_find_hdr);
1628
1629 module_init(ip6_tables_init);
1630 module_exit(ip6_tables_fini);