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