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