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