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