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