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