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