7d492226c16e8fef4c414872a0916e40e59d9fcc
[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  * 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  */
17 #include <linux/config.h>
18 #include <linux/skbuff.h>
19 #include <linux/kmod.h>
20 #include <linux/vmalloc.h>
21 #include <linux/netdevice.h>
22 #include <linux/module.h>
23 #include <linux/tcp.h>
24 #include <linux/udp.h>
25 #include <linux/icmpv6.h>
26 #include <net/ipv6.h>
27 #include <asm/uaccess.h>
28 #include <asm/semaphore.h>
29 #include <linux/proc_fs.h>
30 #include <linux/cpumask.h>
31
32 #include <linux/netfilter_ipv6/ip6_tables.h>
33
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
37
38 #define IPV6_HDR_LEN    (sizeof(struct ipv6hdr))
39 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
40
41 /*#define DEBUG_IP_FIREWALL*/
42 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
43 /*#define DEBUG_IP_FIREWALL_USER*/
44
45 #ifdef DEBUG_IP_FIREWALL
46 #define dprintf(format, args...)  printk(format , ## args)
47 #else
48 #define dprintf(format, args...)
49 #endif
50
51 #ifdef DEBUG_IP_FIREWALL_USER
52 #define duprintf(format, args...) printk(format , ## args)
53 #else
54 #define duprintf(format, args...)
55 #endif
56
57 #ifdef CONFIG_NETFILTER_DEBUG
58 #define IP_NF_ASSERT(x)                                         \
59 do {                                                            \
60         if (!(x))                                               \
61                 printk("IP_NF_ASSERT: %s:%s:%u\n",              \
62                        __FUNCTION__, __FILE__, __LINE__);       \
63 } while(0)
64 #else
65 #define IP_NF_ASSERT(x)
66 #endif
67 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
68
69 static DECLARE_MUTEX(ip6t_mutex);
70
71 /* Must have mutex */
72 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
73 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #include <linux/netfilter_ipv4/listhelp.h>
75
76 #if 0
77 /* All the better to debug you with... */
78 #define static
79 #define inline
80 #endif
81
82 /*
83    We keep a set of rules for each CPU, so we can avoid write-locking
84    them in the softirq when updating the counters and therefore
85    only need to read-lock in the softirq; doing a write_lock_bh() in user
86    context stops packets coming through and allows user context to read
87    the counters or update the rules.
88
89    To be cache friendly on SMP, we arrange them like so:
90    [ n-entries ]
91    ... cache-align padding ...
92    [ n-entries ]
93
94    Hence the start of any table is given by get_table() below.  */
95
96 /* The table itself */
97 struct ip6t_table_info
98 {
99         /* Size per table */
100         unsigned int size;
101         /* Number of entries: FIXME. --RR */
102         unsigned int number;
103         /* Initial number of entries. Needed for module usage count */
104         unsigned int initial_entries;
105
106         /* Entry points and underflows */
107         unsigned int hook_entry[NF_IP6_NUMHOOKS];
108         unsigned int underflow[NF_IP6_NUMHOOKS];
109
110         /* ip6t_entry tables: one per CPU */
111         char entries[0] ____cacheline_aligned;
112 };
113
114 static LIST_HEAD(ip6t_target);
115 static LIST_HEAD(ip6t_match);
116 static LIST_HEAD(ip6t_tables);
117 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
118
119 #ifdef CONFIG_SMP
120 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
121 #else
122 #define TABLE_OFFSET(t,p) 0
123 #endif
124
125 #if 0
126 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
127 #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; })
128 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
129 #endif
130
131 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
132                               struct in6_addr addr2)
133 {
134         int i;
135         for( i = 0; i < 16; i++){
136                 if((addr1.s6_addr[i] & mask.s6_addr[i]) != 
137                    (addr2.s6_addr[i] & mask.s6_addr[i]))
138                         return 1;
139         }
140         return 0;
141 }
142
143 /* Check for an extension */
144 int 
145 ip6t_ext_hdr(u8 nexthdr)
146 {
147         return ( (nexthdr == IPPROTO_HOPOPTS)   ||
148                  (nexthdr == IPPROTO_ROUTING)   ||
149                  (nexthdr == IPPROTO_FRAGMENT)  ||
150                  (nexthdr == IPPROTO_ESP)       ||
151                  (nexthdr == IPPROTO_AH)        ||
152                  (nexthdr == IPPROTO_NONE)      ||
153                  (nexthdr == IPPROTO_DSTOPTS) );
154 }
155
156 /* Returns whether matches rule or not. */
157 static inline int
158 ip6_packet_match(const struct sk_buff *skb,
159                  const char *indev,
160                  const char *outdev,
161                  const struct ip6t_ip6 *ip6info,
162                  unsigned int *protoff,
163                  int *fragoff)
164 {
165         size_t i;
166         unsigned long ret;
167         const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
168
169 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
170
171         if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
172                   IP6T_INV_SRCIP)
173             || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
174                      IP6T_INV_DSTIP)) {
175                 dprintf("Source or dest mismatch.\n");
176 /*
177                 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
178                         ipinfo->smsk.s_addr, ipinfo->src.s_addr,
179                         ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
180                 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
181                         ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
182                         ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
183                 return 0;
184         }
185
186         /* Look for ifname matches; this should unroll nicely. */
187         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
188                 ret |= (((const unsigned long *)indev)[i]
189                         ^ ((const unsigned long *)ip6info->iniface)[i])
190                         & ((const unsigned long *)ip6info->iniface_mask)[i];
191         }
192
193         if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
194                 dprintf("VIA in mismatch (%s vs %s).%s\n",
195                         indev, ip6info->iniface,
196                         ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
197                 return 0;
198         }
199
200         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
201                 ret |= (((const unsigned long *)outdev)[i]
202                         ^ ((const unsigned long *)ip6info->outiface)[i])
203                         & ((const unsigned long *)ip6info->outiface_mask)[i];
204         }
205
206         if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
207                 dprintf("VIA out mismatch (%s vs %s).%s\n",
208                         outdev, ip6info->outiface,
209                         ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
210                 return 0;
211         }
212
213 /* ... might want to do something with class and flowlabel here ... */
214
215         /* look for the desired protocol header */
216         if((ip6info->flags & IP6T_F_PROTO)) {
217                 u_int8_t currenthdr = ipv6->nexthdr;
218                 struct ipv6_opt_hdr _hdr, *hp;
219                 u_int16_t ptr;          /* Header offset in skb */
220                 u_int16_t hdrlen;       /* Header */
221                 u_int16_t _fragoff = 0, *fp = NULL;
222
223                 ptr = IPV6_HDR_LEN;
224
225                 while (ip6t_ext_hdr(currenthdr)) {
226                         /* Is there enough space for the next ext header? */
227                         if (skb->len - ptr < IPV6_OPTHDR_LEN)
228                                 return 0;
229
230                         /* NONE or ESP: there isn't protocol part */
231                         /* If we want to count these packets in '-p all',
232                          * we will change the return 0 to 1*/
233                         if ((currenthdr == IPPROTO_NONE) || 
234                                 (currenthdr == IPPROTO_ESP))
235                                 break;
236
237                         hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
238                         BUG_ON(hp == NULL);
239
240                         /* Size calculation */
241                         if (currenthdr == IPPROTO_FRAGMENT) {
242                                 fp = skb_header_pointer(skb,
243                                                    ptr+offsetof(struct frag_hdr,
244                                                                 frag_off),
245                                                    sizeof(_fragoff),
246                                                    &_fragoff);
247                                 if (fp == NULL)
248                                         return 0;
249
250                                 _fragoff = ntohs(*fp) & ~0x7;
251                                 hdrlen = 8;
252                         } else if (currenthdr == IPPROTO_AH)
253                                 hdrlen = (hp->hdrlen+2)<<2;
254                         else
255                                 hdrlen = ipv6_optlen(hp);
256
257                         currenthdr = hp->nexthdr;
258                         ptr += hdrlen;
259                         /* ptr is too large */
260                         if ( ptr > skb->len ) 
261                                 return 0;
262                         if (_fragoff) {
263                                 if (ip6t_ext_hdr(currenthdr))
264                                         return 0;
265                                 break;
266                         }
267                 }
268
269                 *protoff = ptr;
270                 *fragoff = _fragoff;
271
272                 /* currenthdr contains the protocol header */
273
274                 dprintf("Packet protocol %hi ?= %s%hi.\n",
275                                 currenthdr, 
276                                 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
277                                 ip6info->proto);
278
279                 if (ip6info->proto == currenthdr) {
280                         if(ip6info->invflags & IP6T_INV_PROTO) {
281                                 return 0;
282                         }
283                         return 1;
284                 }
285
286                 /* We need match for the '-p all', too! */
287                 if ((ip6info->proto != 0) &&
288                         !(ip6info->invflags & IP6T_INV_PROTO))
289                         return 0;
290         }
291         return 1;
292 }
293
294 /* should be ip6 safe */
295 static inline int 
296 ip6_checkentry(const struct ip6t_ip6 *ipv6)
297 {
298         if (ipv6->flags & ~IP6T_F_MASK) {
299                 duprintf("Unknown flag bits set: %08X\n",
300                          ipv6->flags & ~IP6T_F_MASK);
301                 return 0;
302         }
303         if (ipv6->invflags & ~IP6T_INV_MASK) {
304                 duprintf("Unknown invflag bits set: %08X\n",
305                          ipv6->invflags & ~IP6T_INV_MASK);
306                 return 0;
307         }
308         return 1;
309 }
310
311 static unsigned int
312 ip6t_error(struct sk_buff **pskb,
313           const struct net_device *in,
314           const struct net_device *out,
315           unsigned int hooknum,
316           const void *targinfo,
317           void *userinfo)
318 {
319         if (net_ratelimit())
320                 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
321
322         return NF_DROP;
323 }
324
325 static inline
326 int do_match(struct ip6t_entry_match *m,
327              const struct sk_buff *skb,
328              const struct net_device *in,
329              const struct net_device *out,
330              int offset,
331              unsigned int protoff,
332              int *hotdrop)
333 {
334         /* Stop iteration if it doesn't match */
335         if (!m->u.kernel.match->match(skb, in, out, m->data,
336                                       offset, protoff, hotdrop))
337                 return 1;
338         else
339                 return 0;
340 }
341
342 static inline struct ip6t_entry *
343 get_entry(void *base, unsigned int offset)
344 {
345         return (struct ip6t_entry *)(base + offset);
346 }
347
348 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
349 unsigned int
350 ip6t_do_table(struct sk_buff **pskb,
351               unsigned int hook,
352               const struct net_device *in,
353               const struct net_device *out,
354               struct ip6t_table *table,
355               void *userdata)
356 {
357         static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
358         int offset = 0;
359         unsigned int protoff = 0;
360         int hotdrop = 0;
361         /* Initializing verdict to NF_DROP keeps gcc happy. */
362         unsigned int verdict = NF_DROP;
363         const char *indev, *outdev;
364         void *table_base;
365         struct ip6t_entry *e, *back;
366
367         /* Initialization */
368         indev = in ? in->name : nulldevname;
369         outdev = out ? out->name : nulldevname;
370         /* We handle fragments by dealing with the first fragment as
371          * if it was a normal packet.  All other fragments are treated
372          * normally, except that they will NEVER match rules that ask
373          * things we don't know, ie. tcp syn flag or ports).  If the
374          * rule is also a fragment-specific rule, non-fragments won't
375          * match it. */
376
377         read_lock_bh(&table->lock);
378         IP_NF_ASSERT(table->valid_hooks & (1 << hook));
379         table_base = (void *)table->private->entries
380                 + TABLE_OFFSET(table->private, smp_processor_id());
381         e = get_entry(table_base, table->private->hook_entry[hook]);
382
383 #ifdef CONFIG_NETFILTER_DEBUG
384         /* Check noone else using our table */
385         if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
386             && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
387                 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
388                        smp_processor_id(),
389                        table->name,
390                        &((struct ip6t_entry *)table_base)->comefrom,
391                        ((struct ip6t_entry *)table_base)->comefrom);
392         }
393         ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
394 #endif
395
396         /* For return from builtin chain */
397         back = get_entry(table_base, table->private->underflow[hook]);
398
399         do {
400                 IP_NF_ASSERT(e);
401                 IP_NF_ASSERT(back);
402                 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
403                         &protoff, &offset)) {
404                         struct ip6t_entry_target *t;
405
406                         if (IP6T_MATCH_ITERATE(e, do_match,
407                                                *pskb, in, out,
408                                                offset, protoff, &hotdrop) != 0)
409                                 goto no_match;
410
411                         ADD_COUNTER(e->counters,
412                                     ntohs((*pskb)->nh.ipv6h->payload_len)
413                                     + IPV6_HDR_LEN,
414                                     1);
415
416                         t = ip6t_get_target(e);
417                         IP_NF_ASSERT(t->u.kernel.target);
418                         /* Standard target? */
419                         if (!t->u.kernel.target->target) {
420                                 int v;
421
422                                 v = ((struct ip6t_standard_target *)t)->verdict;
423                                 if (v < 0) {
424                                         /* Pop from stack? */
425                                         if (v != IP6T_RETURN) {
426                                                 verdict = (unsigned)(-v) - 1;
427                                                 break;
428                                         }
429                                         e = back;
430                                         back = get_entry(table_base,
431                                                          back->comefrom);
432                                         continue;
433                                 }
434                                 if (table_base + v != (void *)e + e->next_offset
435                                     && !(e->ipv6.flags & IP6T_F_GOTO)) {
436                                         /* Save old back ptr in next entry */
437                                         struct ip6t_entry *next
438                                                 = (void *)e + e->next_offset;
439                                         next->comefrom
440                                                 = (void *)back - table_base;
441                                         /* set back pointer to next entry */
442                                         back = next;
443                                 }
444
445                                 e = get_entry(table_base, v);
446                         } else {
447                                 /* Targets which reenter must return
448                                    abs. verdicts */
449 #ifdef CONFIG_NETFILTER_DEBUG
450                                 ((struct ip6t_entry *)table_base)->comefrom
451                                         = 0xeeeeeeec;
452 #endif
453                                 verdict = t->u.kernel.target->target(pskb,
454                                                                      in, out,
455                                                                      hook,
456                                                                      t->data,
457                                                                      userdata);
458
459 #ifdef CONFIG_NETFILTER_DEBUG
460                                 if (((struct ip6t_entry *)table_base)->comefrom
461                                     != 0xeeeeeeec
462                                     && verdict == IP6T_CONTINUE) {
463                                         printk("Target %s reentered!\n",
464                                                t->u.kernel.target->name);
465                                         verdict = NF_DROP;
466                                 }
467                                 ((struct ip6t_entry *)table_base)->comefrom
468                                         = 0x57acc001;
469 #endif
470                                 if (verdict == IP6T_CONTINUE)
471                                         e = (void *)e + e->next_offset;
472                                 else
473                                         /* Verdict */
474                                         break;
475                         }
476                 } else {
477
478                 no_match:
479                         e = (void *)e + e->next_offset;
480                 }
481         } while (!hotdrop);
482
483 #ifdef CONFIG_NETFILTER_DEBUG
484         ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
485 #endif
486         read_unlock_bh(&table->lock);
487
488 #ifdef DEBUG_ALLOW_ALL
489         return NF_ACCEPT;
490 #else
491         if (hotdrop)
492                 return NF_DROP;
493         else return verdict;
494 #endif
495 }
496
497 /*
498  * These are weird, but module loading must not be done with mutex
499  * held (since they will register), and we have to have a single
500  * function to use try_then_request_module().
501  */
502
503 /* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
504 static inline struct ip6t_table *find_table_lock(const char *name)
505 {
506         struct ip6t_table *t;
507
508         if (down_interruptible(&ip6t_mutex) != 0)
509                 return ERR_PTR(-EINTR);
510
511         list_for_each_entry(t, &ip6t_tables, list)
512                 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
513                         return t;
514         up(&ip6t_mutex);
515         return NULL;
516 }
517
518 /* Find match, grabs ref.  Returns ERR_PTR() on error. */
519 static inline struct ip6t_match *find_match(const char *name, u8 revision)
520 {
521         struct ip6t_match *m;
522         int err = 0;
523
524         if (down_interruptible(&ip6t_mutex) != 0)
525                 return ERR_PTR(-EINTR);
526
527         list_for_each_entry(m, &ip6t_match, list) {
528                 if (strcmp(m->name, name) == 0) {
529                         if (m->revision == revision) {
530                                 if (try_module_get(m->me)) {
531                                         up(&ip6t_mutex);
532                                         return m;
533                                 }
534                         } else
535                                 err = -EPROTOTYPE; /* Found something. */
536                 }
537         }
538         up(&ip6t_mutex);
539         return ERR_PTR(err);
540 }
541
542 /* Find target, grabs ref.  Returns ERR_PTR() on error. */
543 static inline struct ip6t_target *find_target(const char *name, u8 revision)
544 {
545         struct ip6t_target *t;
546         int err = 0;
547
548         if (down_interruptible(&ip6t_mutex) != 0)
549                 return ERR_PTR(-EINTR);
550
551         list_for_each_entry(t, &ip6t_target, list) {
552                 if (strcmp(t->name, name) == 0) {
553                         if (t->revision == revision) {
554                                 if (try_module_get(t->me)) {
555                                         up(&ip6t_mutex);
556                                         return t;
557                                 }
558                         } else
559                                 err = -EPROTOTYPE; /* Found something. */
560                 }
561         }
562         up(&ip6t_mutex);
563         return ERR_PTR(err);
564 }
565
566 struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
567 {
568         struct ip6t_target *target;
569
570         target = try_then_request_module(find_target(name, revision),
571                                          "ip6t_%s", name);
572         if (IS_ERR(target) || !target)
573                 return NULL;
574         return target;
575 }
576
577 static int match_revfn(const char *name, u8 revision, int *bestp)
578 {
579         struct ip6t_match *m;
580         int have_rev = 0;
581
582         list_for_each_entry(m, &ip6t_match, list) {
583                 if (strcmp(m->name, name) == 0) {
584                         if (m->revision > *bestp)
585                                 *bestp = m->revision;
586                         if (m->revision == revision)
587                                 have_rev = 1;
588                 }
589         }
590         return have_rev;
591 }
592
593 static int target_revfn(const char *name, u8 revision, int *bestp)
594 {
595         struct ip6t_target *t;
596         int have_rev = 0;
597
598         list_for_each_entry(t, &ip6t_target, list) {
599                 if (strcmp(t->name, name) == 0) {
600                         if (t->revision > *bestp)
601                                 *bestp = t->revision;
602                         if (t->revision == revision)
603                                 have_rev = 1;
604                 }
605         }
606         return have_rev;
607 }
608
609 /* Returns true or fals (if no such extension at all) */
610 static inline int find_revision(const char *name, u8 revision,
611                                 int (*revfn)(const char *, u8, int *),
612                                 int *err)
613 {
614         int have_rev, best = -1;
615
616         if (down_interruptible(&ip6t_mutex) != 0) {
617                 *err = -EINTR;
618                 return 1;
619         }
620         have_rev = revfn(name, revision, &best);
621         up(&ip6t_mutex);
622
623         /* Nothing at all?  Return 0 to try loading module. */
624         if (best == -1) {
625                 *err = -ENOENT;
626                 return 0;
627         }
628
629         *err = best;
630         if (!have_rev)
631                 *err = -EPROTONOSUPPORT;
632         return 1;
633 }
634
635
636 /* All zeroes == unconditional rule. */
637 static inline int
638 unconditional(const struct ip6t_ip6 *ipv6)
639 {
640         unsigned int i;
641
642         for (i = 0; i < sizeof(*ipv6); i++)
643                 if (((char *)ipv6)[i])
644                         break;
645
646         return (i == sizeof(*ipv6));
647 }
648
649 /* Figures out from what hook each rule can be called: returns 0 if
650    there are loops.  Puts hook bitmask in comefrom. */
651 static int
652 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
653 {
654         unsigned int hook;
655
656         /* No recursion; use packet counter to save back ptrs (reset
657            to 0 as we leave), and comefrom to save source hook bitmask */
658         for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
659                 unsigned int pos = newinfo->hook_entry[hook];
660                 struct ip6t_entry *e
661                         = (struct ip6t_entry *)(newinfo->entries + pos);
662
663                 if (!(valid_hooks & (1 << hook)))
664                         continue;
665
666                 /* Set initial back pointer. */
667                 e->counters.pcnt = pos;
668
669                 for (;;) {
670                         struct ip6t_standard_target *t
671                                 = (void *)ip6t_get_target(e);
672
673                         if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
674                                 printk("iptables: loop hook %u pos %u %08X.\n",
675                                        hook, pos, e->comefrom);
676                                 return 0;
677                         }
678                         e->comefrom
679                                 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
680
681                         /* Unconditional return/END. */
682                         if (e->target_offset == sizeof(struct ip6t_entry)
683                             && (strcmp(t->target.u.user.name,
684                                        IP6T_STANDARD_TARGET) == 0)
685                             && t->verdict < 0
686                             && unconditional(&e->ipv6)) {
687                                 unsigned int oldpos, size;
688
689                                 /* Return: backtrack through the last
690                                    big jump. */
691                                 do {
692                                         e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
693 #ifdef DEBUG_IP_FIREWALL_USER
694                                         if (e->comefrom
695                                             & (1 << NF_IP6_NUMHOOKS)) {
696                                                 duprintf("Back unset "
697                                                          "on hook %u "
698                                                          "rule %u\n",
699                                                          hook, pos);
700                                         }
701 #endif
702                                         oldpos = pos;
703                                         pos = e->counters.pcnt;
704                                         e->counters.pcnt = 0;
705
706                                         /* We're at the start. */
707                                         if (pos == oldpos)
708                                                 goto next;
709
710                                         e = (struct ip6t_entry *)
711                                                 (newinfo->entries + pos);
712                                 } while (oldpos == pos + e->next_offset);
713
714                                 /* Move along one */
715                                 size = e->next_offset;
716                                 e = (struct ip6t_entry *)
717                                         (newinfo->entries + pos + size);
718                                 e->counters.pcnt = pos;
719                                 pos += size;
720                         } else {
721                                 int newpos = t->verdict;
722
723                                 if (strcmp(t->target.u.user.name,
724                                            IP6T_STANDARD_TARGET) == 0
725                                     && newpos >= 0) {
726                                         /* This a jump; chase it. */
727                                         duprintf("Jump rule %u -> %u\n",
728                                                  pos, newpos);
729                                 } else {
730                                         /* ... this is a fallthru */
731                                         newpos = pos + e->next_offset;
732                                 }
733                                 e = (struct ip6t_entry *)
734                                         (newinfo->entries + newpos);
735                                 e->counters.pcnt = pos;
736                                 pos = newpos;
737                         }
738                 }
739                 next:
740                 duprintf("Finished chain %u\n", hook);
741         }
742         return 1;
743 }
744
745 static inline int
746 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
747 {
748         if (i && (*i)-- == 0)
749                 return 1;
750
751         if (m->u.kernel.match->destroy)
752                 m->u.kernel.match->destroy(m->data,
753                                            m->u.match_size - sizeof(*m));
754         module_put(m->u.kernel.match->me);
755         return 0;
756 }
757
758 static inline int
759 standard_check(const struct ip6t_entry_target *t,
760                unsigned int max_offset)
761 {
762         struct ip6t_standard_target *targ = (void *)t;
763
764         /* Check standard info. */
765         if (t->u.target_size
766             != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
767                 duprintf("standard_check: target size %u != %u\n",
768                          t->u.target_size,
769                          IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
770                 return 0;
771         }
772
773         if (targ->verdict >= 0
774             && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
775                 duprintf("ip6t_standard_check: bad verdict (%i)\n",
776                          targ->verdict);
777                 return 0;
778         }
779
780         if (targ->verdict < -NF_MAX_VERDICT - 1) {
781                 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
782                          targ->verdict);
783                 return 0;
784         }
785         return 1;
786 }
787
788 static inline int
789 check_match(struct ip6t_entry_match *m,
790             const char *name,
791             const struct ip6t_ip6 *ipv6,
792             unsigned int hookmask,
793             unsigned int *i)
794 {
795         struct ip6t_match *match;
796
797         match = try_then_request_module(find_match(m->u.user.name,
798                                                    m->u.user.revision),
799                                         "ip6t_%s", m->u.user.name);
800         if (IS_ERR(match) || !match) {
801                 duprintf("check_match: `%s' not found\n", m->u.user.name);
802                 return match ? PTR_ERR(match) : -ENOENT;
803         }
804         m->u.kernel.match = match;
805
806         if (m->u.kernel.match->checkentry
807             && !m->u.kernel.match->checkentry(name, ipv6, m->data,
808                                               m->u.match_size - sizeof(*m),
809                                               hookmask)) {
810                 module_put(m->u.kernel.match->me);
811                 duprintf("ip_tables: check failed for `%s'.\n",
812                          m->u.kernel.match->name);
813                 return -EINVAL;
814         }
815
816         (*i)++;
817         return 0;
818 }
819
820 static struct ip6t_target ip6t_standard_target;
821
822 static inline int
823 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
824             unsigned int *i)
825 {
826         struct ip6t_entry_target *t;
827         struct ip6t_target *target;
828         int ret;
829         unsigned int j;
830
831         if (!ip6_checkentry(&e->ipv6)) {
832                 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
833                 return -EINVAL;
834         }
835
836         j = 0;
837         ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
838         if (ret != 0)
839                 goto cleanup_matches;
840
841         t = ip6t_get_target(e);
842         target = try_then_request_module(find_target(t->u.user.name,
843                                                      t->u.user.revision),
844                                          "ip6t_%s", t->u.user.name);
845         if (IS_ERR(target) || !target) {
846                 duprintf("check_entry: `%s' not found\n", t->u.user.name);
847                 ret = target ? PTR_ERR(target) : -ENOENT;
848                 goto cleanup_matches;
849         }
850         t->u.kernel.target = target;
851
852         if (t->u.kernel.target == &ip6t_standard_target) {
853                 if (!standard_check(t, size)) {
854                         ret = -EINVAL;
855                         goto cleanup_matches;
856                 }
857         } else if (t->u.kernel.target->checkentry
858                    && !t->u.kernel.target->checkentry(name, e, t->data,
859                                                       t->u.target_size
860                                                       - sizeof(*t),
861                                                       e->comefrom)) {
862                 module_put(t->u.kernel.target->me);
863                 duprintf("ip_tables: check failed for `%s'.\n",
864                          t->u.kernel.target->name);
865                 ret = -EINVAL;
866                 goto cleanup_matches;
867         }
868
869         (*i)++;
870         return 0;
871
872  cleanup_matches:
873         IP6T_MATCH_ITERATE(e, cleanup_match, &j);
874         return ret;
875 }
876
877 static inline int
878 check_entry_size_and_hooks(struct ip6t_entry *e,
879                            struct ip6t_table_info *newinfo,
880                            unsigned char *base,
881                            unsigned char *limit,
882                            const unsigned int *hook_entries,
883                            const unsigned int *underflows,
884                            unsigned int *i)
885 {
886         unsigned int h;
887
888         if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
889             || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
890                 duprintf("Bad offset %p\n", e);
891                 return -EINVAL;
892         }
893
894         if (e->next_offset
895             < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
896                 duprintf("checking: element %p size %u\n",
897                          e, e->next_offset);
898                 return -EINVAL;
899         }
900
901         /* Check hooks & underflows */
902         for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
903                 if ((unsigned char *)e - base == hook_entries[h])
904                         newinfo->hook_entry[h] = hook_entries[h];
905                 if ((unsigned char *)e - base == underflows[h])
906                         newinfo->underflow[h] = underflows[h];
907         }
908
909         /* FIXME: underflows must be unconditional, standard verdicts
910            < 0 (not IP6T_RETURN). --RR */
911
912         /* Clear counters and comefrom */
913         e->counters = ((struct ip6t_counters) { 0, 0 });
914         e->comefrom = 0;
915
916         (*i)++;
917         return 0;
918 }
919
920 static inline int
921 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
922 {
923         struct ip6t_entry_target *t;
924
925         if (i && (*i)-- == 0)
926                 return 1;
927
928         /* Cleanup all matches */
929         IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
930         t = ip6t_get_target(e);
931         if (t->u.kernel.target->destroy)
932                 t->u.kernel.target->destroy(t->data,
933                                             t->u.target_size - sizeof(*t));
934         module_put(t->u.kernel.target->me);
935         return 0;
936 }
937
938 /* Checks and translates the user-supplied table segment (held in
939    newinfo) */
940 static int
941 translate_table(const char *name,
942                 unsigned int valid_hooks,
943                 struct ip6t_table_info *newinfo,
944                 unsigned int size,
945                 unsigned int number,
946                 const unsigned int *hook_entries,
947                 const unsigned int *underflows)
948 {
949         unsigned int i;
950         int ret;
951
952         newinfo->size = size;
953         newinfo->number = number;
954
955         /* Init all hooks to impossible value. */
956         for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
957                 newinfo->hook_entry[i] = 0xFFFFFFFF;
958                 newinfo->underflow[i] = 0xFFFFFFFF;
959         }
960
961         duprintf("translate_table: size %u\n", newinfo->size);
962         i = 0;
963         /* Walk through entries, checking offsets. */
964         ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
965                                 check_entry_size_and_hooks,
966                                 newinfo,
967                                 newinfo->entries,
968                                 newinfo->entries + size,
969                                 hook_entries, underflows, &i);
970         if (ret != 0)
971                 return ret;
972
973         if (i != number) {
974                 duprintf("translate_table: %u not %u entries\n",
975                          i, number);
976                 return -EINVAL;
977         }
978
979         /* Check hooks all assigned */
980         for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
981                 /* Only hooks which are valid */
982                 if (!(valid_hooks & (1 << i)))
983                         continue;
984                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
985                         duprintf("Invalid hook entry %u %u\n",
986                                  i, hook_entries[i]);
987                         return -EINVAL;
988                 }
989                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
990                         duprintf("Invalid underflow %u %u\n",
991                                  i, underflows[i]);
992                         return -EINVAL;
993                 }
994         }
995
996         if (!mark_source_chains(newinfo, valid_hooks))
997                 return -ELOOP;
998
999         /* Finally, each sanity check must pass */
1000         i = 0;
1001         ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
1002                                 check_entry, name, size, &i);
1003
1004         if (ret != 0) {
1005                 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
1006                                   cleanup_entry, &i);
1007                 return ret;
1008         }
1009
1010         /* And one copy for every other CPU */
1011         for_each_cpu(i) {
1012                 if (i == 0)
1013                         continue;
1014                 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i,
1015                        newinfo->entries,
1016                        SMP_ALIGN(newinfo->size));
1017         }
1018
1019         return ret;
1020 }
1021
1022 static struct ip6t_table_info *
1023 replace_table(struct ip6t_table *table,
1024               unsigned int num_counters,
1025               struct ip6t_table_info *newinfo,
1026               int *error)
1027 {
1028         struct ip6t_table_info *oldinfo;
1029
1030 #ifdef CONFIG_NETFILTER_DEBUG
1031         {
1032                 struct ip6t_entry *table_base;
1033                 unsigned int i;
1034
1035                 for_each_cpu(i) {
1036                         table_base =
1037                                 (void *)newinfo->entries
1038                                 + TABLE_OFFSET(newinfo, i);
1039
1040                         table_base->comefrom = 0xdead57ac;
1041                 }
1042         }
1043 #endif
1044
1045         /* Do the substitution. */
1046         write_lock_bh(&table->lock);
1047         /* Check inside lock: is the old number correct? */
1048         if (num_counters != table->private->number) {
1049                 duprintf("num_counters != table->private->number (%u/%u)\n",
1050                          num_counters, table->private->number);
1051                 write_unlock_bh(&table->lock);
1052                 *error = -EAGAIN;
1053                 return NULL;
1054         }
1055         oldinfo = table->private;
1056         table->private = newinfo;
1057         newinfo->initial_entries = oldinfo->initial_entries;
1058         write_unlock_bh(&table->lock);
1059
1060         return oldinfo;
1061 }
1062
1063 /* Gets counters. */
1064 static inline int
1065 add_entry_to_counter(const struct ip6t_entry *e,
1066                      struct ip6t_counters total[],
1067                      unsigned int *i)
1068 {
1069         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1070
1071         (*i)++;
1072         return 0;
1073 }
1074
1075 static void
1076 get_counters(const struct ip6t_table_info *t,
1077              struct ip6t_counters counters[])
1078 {
1079         unsigned int cpu;
1080         unsigned int i;
1081
1082         for_each_cpu(cpu) {
1083                 i = 0;
1084                 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1085                                   t->size,
1086                                   add_entry_to_counter,
1087                                   counters,
1088                                   &i);
1089         }
1090 }
1091
1092 static int
1093 copy_entries_to_user(unsigned int total_size,
1094                      struct ip6t_table *table,
1095                      void __user *userptr)
1096 {
1097         unsigned int off, num, countersize;
1098         struct ip6t_entry *e;
1099         struct ip6t_counters *counters;
1100         int ret = 0;
1101
1102         /* We need atomic snapshot of counters: rest doesn't change
1103            (other than comefrom, which userspace doesn't care
1104            about). */
1105         countersize = sizeof(struct ip6t_counters) * table->private->number;
1106         counters = vmalloc(countersize);
1107
1108         if (counters == NULL)
1109                 return -ENOMEM;
1110
1111         /* First, sum counters... */
1112         memset(counters, 0, countersize);
1113         write_lock_bh(&table->lock);
1114         get_counters(table->private, counters);
1115         write_unlock_bh(&table->lock);
1116
1117         /* ... then copy entire thing from CPU 0... */
1118         if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1119                 ret = -EFAULT;
1120                 goto free_counters;
1121         }
1122
1123         /* FIXME: use iterator macros --RR */
1124         /* ... then go back and fix counters and names */
1125         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1126                 unsigned int i;
1127                 struct ip6t_entry_match *m;
1128                 struct ip6t_entry_target *t;
1129
1130                 e = (struct ip6t_entry *)(table->private->entries + off);
1131                 if (copy_to_user(userptr + off
1132                                  + offsetof(struct ip6t_entry, counters),
1133                                  &counters[num],
1134                                  sizeof(counters[num])) != 0) {
1135                         ret = -EFAULT;
1136                         goto free_counters;
1137                 }
1138
1139                 for (i = sizeof(struct ip6t_entry);
1140                      i < e->target_offset;
1141                      i += m->u.match_size) {
1142                         m = (void *)e + i;
1143
1144                         if (copy_to_user(userptr + off + i
1145                                          + offsetof(struct ip6t_entry_match,
1146                                                     u.user.name),
1147                                          m->u.kernel.match->name,
1148                                          strlen(m->u.kernel.match->name)+1)
1149                             != 0) {
1150                                 ret = -EFAULT;
1151                                 goto free_counters;
1152                         }
1153                 }
1154
1155                 t = ip6t_get_target(e);
1156                 if (copy_to_user(userptr + off + e->target_offset
1157                                  + offsetof(struct ip6t_entry_target,
1158                                             u.user.name),
1159                                  t->u.kernel.target->name,
1160                                  strlen(t->u.kernel.target->name)+1) != 0) {
1161                         ret = -EFAULT;
1162                         goto free_counters;
1163                 }
1164         }
1165
1166  free_counters:
1167         vfree(counters);
1168         return ret;
1169 }
1170
1171 static int
1172 get_entries(const struct ip6t_get_entries *entries,
1173             struct ip6t_get_entries __user *uptr)
1174 {
1175         int ret;
1176         struct ip6t_table *t;
1177
1178         t = find_table_lock(entries->name);
1179         if (t && !IS_ERR(t)) {
1180                 duprintf("t->private->number = %u\n",
1181                          t->private->number);
1182                 if (entries->size == t->private->size)
1183                         ret = copy_entries_to_user(t->private->size,
1184                                                    t, uptr->entrytable);
1185                 else {
1186                         duprintf("get_entries: I've got %u not %u!\n",
1187                                  t->private->size,
1188                                  entries->size);
1189                         ret = -EINVAL;
1190                 }
1191                 module_put(t->me);
1192                 up(&ip6t_mutex);
1193         } else
1194                 ret = t ? PTR_ERR(t) : -ENOENT;
1195
1196         return ret;
1197 }
1198
1199 static int
1200 do_replace(void __user *user, unsigned int len)
1201 {
1202         int ret;
1203         struct ip6t_replace tmp;
1204         struct ip6t_table *t;
1205         struct ip6t_table_info *newinfo, *oldinfo;
1206         struct ip6t_counters *counters;
1207
1208         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1209                 return -EFAULT;
1210
1211         /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1212         if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1213                 return -ENOMEM;
1214
1215         newinfo = vmalloc(sizeof(struct ip6t_table_info)
1216                           + SMP_ALIGN(tmp.size) *
1217                                         (highest_possible_processor_id()+1));
1218         if (!newinfo)
1219                 return -ENOMEM;
1220
1221         if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1222                            tmp.size) != 0) {
1223                 ret = -EFAULT;
1224                 goto free_newinfo;
1225         }
1226
1227         counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1228         if (!counters) {
1229                 ret = -ENOMEM;
1230                 goto free_newinfo;
1231         }
1232         memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1233
1234         ret = translate_table(tmp.name, tmp.valid_hooks,
1235                               newinfo, tmp.size, tmp.num_entries,
1236                               tmp.hook_entry, tmp.underflow);
1237         if (ret != 0)
1238                 goto free_newinfo_counters;
1239
1240         duprintf("ip_tables: Translated table\n");
1241
1242         t = try_then_request_module(find_table_lock(tmp.name),
1243                                     "ip6table_%s", tmp.name);
1244         if (!t || IS_ERR(t)) {
1245                 ret = t ? PTR_ERR(t) : -ENOENT;
1246                 goto free_newinfo_counters_untrans;
1247         }
1248
1249         /* You lied! */
1250         if (tmp.valid_hooks != t->valid_hooks) {
1251                 duprintf("Valid hook crap: %08X vs %08X\n",
1252                          tmp.valid_hooks, t->valid_hooks);
1253                 ret = -EINVAL;
1254                 goto put_module;
1255         }
1256
1257         oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1258         if (!oldinfo)
1259                 goto put_module;
1260
1261         /* Update module usage count based on number of rules */
1262         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1263                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1264         if ((oldinfo->number > oldinfo->initial_entries) || 
1265             (newinfo->number <= oldinfo->initial_entries)) 
1266                 module_put(t->me);
1267         if ((oldinfo->number > oldinfo->initial_entries) &&
1268             (newinfo->number <= oldinfo->initial_entries))
1269                 module_put(t->me);
1270
1271         /* Get the old counters. */
1272         get_counters(oldinfo, counters);
1273         /* Decrease module usage counts and free resource */
1274         IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1275         vfree(oldinfo);
1276         if (copy_to_user(tmp.counters, counters,
1277                          sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1278                 ret = -EFAULT;
1279         vfree(counters);
1280         up(&ip6t_mutex);
1281         return ret;
1282
1283  put_module:
1284         module_put(t->me);
1285         up(&ip6t_mutex);
1286  free_newinfo_counters_untrans:
1287         IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1288  free_newinfo_counters:
1289         vfree(counters);
1290  free_newinfo:
1291         vfree(newinfo);
1292         return ret;
1293 }
1294
1295 /* We're lazy, and add to the first CPU; overflow works its fey magic
1296  * and everything is OK. */
1297 static inline int
1298 add_counter_to_entry(struct ip6t_entry *e,
1299                      const struct ip6t_counters addme[],
1300                      unsigned int *i)
1301 {
1302 #if 0
1303         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1304                  *i,
1305                  (long unsigned int)e->counters.pcnt,
1306                  (long unsigned int)e->counters.bcnt,
1307                  (long unsigned int)addme[*i].pcnt,
1308                  (long unsigned int)addme[*i].bcnt);
1309 #endif
1310
1311         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1312
1313         (*i)++;
1314         return 0;
1315 }
1316
1317 static int
1318 do_add_counters(void __user *user, unsigned int len)
1319 {
1320         unsigned int i;
1321         struct ip6t_counters_info tmp, *paddc;
1322         struct ip6t_table *t;
1323         int ret = 0;
1324
1325         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1326                 return -EFAULT;
1327
1328         if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1329                 return -EINVAL;
1330
1331         paddc = vmalloc(len);
1332         if (!paddc)
1333                 return -ENOMEM;
1334
1335         if (copy_from_user(paddc, user, len) != 0) {
1336                 ret = -EFAULT;
1337                 goto free;
1338         }
1339
1340         t = find_table_lock(tmp.name);
1341         if (!t || IS_ERR(t)) {
1342                 ret = t ? PTR_ERR(t) : -ENOENT;
1343                 goto free;
1344         }
1345
1346         write_lock_bh(&t->lock);
1347         if (t->private->number != paddc->num_counters) {
1348                 ret = -EINVAL;
1349                 goto unlock_up_free;
1350         }
1351
1352         i = 0;
1353         IP6T_ENTRY_ITERATE(t->private->entries,
1354                           t->private->size,
1355                           add_counter_to_entry,
1356                           paddc->counters,
1357                           &i);
1358  unlock_up_free:
1359         write_unlock_bh(&t->lock);
1360         up(&ip6t_mutex);
1361         module_put(t->me);
1362  free:
1363         vfree(paddc);
1364
1365         return ret;
1366 }
1367
1368 static int
1369 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1370 {
1371         int ret;
1372
1373         if (!capable(CAP_NET_ADMIN))
1374                 return -EPERM;
1375
1376         switch (cmd) {
1377         case IP6T_SO_SET_REPLACE:
1378                 ret = do_replace(user, len);
1379                 break;
1380
1381         case IP6T_SO_SET_ADD_COUNTERS:
1382                 ret = do_add_counters(user, len);
1383                 break;
1384
1385         default:
1386                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1387                 ret = -EINVAL;
1388         }
1389
1390         return ret;
1391 }
1392
1393 static int
1394 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1395 {
1396         int ret;
1397
1398         if (!capable(CAP_NET_ADMIN))
1399                 return -EPERM;
1400
1401         switch (cmd) {
1402         case IP6T_SO_GET_INFO: {
1403                 char name[IP6T_TABLE_MAXNAMELEN];
1404                 struct ip6t_table *t;
1405
1406                 if (*len != sizeof(struct ip6t_getinfo)) {
1407                         duprintf("length %u != %u\n", *len,
1408                                  sizeof(struct ip6t_getinfo));
1409                         ret = -EINVAL;
1410                         break;
1411                 }
1412
1413                 if (copy_from_user(name, user, sizeof(name)) != 0) {
1414                         ret = -EFAULT;
1415                         break;
1416                 }
1417                 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1418
1419                 t = try_then_request_module(find_table_lock(name),
1420                                             "ip6table_%s", name);
1421                 if (t && !IS_ERR(t)) {
1422                         struct ip6t_getinfo info;
1423
1424                         info.valid_hooks = t->valid_hooks;
1425                         memcpy(info.hook_entry, t->private->hook_entry,
1426                                sizeof(info.hook_entry));
1427                         memcpy(info.underflow, t->private->underflow,
1428                                sizeof(info.underflow));
1429                         info.num_entries = t->private->number;
1430                         info.size = t->private->size;
1431                         memcpy(info.name, name, sizeof(info.name));
1432
1433                         if (copy_to_user(user, &info, *len) != 0)
1434                                 ret = -EFAULT;
1435                         else
1436                                 ret = 0;
1437                         up(&ip6t_mutex);
1438                         module_put(t->me);
1439                 } else
1440                         ret = t ? PTR_ERR(t) : -ENOENT;
1441         }
1442         break;
1443
1444         case IP6T_SO_GET_ENTRIES: {
1445                 struct ip6t_get_entries get;
1446
1447                 if (*len < sizeof(get)) {
1448                         duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1449                         ret = -EINVAL;
1450                 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1451                         ret = -EFAULT;
1452                 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1453                         duprintf("get_entries: %u != %u\n", *len,
1454                                  sizeof(struct ip6t_get_entries) + get.size);
1455                         ret = -EINVAL;
1456                 } else
1457                         ret = get_entries(&get, user);
1458                 break;
1459         }
1460
1461         case IP6T_SO_GET_REVISION_MATCH:
1462         case IP6T_SO_GET_REVISION_TARGET: {
1463                 struct ip6t_get_revision rev;
1464                 int (*revfn)(const char *, u8, int *);
1465
1466                 if (*len != sizeof(rev)) {
1467                         ret = -EINVAL;
1468                         break;
1469                 }
1470                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1471                         ret = -EFAULT;
1472                         break;
1473                 }
1474
1475                 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1476                         revfn = target_revfn;
1477                 else
1478                         revfn = match_revfn;
1479
1480                 try_then_request_module(find_revision(rev.name, rev.revision,
1481                                                       revfn, &ret),
1482                                         "ip6t_%s", rev.name);
1483                 break;
1484         }
1485
1486         default:
1487                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1488                 ret = -EINVAL;
1489         }
1490
1491         return ret;
1492 }
1493
1494 /* Registration hooks for targets. */
1495 int
1496 ip6t_register_target(struct ip6t_target *target)
1497 {
1498         int ret;
1499
1500         ret = down_interruptible(&ip6t_mutex);
1501         if (ret != 0)
1502                 return ret;
1503         list_add(&target->list, &ip6t_target);
1504         up(&ip6t_mutex);
1505         return ret;
1506 }
1507
1508 void
1509 ip6t_unregister_target(struct ip6t_target *target)
1510 {
1511         down(&ip6t_mutex);
1512         LIST_DELETE(&ip6t_target, target);
1513         up(&ip6t_mutex);
1514 }
1515
1516 int
1517 ip6t_register_match(struct ip6t_match *match)
1518 {
1519         int ret;
1520
1521         ret = down_interruptible(&ip6t_mutex);
1522         if (ret != 0)
1523                 return ret;
1524
1525         list_add(&match->list, &ip6t_match);
1526         up(&ip6t_mutex);
1527
1528         return ret;
1529 }
1530
1531 void
1532 ip6t_unregister_match(struct ip6t_match *match)
1533 {
1534         down(&ip6t_mutex);
1535         LIST_DELETE(&ip6t_match, match);
1536         up(&ip6t_mutex);
1537 }
1538
1539 int ip6t_register_table(struct ip6t_table *table,
1540                         const struct ip6t_replace *repl)
1541 {
1542         int ret;
1543         struct ip6t_table_info *newinfo;
1544         static struct ip6t_table_info bootstrap
1545                 = { 0, 0, 0, { 0 }, { 0 }, { } };
1546
1547         newinfo = vmalloc(sizeof(struct ip6t_table_info)
1548                           + SMP_ALIGN(repl->size) *
1549                                         (highest_possible_processor_id()+1));
1550         if (!newinfo)
1551                 return -ENOMEM;
1552
1553         memcpy(newinfo->entries, repl->entries, repl->size);
1554
1555         ret = translate_table(table->name, table->valid_hooks,
1556                               newinfo, repl->size,
1557                               repl->num_entries,
1558                               repl->hook_entry,
1559                               repl->underflow);
1560         if (ret != 0) {
1561                 vfree(newinfo);
1562                 return ret;
1563         }
1564
1565         ret = down_interruptible(&ip6t_mutex);
1566         if (ret != 0) {
1567                 vfree(newinfo);
1568                 return ret;
1569         }
1570
1571         /* Don't autoload: we'd eat our tail... */
1572         if (list_named_find(&ip6t_tables, table->name)) {
1573                 ret = -EEXIST;
1574                 goto free_unlock;
1575         }
1576
1577         /* Simplifies replace_table code. */
1578         table->private = &bootstrap;
1579         if (!replace_table(table, 0, newinfo, &ret))
1580                 goto free_unlock;
1581
1582         duprintf("table->private->number = %u\n",
1583                  table->private->number);
1584
1585         /* save number of initial entries */
1586         table->private->initial_entries = table->private->number;
1587
1588         rwlock_init(&table->lock);
1589         list_prepend(&ip6t_tables, table);
1590
1591  unlock:
1592         up(&ip6t_mutex);
1593         return ret;
1594
1595  free_unlock:
1596         vfree(newinfo);
1597         goto unlock;
1598 }
1599
1600 void ip6t_unregister_table(struct ip6t_table *table)
1601 {
1602         down(&ip6t_mutex);
1603         LIST_DELETE(&ip6t_tables, table);
1604         up(&ip6t_mutex);
1605
1606         /* Decrease module usage counts and free resources */
1607         IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1608                           cleanup_entry, NULL);
1609         vfree(table->private);
1610 }
1611
1612 /* Returns 1 if the port is matched by the range, 0 otherwise */
1613 static inline int
1614 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1615 {
1616         int ret;
1617
1618         ret = (port >= min && port <= max) ^ invert;
1619         return ret;
1620 }
1621
1622 static int
1623 tcp_find_option(u_int8_t option,
1624                 const struct sk_buff *skb,
1625                 unsigned int tcpoff,
1626                 unsigned int optlen,
1627                 int invert,
1628                 int *hotdrop)
1629 {
1630         /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1631         u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1632         unsigned int i;
1633
1634         duprintf("tcp_match: finding option\n");
1635         if (!optlen)
1636                 return invert;
1637         /* If we don't have the whole header, drop packet. */
1638         op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1639                                 _opt);
1640         if (op == NULL) {
1641                 *hotdrop = 1;
1642                 return 0;
1643         }
1644
1645         for (i = 0; i < optlen; ) {
1646                 if (op[i] == option) return !invert;
1647                 if (op[i] < 2) i++;
1648                 else i += op[i+1]?:1;
1649         }
1650
1651         return invert;
1652 }
1653
1654 static int
1655 tcp_match(const struct sk_buff *skb,
1656           const struct net_device *in,
1657           const struct net_device *out,
1658           const void *matchinfo,
1659           int offset,
1660           unsigned int protoff,
1661           int *hotdrop)
1662 {
1663         struct tcphdr _tcph, *th;
1664         const struct ip6t_tcp *tcpinfo = matchinfo;
1665
1666         if (offset) {
1667                 /* To quote Alan:
1668
1669                    Don't allow a fragment of TCP 8 bytes in. Nobody normal
1670                    causes this. Its a cracker trying to break in by doing a
1671                    flag overwrite to pass the direction checks.
1672                 */
1673                 if (offset == 1) {
1674                         duprintf("Dropping evil TCP offset=1 frag.\n");
1675                         *hotdrop = 1;
1676                 }
1677                 /* Must not be a fragment. */
1678                 return 0;
1679         }
1680
1681 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1682
1683         th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1684         if (th == NULL) {
1685                 /* We've been asked to examine this packet, and we
1686                    can't.  Hence, no choice but to drop. */
1687                 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1688                 *hotdrop = 1;
1689                 return 0;
1690         }
1691
1692         if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1693                         ntohs(th->source),
1694                         !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1695                 return 0;
1696         if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1697                         ntohs(th->dest),
1698                         !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1699                 return 0;
1700         if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1701                       == tcpinfo->flg_cmp,
1702                       IP6T_TCP_INV_FLAGS))
1703                 return 0;
1704         if (tcpinfo->option) {
1705                 if (th->doff * 4 < sizeof(_tcph)) {
1706                         *hotdrop = 1;
1707                         return 0;
1708                 }
1709                 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1710                                      th->doff*4 - sizeof(*th),
1711                                      tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1712                                      hotdrop))
1713                         return 0;
1714         }
1715         return 1;
1716 }
1717
1718 /* Called when user tries to insert an entry of this type. */
1719 static int
1720 tcp_checkentry(const char *tablename,
1721                const struct ip6t_ip6 *ipv6,
1722                void *matchinfo,
1723                unsigned int matchsize,
1724                unsigned int hook_mask)
1725 {
1726         const struct ip6t_tcp *tcpinfo = matchinfo;
1727
1728         /* Must specify proto == TCP, and no unknown invflags */
1729         return ipv6->proto == IPPROTO_TCP
1730                 && !(ipv6->invflags & IP6T_INV_PROTO)
1731                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1732                 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1733 }
1734
1735 static int
1736 udp_match(const struct sk_buff *skb,
1737           const struct net_device *in,
1738           const struct net_device *out,
1739           const void *matchinfo,
1740           int offset,
1741           unsigned int protoff,
1742           int *hotdrop)
1743 {
1744         struct udphdr _udph, *uh;
1745         const struct ip6t_udp *udpinfo = matchinfo;
1746
1747         /* Must not be a fragment. */
1748         if (offset)
1749                 return 0;
1750
1751         uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1752         if (uh == NULL) {
1753                 /* We've been asked to examine this packet, and we
1754                    can't.  Hence, no choice but to drop. */
1755                 duprintf("Dropping evil UDP tinygram.\n");
1756                 *hotdrop = 1;
1757                 return 0;
1758         }
1759
1760         return port_match(udpinfo->spts[0], udpinfo->spts[1],
1761                           ntohs(uh->source),
1762                           !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1763                 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1764                               ntohs(uh->dest),
1765                               !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1766 }
1767
1768 /* Called when user tries to insert an entry of this type. */
1769 static int
1770 udp_checkentry(const char *tablename,
1771                const struct ip6t_ip6 *ipv6,
1772                void *matchinfo,
1773                unsigned int matchinfosize,
1774                unsigned int hook_mask)
1775 {
1776         const struct ip6t_udp *udpinfo = matchinfo;
1777
1778         /* Must specify proto == UDP, and no unknown invflags */
1779         if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1780                 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1781                          IPPROTO_UDP);
1782                 return 0;
1783         }
1784         if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1785                 duprintf("ip6t_udp: matchsize %u != %u\n",
1786                          matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1787                 return 0;
1788         }
1789         if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1790                 duprintf("ip6t_udp: unknown flags %X\n",
1791                          udpinfo->invflags);
1792                 return 0;
1793         }
1794
1795         return 1;
1796 }
1797
1798 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1799 static inline int
1800 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1801                      u_int8_t type, u_int8_t code,
1802                      int invert)
1803 {
1804         return (type == test_type && code >= min_code && code <= max_code)
1805                 ^ invert;
1806 }
1807
1808 static int
1809 icmp6_match(const struct sk_buff *skb,
1810            const struct net_device *in,
1811            const struct net_device *out,
1812            const void *matchinfo,
1813            int offset,
1814            unsigned int protoff,
1815            int *hotdrop)
1816 {
1817         struct icmp6hdr _icmp, *ic;
1818         const struct ip6t_icmp *icmpinfo = matchinfo;
1819
1820         /* Must not be a fragment. */
1821         if (offset)
1822                 return 0;
1823
1824         ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1825         if (ic == NULL) {
1826                 /* We've been asked to examine this packet, and we
1827                    can't.  Hence, no choice but to drop. */
1828                 duprintf("Dropping evil ICMP tinygram.\n");
1829                 *hotdrop = 1;
1830                 return 0;
1831         }
1832
1833         return icmp6_type_code_match(icmpinfo->type,
1834                                      icmpinfo->code[0],
1835                                      icmpinfo->code[1],
1836                                      ic->icmp6_type, ic->icmp6_code,
1837                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
1838 }
1839
1840 /* Called when user tries to insert an entry of this type. */
1841 static int
1842 icmp6_checkentry(const char *tablename,
1843            const struct ip6t_ip6 *ipv6,
1844            void *matchinfo,
1845            unsigned int matchsize,
1846            unsigned int hook_mask)
1847 {
1848         const struct ip6t_icmp *icmpinfo = matchinfo;
1849
1850         /* Must specify proto == ICMP, and no unknown invflags */
1851         return ipv6->proto == IPPROTO_ICMPV6
1852                 && !(ipv6->invflags & IP6T_INV_PROTO)
1853                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1854                 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1855 }
1856
1857 /* The built-in targets: standard (NULL) and error. */
1858 static struct ip6t_target ip6t_standard_target = {
1859         .name           = IP6T_STANDARD_TARGET,
1860 };
1861
1862 static struct ip6t_target ip6t_error_target = {
1863         .name           = IP6T_ERROR_TARGET,
1864         .target         = ip6t_error,
1865 };
1866
1867 static struct nf_sockopt_ops ip6t_sockopts = {
1868         .pf             = PF_INET6,
1869         .set_optmin     = IP6T_BASE_CTL,
1870         .set_optmax     = IP6T_SO_SET_MAX+1,
1871         .set            = do_ip6t_set_ctl,
1872         .get_optmin     = IP6T_BASE_CTL,
1873         .get_optmax     = IP6T_SO_GET_MAX+1,
1874         .get            = do_ip6t_get_ctl,
1875 };
1876
1877 static struct ip6t_match tcp_matchstruct = {
1878         .name           = "tcp",
1879         .match          = &tcp_match,
1880         .checkentry     = &tcp_checkentry,
1881 };
1882
1883 static struct ip6t_match udp_matchstruct = {
1884         .name           = "udp",
1885         .match          = &udp_match,
1886         .checkentry     = &udp_checkentry,
1887 };
1888
1889 static struct ip6t_match icmp6_matchstruct = {
1890         .name           = "icmp6",
1891         .match          = &icmp6_match,
1892         .checkentry     = &icmp6_checkentry,
1893 };
1894
1895 #ifdef CONFIG_PROC_FS
1896 static inline int print_name(const char *i,
1897                              off_t start_offset, char *buffer, int length,
1898                              off_t *pos, unsigned int *count)
1899 {
1900         if ((*count)++ >= start_offset) {
1901                 unsigned int namelen;
1902
1903                 namelen = sprintf(buffer + *pos, "%s\n",
1904                                   i + sizeof(struct list_head));
1905                 if (*pos + namelen > length) {
1906                         /* Stop iterating */
1907                         return 1;
1908                 }
1909                 *pos += namelen;
1910         }
1911         return 0;
1912 }
1913
1914 static inline int print_target(const struct ip6t_target *t,
1915                                off_t start_offset, char *buffer, int length,
1916                                off_t *pos, unsigned int *count)
1917 {
1918         if (t == &ip6t_standard_target || t == &ip6t_error_target)
1919                 return 0;
1920         return print_name((char *)t, start_offset, buffer, length, pos, count);
1921 }
1922
1923 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1924 {
1925         off_t pos = 0;
1926         unsigned int count = 0;
1927
1928         if (down_interruptible(&ip6t_mutex) != 0)
1929                 return 0;
1930
1931         LIST_FIND(&ip6t_tables, print_name, char *,
1932                   offset, buffer, length, &pos, &count);
1933
1934         up(&ip6t_mutex);
1935
1936         /* `start' hack - see fs/proc/generic.c line ~105 */
1937         *start=(char *)((unsigned long)count-offset);
1938         return pos;
1939 }
1940
1941 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1942 {
1943         off_t pos = 0;
1944         unsigned int count = 0;
1945
1946         if (down_interruptible(&ip6t_mutex) != 0)
1947                 return 0;
1948
1949         LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1950                   offset, buffer, length, &pos, &count);
1951
1952         up(&ip6t_mutex);
1953
1954         *start = (char *)((unsigned long)count - offset);
1955         return pos;
1956 }
1957
1958 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1959 {
1960         off_t pos = 0;
1961         unsigned int count = 0;
1962
1963         if (down_interruptible(&ip6t_mutex) != 0)
1964                 return 0;
1965
1966         LIST_FIND(&ip6t_match, print_name, char *,
1967                   offset, buffer, length, &pos, &count);
1968
1969         up(&ip6t_mutex);
1970
1971         *start = (char *)((unsigned long)count - offset);
1972         return pos;
1973 }
1974
1975 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1976 { { "ip6_tables_names", ip6t_get_tables },
1977   { "ip6_tables_targets", ip6t_get_targets },
1978   { "ip6_tables_matches", ip6t_get_matches },
1979   { NULL, NULL} };
1980 #endif /*CONFIG_PROC_FS*/
1981
1982 static int __init init(void)
1983 {
1984         int ret;
1985
1986         /* Noone else will be downing sem now, so we won't sleep */
1987         down(&ip6t_mutex);
1988         list_append(&ip6t_target, &ip6t_standard_target);
1989         list_append(&ip6t_target, &ip6t_error_target);
1990         list_append(&ip6t_match, &tcp_matchstruct);
1991         list_append(&ip6t_match, &udp_matchstruct);
1992         list_append(&ip6t_match, &icmp6_matchstruct);
1993         up(&ip6t_mutex);
1994
1995         /* Register setsockopt */
1996         ret = nf_register_sockopt(&ip6t_sockopts);
1997         if (ret < 0) {
1998                 duprintf("Unable to register sockopts.\n");
1999                 return ret;
2000         }
2001
2002 #ifdef CONFIG_PROC_FS
2003         {
2004                 struct proc_dir_entry *proc;
2005                 int i;
2006
2007                 for (i = 0; ip6t_proc_entry[i].name; i++) {
2008                         proc = proc_net_create(ip6t_proc_entry[i].name, 0,
2009                                                ip6t_proc_entry[i].get_info);
2010                         if (!proc) {
2011                                 while (--i >= 0)
2012                                        proc_net_remove(ip6t_proc_entry[i].name);
2013                                 nf_unregister_sockopt(&ip6t_sockopts);
2014                                 return -ENOMEM;
2015                         }
2016                         proc->owner = THIS_MODULE;
2017                 }
2018         }
2019 #endif
2020
2021         printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
2022         return 0;
2023 }
2024
2025 static void __exit fini(void)
2026 {
2027         nf_unregister_sockopt(&ip6t_sockopts);
2028 #ifdef CONFIG_PROC_FS
2029         {
2030                 int i;
2031                 for (i = 0; ip6t_proc_entry[i].name; i++)
2032                         proc_net_remove(ip6t_proc_entry[i].name);
2033         }
2034 #endif
2035 }
2036
2037 /*
2038  * find specified header up to transport protocol header.
2039  * If found target header, the offset to the header is set to *offset
2040  * and return 0. otherwise, return -1.
2041  *
2042  * Notes: - non-1st Fragment Header isn't skipped.
2043  *        - ESP header isn't skipped.
2044  *        - The target header may be trancated.
2045  */
2046 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
2047 {
2048         unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
2049         u8 nexthdr = skb->nh.ipv6h->nexthdr;
2050         unsigned int len = skb->len - start;
2051
2052         while (nexthdr != target) {
2053                 struct ipv6_opt_hdr _hdr, *hp;
2054                 unsigned int hdrlen;
2055
2056                 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
2057                         return -1;
2058                 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2059                 if (hp == NULL)
2060                         return -1;
2061                 if (nexthdr == NEXTHDR_FRAGMENT) {
2062                         unsigned short _frag_off, *fp;
2063                         fp = skb_header_pointer(skb,
2064                                                 start+offsetof(struct frag_hdr,
2065                                                                frag_off),
2066                                                 sizeof(_frag_off),
2067                                                 &_frag_off);
2068                         if (fp == NULL)
2069                                 return -1;
2070
2071                         if (ntohs(*fp) & ~0x7)
2072                                 return -1;
2073                         hdrlen = 8;
2074                 } else if (nexthdr == NEXTHDR_AUTH)
2075                         hdrlen = (hp->hdrlen + 2) << 2; 
2076                 else
2077                         hdrlen = ipv6_optlen(hp); 
2078
2079                 nexthdr = hp->nexthdr;
2080                 len -= hdrlen;
2081                 start += hdrlen;
2082         }
2083
2084         *offset = start;
2085         return 0;
2086 }
2087
2088 EXPORT_SYMBOL(ip6t_register_table);
2089 EXPORT_SYMBOL(ip6t_unregister_table);
2090 EXPORT_SYMBOL(ip6t_do_table);
2091 EXPORT_SYMBOL(ip6t_register_match);
2092 EXPORT_SYMBOL(ip6t_unregister_match);
2093 EXPORT_SYMBOL(ip6t_register_target);
2094 EXPORT_SYMBOL(ip6t_unregister_target);
2095 EXPORT_SYMBOL(ip6t_ext_hdr);
2096 EXPORT_SYMBOL(ipv6_find_hdr);
2097
2098 module_init(init);
2099 module_exit(fini);