73034511c8db49d8b03ec2f441899a2118523af1
[powerpc.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 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                 (*pskb)->nfcache |= e->nfcache;
405                 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
406                         &protoff, &offset)) {
407                         struct ip6t_entry_target *t;
408
409                         if (IP6T_MATCH_ITERATE(e, do_match,
410                                                *pskb, in, out,
411                                                offset, protoff, &hotdrop) != 0)
412                                 goto no_match;
413
414                         ADD_COUNTER(e->counters,
415                                     ntohs((*pskb)->nh.ipv6h->payload_len)
416                                     + IPV6_HDR_LEN,
417                                     1);
418
419                         t = ip6t_get_target(e);
420                         IP_NF_ASSERT(t->u.kernel.target);
421                         /* Standard target? */
422                         if (!t->u.kernel.target->target) {
423                                 int v;
424
425                                 v = ((struct ip6t_standard_target *)t)->verdict;
426                                 if (v < 0) {
427                                         /* Pop from stack? */
428                                         if (v != IP6T_RETURN) {
429                                                 verdict = (unsigned)(-v) - 1;
430                                                 break;
431                                         }
432                                         e = back;
433                                         back = get_entry(table_base,
434                                                          back->comefrom);
435                                         continue;
436                                 }
437                                 if (table_base + v
438                                     != (void *)e + e->next_offset) {
439                                         /* Save old back ptr in next entry */
440                                         struct ip6t_entry *next
441                                                 = (void *)e + e->next_offset;
442                                         next->comefrom
443                                                 = (void *)back - table_base;
444                                         /* set back pointer to next entry */
445                                         back = next;
446                                 }
447
448                                 e = get_entry(table_base, v);
449                         } else {
450                                 /* Targets which reenter must return
451                                    abs. verdicts */
452 #ifdef CONFIG_NETFILTER_DEBUG
453                                 ((struct ip6t_entry *)table_base)->comefrom
454                                         = 0xeeeeeeec;
455 #endif
456                                 verdict = t->u.kernel.target->target(pskb,
457                                                                      in, out,
458                                                                      hook,
459                                                                      t->data,
460                                                                      userdata);
461
462 #ifdef CONFIG_NETFILTER_DEBUG
463                                 if (((struct ip6t_entry *)table_base)->comefrom
464                                     != 0xeeeeeeec
465                                     && verdict == IP6T_CONTINUE) {
466                                         printk("Target %s reentered!\n",
467                                                t->u.kernel.target->name);
468                                         verdict = NF_DROP;
469                                 }
470                                 ((struct ip6t_entry *)table_base)->comefrom
471                                         = 0x57acc001;
472 #endif
473                                 if (verdict == IP6T_CONTINUE)
474                                         e = (void *)e + e->next_offset;
475                                 else
476                                         /* Verdict */
477                                         break;
478                         }
479                 } else {
480
481                 no_match:
482                         e = (void *)e + e->next_offset;
483                 }
484         } while (!hotdrop);
485
486 #ifdef CONFIG_NETFILTER_DEBUG
487         ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
488 #endif
489         read_unlock_bh(&table->lock);
490
491 #ifdef DEBUG_ALLOW_ALL
492         return NF_ACCEPT;
493 #else
494         if (hotdrop)
495                 return NF_DROP;
496         else return verdict;
497 #endif
498 }
499
500 /* If it succeeds, returns element and locks mutex */
501 static inline void *
502 find_inlist_lock_noload(struct list_head *head,
503                         const char *name,
504                         int *error,
505                         struct semaphore *mutex)
506 {
507         void *ret;
508
509 #if 1
510         duprintf("find_inlist: searching for `%s' in %s.\n",
511                  name, head == &ip6t_target ? "ip6t_target"
512                  : head == &ip6t_match ? "ip6t_match"
513                  : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
514 #endif
515
516         *error = down_interruptible(mutex);
517         if (*error != 0)
518                 return NULL;
519
520         ret = list_named_find(head, name);
521         if (!ret) {
522                 *error = -ENOENT;
523                 up(mutex);
524         }
525         return ret;
526 }
527
528 #ifndef CONFIG_KMOD
529 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
530 #else
531 static void *
532 find_inlist_lock(struct list_head *head,
533                  const char *name,
534                  const char *prefix,
535                  int *error,
536                  struct semaphore *mutex)
537 {
538         void *ret;
539
540         ret = find_inlist_lock_noload(head, name, error, mutex);
541         if (!ret) {
542                 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
543                 request_module("%s%s", prefix, name);
544                 ret = find_inlist_lock_noload(head, name, error, mutex);
545         }
546
547         return ret;
548 }
549 #endif
550
551 static inline struct ip6t_table *
552 ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
553 {
554         return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
555 }
556
557 static inline struct ip6t_match *
558 find_match_lock(const char *name, int *error, struct semaphore *mutex)
559 {
560         return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
561 }
562
563 static struct ip6t_target *
564 ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
565 {
566         return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
567 }
568
569 /* All zeroes == unconditional rule. */
570 static inline int
571 unconditional(const struct ip6t_ip6 *ipv6)
572 {
573         unsigned int i;
574
575         for (i = 0; i < sizeof(*ipv6); i++)
576                 if (((char *)ipv6)[i])
577                         break;
578
579         return (i == sizeof(*ipv6));
580 }
581
582 /* Figures out from what hook each rule can be called: returns 0 if
583    there are loops.  Puts hook bitmask in comefrom. */
584 static int
585 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
586 {
587         unsigned int hook;
588
589         /* No recursion; use packet counter to save back ptrs (reset
590            to 0 as we leave), and comefrom to save source hook bitmask */
591         for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
592                 unsigned int pos = newinfo->hook_entry[hook];
593                 struct ip6t_entry *e
594                         = (struct ip6t_entry *)(newinfo->entries + pos);
595
596                 if (!(valid_hooks & (1 << hook)))
597                         continue;
598
599                 /* Set initial back pointer. */
600                 e->counters.pcnt = pos;
601
602                 for (;;) {
603                         struct ip6t_standard_target *t
604                                 = (void *)ip6t_get_target(e);
605
606                         if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
607                                 printk("iptables: loop hook %u pos %u %08X.\n",
608                                        hook, pos, e->comefrom);
609                                 return 0;
610                         }
611                         e->comefrom
612                                 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
613
614                         /* Unconditional return/END. */
615                         if (e->target_offset == sizeof(struct ip6t_entry)
616                             && (strcmp(t->target.u.user.name,
617                                        IP6T_STANDARD_TARGET) == 0)
618                             && t->verdict < 0
619                             && unconditional(&e->ipv6)) {
620                                 unsigned int oldpos, size;
621
622                                 /* Return: backtrack through the last
623                                    big jump. */
624                                 do {
625                                         e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
626 #ifdef DEBUG_IP_FIREWALL_USER
627                                         if (e->comefrom
628                                             & (1 << NF_IP6_NUMHOOKS)) {
629                                                 duprintf("Back unset "
630                                                          "on hook %u "
631                                                          "rule %u\n",
632                                                          hook, pos);
633                                         }
634 #endif
635                                         oldpos = pos;
636                                         pos = e->counters.pcnt;
637                                         e->counters.pcnt = 0;
638
639                                         /* We're at the start. */
640                                         if (pos == oldpos)
641                                                 goto next;
642
643                                         e = (struct ip6t_entry *)
644                                                 (newinfo->entries + pos);
645                                 } while (oldpos == pos + e->next_offset);
646
647                                 /* Move along one */
648                                 size = e->next_offset;
649                                 e = (struct ip6t_entry *)
650                                         (newinfo->entries + pos + size);
651                                 e->counters.pcnt = pos;
652                                 pos += size;
653                         } else {
654                                 int newpos = t->verdict;
655
656                                 if (strcmp(t->target.u.user.name,
657                                            IP6T_STANDARD_TARGET) == 0
658                                     && newpos >= 0) {
659                                         /* This a jump; chase it. */
660                                         duprintf("Jump rule %u -> %u\n",
661                                                  pos, newpos);
662                                 } else {
663                                         /* ... this is a fallthru */
664                                         newpos = pos + e->next_offset;
665                                 }
666                                 e = (struct ip6t_entry *)
667                                         (newinfo->entries + newpos);
668                                 e->counters.pcnt = pos;
669                                 pos = newpos;
670                         }
671                 }
672                 next:
673                 duprintf("Finished chain %u\n", hook);
674         }
675         return 1;
676 }
677
678 static inline int
679 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
680 {
681         if (i && (*i)-- == 0)
682                 return 1;
683
684         if (m->u.kernel.match->destroy)
685                 m->u.kernel.match->destroy(m->data,
686                                            m->u.match_size - sizeof(*m));
687         module_put(m->u.kernel.match->me);
688         return 0;
689 }
690
691 static inline int
692 standard_check(const struct ip6t_entry_target *t,
693                unsigned int max_offset)
694 {
695         struct ip6t_standard_target *targ = (void *)t;
696
697         /* Check standard info. */
698         if (t->u.target_size
699             != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
700                 duprintf("standard_check: target size %u != %u\n",
701                          t->u.target_size,
702                          IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
703                 return 0;
704         }
705
706         if (targ->verdict >= 0
707             && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
708                 duprintf("ip6t_standard_check: bad verdict (%i)\n",
709                          targ->verdict);
710                 return 0;
711         }
712
713         if (targ->verdict < -NF_MAX_VERDICT - 1) {
714                 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
715                          targ->verdict);
716                 return 0;
717         }
718         return 1;
719 }
720
721 static inline int
722 check_match(struct ip6t_entry_match *m,
723             const char *name,
724             const struct ip6t_ip6 *ipv6,
725             unsigned int hookmask,
726             unsigned int *i)
727 {
728         int ret;
729         struct ip6t_match *match;
730
731         match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
732         if (!match) {
733           //            duprintf("check_match: `%s' not found\n", m->u.name);
734                 return ret;
735         }
736         if (!try_module_get(match->me)) {
737                 up(&ip6t_mutex);
738                 return -ENOENT;
739         }
740         m->u.kernel.match = match;
741         up(&ip6t_mutex);
742
743         if (m->u.kernel.match->checkentry
744             && !m->u.kernel.match->checkentry(name, ipv6, m->data,
745                                               m->u.match_size - sizeof(*m),
746                                               hookmask)) {
747                 module_put(m->u.kernel.match->me);
748                 duprintf("ip_tables: check failed for `%s'.\n",
749                          m->u.kernel.match->name);
750                 return -EINVAL;
751         }
752
753         (*i)++;
754         return 0;
755 }
756
757 static struct ip6t_target ip6t_standard_target;
758
759 static inline int
760 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
761             unsigned int *i)
762 {
763         struct ip6t_entry_target *t;
764         struct ip6t_target *target;
765         int ret;
766         unsigned int j;
767
768         if (!ip6_checkentry(&e->ipv6)) {
769                 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
770                 return -EINVAL;
771         }
772
773         j = 0;
774         ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
775         if (ret != 0)
776                 goto cleanup_matches;
777
778         t = ip6t_get_target(e);
779         target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
780         if (!target) {
781                 duprintf("check_entry: `%s' not found\n", t->u.user.name);
782                 goto cleanup_matches;
783         }
784         if (!try_module_get(target->me)) {
785                 up(&ip6t_mutex);
786                 ret = -ENOENT;
787                 goto cleanup_matches;
788         }
789         t->u.kernel.target = target;
790         up(&ip6t_mutex);
791         if (!t->u.kernel.target) {
792                 ret = -EBUSY;
793                 goto cleanup_matches;
794         }
795         if (t->u.kernel.target == &ip6t_standard_target) {
796                 if (!standard_check(t, size)) {
797                         ret = -EINVAL;
798                         goto cleanup_matches;
799                 }
800         } else if (t->u.kernel.target->checkentry
801                    && !t->u.kernel.target->checkentry(name, e, t->data,
802                                                       t->u.target_size
803                                                       - sizeof(*t),
804                                                       e->comefrom)) {
805                 module_put(t->u.kernel.target->me);
806                 duprintf("ip_tables: check failed for `%s'.\n",
807                          t->u.kernel.target->name);
808                 ret = -EINVAL;
809                 goto cleanup_matches;
810         }
811
812         (*i)++;
813         return 0;
814
815  cleanup_matches:
816         IP6T_MATCH_ITERATE(e, cleanup_match, &j);
817         return ret;
818 }
819
820 static inline int
821 check_entry_size_and_hooks(struct ip6t_entry *e,
822                            struct ip6t_table_info *newinfo,
823                            unsigned char *base,
824                            unsigned char *limit,
825                            const unsigned int *hook_entries,
826                            const unsigned int *underflows,
827                            unsigned int *i)
828 {
829         unsigned int h;
830
831         if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
832             || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
833                 duprintf("Bad offset %p\n", e);
834                 return -EINVAL;
835         }
836
837         if (e->next_offset
838             < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
839                 duprintf("checking: element %p size %u\n",
840                          e, e->next_offset);
841                 return -EINVAL;
842         }
843
844         /* Check hooks & underflows */
845         for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
846                 if ((unsigned char *)e - base == hook_entries[h])
847                         newinfo->hook_entry[h] = hook_entries[h];
848                 if ((unsigned char *)e - base == underflows[h])
849                         newinfo->underflow[h] = underflows[h];
850         }
851
852         /* FIXME: underflows must be unconditional, standard verdicts
853            < 0 (not IP6T_RETURN). --RR */
854
855         /* Clear counters and comefrom */
856         e->counters = ((struct ip6t_counters) { 0, 0 });
857         e->comefrom = 0;
858
859         (*i)++;
860         return 0;
861 }
862
863 static inline int
864 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
865 {
866         struct ip6t_entry_target *t;
867
868         if (i && (*i)-- == 0)
869                 return 1;
870
871         /* Cleanup all matches */
872         IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
873         t = ip6t_get_target(e);
874         if (t->u.kernel.target->destroy)
875                 t->u.kernel.target->destroy(t->data,
876                                             t->u.target_size - sizeof(*t));
877         module_put(t->u.kernel.target->me);
878         return 0;
879 }
880
881 /* Checks and translates the user-supplied table segment (held in
882    newinfo) */
883 static int
884 translate_table(const char *name,
885                 unsigned int valid_hooks,
886                 struct ip6t_table_info *newinfo,
887                 unsigned int size,
888                 unsigned int number,
889                 const unsigned int *hook_entries,
890                 const unsigned int *underflows)
891 {
892         unsigned int i;
893         int ret;
894
895         newinfo->size = size;
896         newinfo->number = number;
897
898         /* Init all hooks to impossible value. */
899         for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
900                 newinfo->hook_entry[i] = 0xFFFFFFFF;
901                 newinfo->underflow[i] = 0xFFFFFFFF;
902         }
903
904         duprintf("translate_table: size %u\n", newinfo->size);
905         i = 0;
906         /* Walk through entries, checking offsets. */
907         ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
908                                 check_entry_size_and_hooks,
909                                 newinfo,
910                                 newinfo->entries,
911                                 newinfo->entries + size,
912                                 hook_entries, underflows, &i);
913         if (ret != 0)
914                 return ret;
915
916         if (i != number) {
917                 duprintf("translate_table: %u not %u entries\n",
918                          i, number);
919                 return -EINVAL;
920         }
921
922         /* Check hooks all assigned */
923         for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
924                 /* Only hooks which are valid */
925                 if (!(valid_hooks & (1 << i)))
926                         continue;
927                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
928                         duprintf("Invalid hook entry %u %u\n",
929                                  i, hook_entries[i]);
930                         return -EINVAL;
931                 }
932                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
933                         duprintf("Invalid underflow %u %u\n",
934                                  i, underflows[i]);
935                         return -EINVAL;
936                 }
937         }
938
939         if (!mark_source_chains(newinfo, valid_hooks))
940                 return -ELOOP;
941
942         /* Finally, each sanity check must pass */
943         i = 0;
944         ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
945                                 check_entry, name, size, &i);
946
947         if (ret != 0) {
948                 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
949                                   cleanup_entry, &i);
950                 return ret;
951         }
952
953         /* And one copy for every other CPU */
954         for (i = 1; i < num_possible_cpus(); i++) {
955                 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
956                        newinfo->entries,
957                        SMP_ALIGN(newinfo->size));
958         }
959
960         return ret;
961 }
962
963 static struct ip6t_table_info *
964 replace_table(struct ip6t_table *table,
965               unsigned int num_counters,
966               struct ip6t_table_info *newinfo,
967               int *error)
968 {
969         struct ip6t_table_info *oldinfo;
970
971 #ifdef CONFIG_NETFILTER_DEBUG
972         {
973                 struct ip6t_entry *table_base;
974                 unsigned int i;
975
976                 for (i = 0; i < num_possible_cpus(); i++) {
977                         table_base =
978                                 (void *)newinfo->entries
979                                 + TABLE_OFFSET(newinfo, i);
980
981                         table_base->comefrom = 0xdead57ac;
982                 }
983         }
984 #endif
985
986         /* Do the substitution. */
987         write_lock_bh(&table->lock);
988         /* Check inside lock: is the old number correct? */
989         if (num_counters != table->private->number) {
990                 duprintf("num_counters != table->private->number (%u/%u)\n",
991                          num_counters, table->private->number);
992                 write_unlock_bh(&table->lock);
993                 *error = -EAGAIN;
994                 return NULL;
995         }
996         oldinfo = table->private;
997         table->private = newinfo;
998         newinfo->initial_entries = oldinfo->initial_entries;
999         write_unlock_bh(&table->lock);
1000
1001         return oldinfo;
1002 }
1003
1004 /* Gets counters. */
1005 static inline int
1006 add_entry_to_counter(const struct ip6t_entry *e,
1007                      struct ip6t_counters total[],
1008                      unsigned int *i)
1009 {
1010         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1011
1012         (*i)++;
1013         return 0;
1014 }
1015
1016 static void
1017 get_counters(const struct ip6t_table_info *t,
1018              struct ip6t_counters counters[])
1019 {
1020         unsigned int cpu;
1021         unsigned int i;
1022
1023         for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
1024                 i = 0;
1025                 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1026                                   t->size,
1027                                   add_entry_to_counter,
1028                                   counters,
1029                                   &i);
1030         }
1031 }
1032
1033 static int
1034 copy_entries_to_user(unsigned int total_size,
1035                      struct ip6t_table *table,
1036                      void __user *userptr)
1037 {
1038         unsigned int off, num, countersize;
1039         struct ip6t_entry *e;
1040         struct ip6t_counters *counters;
1041         int ret = 0;
1042
1043         /* We need atomic snapshot of counters: rest doesn't change
1044            (other than comefrom, which userspace doesn't care
1045            about). */
1046         countersize = sizeof(struct ip6t_counters) * table->private->number;
1047         counters = vmalloc(countersize);
1048
1049         if (counters == NULL)
1050                 return -ENOMEM;
1051
1052         /* First, sum counters... */
1053         memset(counters, 0, countersize);
1054         write_lock_bh(&table->lock);
1055         get_counters(table->private, counters);
1056         write_unlock_bh(&table->lock);
1057
1058         /* ... then copy entire thing from CPU 0... */
1059         if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1060                 ret = -EFAULT;
1061                 goto free_counters;
1062         }
1063
1064         /* FIXME: use iterator macros --RR */
1065         /* ... then go back and fix counters and names */
1066         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1067                 unsigned int i;
1068                 struct ip6t_entry_match *m;
1069                 struct ip6t_entry_target *t;
1070
1071                 e = (struct ip6t_entry *)(table->private->entries + off);
1072                 if (copy_to_user(userptr + off
1073                                  + offsetof(struct ip6t_entry, counters),
1074                                  &counters[num],
1075                                  sizeof(counters[num])) != 0) {
1076                         ret = -EFAULT;
1077                         goto free_counters;
1078                 }
1079
1080                 for (i = sizeof(struct ip6t_entry);
1081                      i < e->target_offset;
1082                      i += m->u.match_size) {
1083                         m = (void *)e + i;
1084
1085                         if (copy_to_user(userptr + off + i
1086                                          + offsetof(struct ip6t_entry_match,
1087                                                     u.user.name),
1088                                          m->u.kernel.match->name,
1089                                          strlen(m->u.kernel.match->name)+1)
1090                             != 0) {
1091                                 ret = -EFAULT;
1092                                 goto free_counters;
1093                         }
1094                 }
1095
1096                 t = ip6t_get_target(e);
1097                 if (copy_to_user(userptr + off + e->target_offset
1098                                  + offsetof(struct ip6t_entry_target,
1099                                             u.user.name),
1100                                  t->u.kernel.target->name,
1101                                  strlen(t->u.kernel.target->name)+1) != 0) {
1102                         ret = -EFAULT;
1103                         goto free_counters;
1104                 }
1105         }
1106
1107  free_counters:
1108         vfree(counters);
1109         return ret;
1110 }
1111
1112 static int
1113 get_entries(const struct ip6t_get_entries *entries,
1114             struct ip6t_get_entries __user *uptr)
1115 {
1116         int ret;
1117         struct ip6t_table *t;
1118
1119         t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1120         if (t) {
1121                 duprintf("t->private->number = %u\n",
1122                          t->private->number);
1123                 if (entries->size == t->private->size)
1124                         ret = copy_entries_to_user(t->private->size,
1125                                                    t, uptr->entrytable);
1126                 else {
1127                         duprintf("get_entries: I've got %u not %u!\n",
1128                                  t->private->size,
1129                                  entries->size);
1130                         ret = -EINVAL;
1131                 }
1132                 up(&ip6t_mutex);
1133         } else
1134                 duprintf("get_entries: Can't find %s!\n",
1135                          entries->name);
1136
1137         return ret;
1138 }
1139
1140 static int
1141 do_replace(void __user *user, unsigned int len)
1142 {
1143         int ret;
1144         struct ip6t_replace tmp;
1145         struct ip6t_table *t;
1146         struct ip6t_table_info *newinfo, *oldinfo;
1147         struct ip6t_counters *counters;
1148
1149         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1150                 return -EFAULT;
1151
1152         /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1153         if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1154                 return -ENOMEM;
1155
1156         newinfo = vmalloc(sizeof(struct ip6t_table_info)
1157                           + SMP_ALIGN(tmp.size) * num_possible_cpus());
1158         if (!newinfo)
1159                 return -ENOMEM;
1160
1161         if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1162                            tmp.size) != 0) {
1163                 ret = -EFAULT;
1164                 goto free_newinfo;
1165         }
1166
1167         counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1168         if (!counters) {
1169                 ret = -ENOMEM;
1170                 goto free_newinfo;
1171         }
1172         memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1173
1174         ret = translate_table(tmp.name, tmp.valid_hooks,
1175                               newinfo, tmp.size, tmp.num_entries,
1176                               tmp.hook_entry, tmp.underflow);
1177         if (ret != 0)
1178                 goto free_newinfo_counters;
1179
1180         duprintf("ip_tables: Translated table\n");
1181
1182         t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1183         if (!t)
1184                 goto free_newinfo_counters_untrans;
1185
1186         /* You lied! */
1187         if (tmp.valid_hooks != t->valid_hooks) {
1188                 duprintf("Valid hook crap: %08X vs %08X\n",
1189                          tmp.valid_hooks, t->valid_hooks);
1190                 ret = -EINVAL;
1191                 goto free_newinfo_counters_untrans_unlock;
1192         }
1193
1194         /* Get a reference in advance, we're not allowed fail later */
1195         if (!try_module_get(t->me)) {
1196                 ret = -EBUSY;
1197                 goto free_newinfo_counters_untrans_unlock;
1198         }
1199
1200         oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1201         if (!oldinfo)
1202                 goto put_module;
1203
1204         /* Update module usage count based on number of rules */
1205         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1206                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1207         if ((oldinfo->number > oldinfo->initial_entries) || 
1208             (newinfo->number <= oldinfo->initial_entries)) 
1209                 module_put(t->me);
1210         if ((oldinfo->number > oldinfo->initial_entries) &&
1211             (newinfo->number <= oldinfo->initial_entries))
1212                 module_put(t->me);
1213
1214         /* Get the old counters. */
1215         get_counters(oldinfo, counters);
1216         /* Decrease module usage counts and free resource */
1217         IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1218         vfree(oldinfo);
1219         /* Silent error: too late now. */
1220         if (copy_to_user(tmp.counters, counters,
1221                          sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1222                 ret = -EFAULT;
1223         vfree(counters);
1224         up(&ip6t_mutex);
1225         return ret;
1226
1227  put_module:
1228         module_put(t->me);
1229  free_newinfo_counters_untrans_unlock:
1230         up(&ip6t_mutex);
1231  free_newinfo_counters_untrans:
1232         IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1233  free_newinfo_counters:
1234         vfree(counters);
1235  free_newinfo:
1236         vfree(newinfo);
1237         return ret;
1238 }
1239
1240 /* We're lazy, and add to the first CPU; overflow works its fey magic
1241  * and everything is OK. */
1242 static inline int
1243 add_counter_to_entry(struct ip6t_entry *e,
1244                      const struct ip6t_counters addme[],
1245                      unsigned int *i)
1246 {
1247 #if 0
1248         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1249                  *i,
1250                  (long unsigned int)e->counters.pcnt,
1251                  (long unsigned int)e->counters.bcnt,
1252                  (long unsigned int)addme[*i].pcnt,
1253                  (long unsigned int)addme[*i].bcnt);
1254 #endif
1255
1256         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1257
1258         (*i)++;
1259         return 0;
1260 }
1261
1262 static int
1263 do_add_counters(void __user *user, unsigned int len)
1264 {
1265         unsigned int i;
1266         struct ip6t_counters_info tmp, *paddc;
1267         struct ip6t_table *t;
1268         int ret;
1269
1270         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1271                 return -EFAULT;
1272
1273         if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1274                 return -EINVAL;
1275
1276         paddc = vmalloc(len);
1277         if (!paddc)
1278                 return -ENOMEM;
1279
1280         if (copy_from_user(paddc, user, len) != 0) {
1281                 ret = -EFAULT;
1282                 goto free;
1283         }
1284
1285         t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1286         if (!t)
1287                 goto free;
1288
1289         write_lock_bh(&t->lock);
1290         if (t->private->number != paddc->num_counters) {
1291                 ret = -EINVAL;
1292                 goto unlock_up_free;
1293         }
1294
1295         i = 0;
1296         IP6T_ENTRY_ITERATE(t->private->entries,
1297                           t->private->size,
1298                           add_counter_to_entry,
1299                           paddc->counters,
1300                           &i);
1301  unlock_up_free:
1302         write_unlock_bh(&t->lock);
1303         up(&ip6t_mutex);
1304  free:
1305         vfree(paddc);
1306
1307         return ret;
1308 }
1309
1310 static int
1311 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1312 {
1313         int ret;
1314
1315         if (!capable(CAP_NET_ADMIN))
1316                 return -EPERM;
1317
1318         switch (cmd) {
1319         case IP6T_SO_SET_REPLACE:
1320                 ret = do_replace(user, len);
1321                 break;
1322
1323         case IP6T_SO_SET_ADD_COUNTERS:
1324                 ret = do_add_counters(user, len);
1325                 break;
1326
1327         default:
1328                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1329                 ret = -EINVAL;
1330         }
1331
1332         return ret;
1333 }
1334
1335 static int
1336 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1337 {
1338         int ret;
1339
1340         if (!capable(CAP_NET_ADMIN))
1341                 return -EPERM;
1342
1343         switch (cmd) {
1344         case IP6T_SO_GET_INFO: {
1345                 char name[IP6T_TABLE_MAXNAMELEN];
1346                 struct ip6t_table *t;
1347
1348                 if (*len != sizeof(struct ip6t_getinfo)) {
1349                         duprintf("length %u != %u\n", *len,
1350                                  sizeof(struct ip6t_getinfo));
1351                         ret = -EINVAL;
1352                         break;
1353                 }
1354
1355                 if (copy_from_user(name, user, sizeof(name)) != 0) {
1356                         ret = -EFAULT;
1357                         break;
1358                 }
1359                 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1360                 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1361                 if (t) {
1362                         struct ip6t_getinfo info;
1363
1364                         info.valid_hooks = t->valid_hooks;
1365                         memcpy(info.hook_entry, t->private->hook_entry,
1366                                sizeof(info.hook_entry));
1367                         memcpy(info.underflow, t->private->underflow,
1368                                sizeof(info.underflow));
1369                         info.num_entries = t->private->number;
1370                         info.size = t->private->size;
1371                         memcpy(info.name, name, sizeof(info.name));
1372
1373                         if (copy_to_user(user, &info, *len) != 0)
1374                                 ret = -EFAULT;
1375                         else
1376                                 ret = 0;
1377
1378                         up(&ip6t_mutex);
1379                 }
1380         }
1381         break;
1382
1383         case IP6T_SO_GET_ENTRIES: {
1384                 struct ip6t_get_entries get;
1385
1386                 if (*len < sizeof(get)) {
1387                         duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1388                         ret = -EINVAL;
1389                 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1390                         ret = -EFAULT;
1391                 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1392                         duprintf("get_entries: %u != %u\n", *len,
1393                                  sizeof(struct ip6t_get_entries) + get.size);
1394                         ret = -EINVAL;
1395                 } else
1396                         ret = get_entries(&get, user);
1397                 break;
1398         }
1399
1400         default:
1401                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1402                 ret = -EINVAL;
1403         }
1404
1405         return ret;
1406 }
1407
1408 /* Registration hooks for targets. */
1409 int
1410 ip6t_register_target(struct ip6t_target *target)
1411 {
1412         int ret;
1413
1414         ret = down_interruptible(&ip6t_mutex);
1415         if (ret != 0)
1416                 return ret;
1417
1418         if (!list_named_insert(&ip6t_target, target)) {
1419                 duprintf("ip6t_register_target: `%s' already in list!\n",
1420                          target->name);
1421                 ret = -EINVAL;
1422         }
1423         up(&ip6t_mutex);
1424         return ret;
1425 }
1426
1427 void
1428 ip6t_unregister_target(struct ip6t_target *target)
1429 {
1430         down(&ip6t_mutex);
1431         LIST_DELETE(&ip6t_target, target);
1432         up(&ip6t_mutex);
1433 }
1434
1435 int
1436 ip6t_register_match(struct ip6t_match *match)
1437 {
1438         int ret;
1439
1440         ret = down_interruptible(&ip6t_mutex);
1441         if (ret != 0)
1442                 return ret;
1443
1444         if (!list_named_insert(&ip6t_match, match)) {
1445                 duprintf("ip6t_register_match: `%s' already in list!\n",
1446                          match->name);
1447                 ret = -EINVAL;
1448         }
1449         up(&ip6t_mutex);
1450
1451         return ret;
1452 }
1453
1454 void
1455 ip6t_unregister_match(struct ip6t_match *match)
1456 {
1457         down(&ip6t_mutex);
1458         LIST_DELETE(&ip6t_match, match);
1459         up(&ip6t_mutex);
1460 }
1461
1462 int ip6t_register_table(struct ip6t_table *table,
1463                         const struct ip6t_replace *repl)
1464 {
1465         int ret;
1466         struct ip6t_table_info *newinfo;
1467         static struct ip6t_table_info bootstrap
1468                 = { 0, 0, 0, { 0 }, { 0 }, { } };
1469
1470         newinfo = vmalloc(sizeof(struct ip6t_table_info)
1471                           + SMP_ALIGN(repl->size) * num_possible_cpus());
1472         if (!newinfo)
1473                 return -ENOMEM;
1474
1475         memcpy(newinfo->entries, repl->entries, repl->size);
1476
1477         ret = translate_table(table->name, table->valid_hooks,
1478                               newinfo, repl->size,
1479                               repl->num_entries,
1480                               repl->hook_entry,
1481                               repl->underflow);
1482         if (ret != 0) {
1483                 vfree(newinfo);
1484                 return ret;
1485         }
1486
1487         ret = down_interruptible(&ip6t_mutex);
1488         if (ret != 0) {
1489                 vfree(newinfo);
1490                 return ret;
1491         }
1492
1493         /* Don't autoload: we'd eat our tail... */
1494         if (list_named_find(&ip6t_tables, table->name)) {
1495                 ret = -EEXIST;
1496                 goto free_unlock;
1497         }
1498
1499         /* Simplifies replace_table code. */
1500         table->private = &bootstrap;
1501         if (!replace_table(table, 0, newinfo, &ret))
1502                 goto free_unlock;
1503
1504         duprintf("table->private->number = %u\n",
1505                  table->private->number);
1506
1507         /* save number of initial entries */
1508         table->private->initial_entries = table->private->number;
1509
1510         rwlock_init(&table->lock);
1511         list_prepend(&ip6t_tables, table);
1512
1513  unlock:
1514         up(&ip6t_mutex);
1515         return ret;
1516
1517  free_unlock:
1518         vfree(newinfo);
1519         goto unlock;
1520 }
1521
1522 void ip6t_unregister_table(struct ip6t_table *table)
1523 {
1524         down(&ip6t_mutex);
1525         LIST_DELETE(&ip6t_tables, table);
1526         up(&ip6t_mutex);
1527
1528         /* Decrease module usage counts and free resources */
1529         IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1530                           cleanup_entry, NULL);
1531         vfree(table->private);
1532 }
1533
1534 /* Returns 1 if the port is matched by the range, 0 otherwise */
1535 static inline int
1536 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1537 {
1538         int ret;
1539
1540         ret = (port >= min && port <= max) ^ invert;
1541         return ret;
1542 }
1543
1544 static int
1545 tcp_find_option(u_int8_t option,
1546                 const struct sk_buff *skb,
1547                 unsigned int tcpoff,
1548                 unsigned int optlen,
1549                 int invert,
1550                 int *hotdrop)
1551 {
1552         /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1553         u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1554         unsigned int i;
1555
1556         duprintf("tcp_match: finding option\n");
1557         if (!optlen)
1558                 return invert;
1559         /* If we don't have the whole header, drop packet. */
1560         op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1561                                 _opt);
1562         if (op == NULL) {
1563                 *hotdrop = 1;
1564                 return 0;
1565         }
1566
1567         for (i = 0; i < optlen; ) {
1568                 if (op[i] == option) return !invert;
1569                 if (op[i] < 2) i++;
1570                 else i += op[i+1]?:1;
1571         }
1572
1573         return invert;
1574 }
1575
1576 static int
1577 tcp_match(const struct sk_buff *skb,
1578           const struct net_device *in,
1579           const struct net_device *out,
1580           const void *matchinfo,
1581           int offset,
1582           unsigned int protoff,
1583           int *hotdrop)
1584 {
1585         struct tcphdr _tcph, *th;
1586         const struct ip6t_tcp *tcpinfo = matchinfo;
1587
1588         if (offset) {
1589                 /* To quote Alan:
1590
1591                    Don't allow a fragment of TCP 8 bytes in. Nobody normal
1592                    causes this. Its a cracker trying to break in by doing a
1593                    flag overwrite to pass the direction checks.
1594                 */
1595                 if (offset == 1) {
1596                         duprintf("Dropping evil TCP offset=1 frag.\n");
1597                         *hotdrop = 1;
1598                 }
1599                 /* Must not be a fragment. */
1600                 return 0;
1601         }
1602
1603 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1604
1605         th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1606         if (th == NULL) {
1607                 /* We've been asked to examine this packet, and we
1608                    can't.  Hence, no choice but to drop. */
1609                 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1610                 *hotdrop = 1;
1611                 return 0;
1612         }
1613
1614         if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1615                         ntohs(th->source),
1616                         !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1617                 return 0;
1618         if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1619                         ntohs(th->dest),
1620                         !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1621                 return 0;
1622         if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1623                       == tcpinfo->flg_cmp,
1624                       IP6T_TCP_INV_FLAGS))
1625                 return 0;
1626         if (tcpinfo->option) {
1627                 if (th->doff * 4 < sizeof(_tcph)) {
1628                         *hotdrop = 1;
1629                         return 0;
1630                 }
1631                 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1632                                      th->doff*4 - sizeof(*th),
1633                                      tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1634                                      hotdrop))
1635                         return 0;
1636         }
1637         return 1;
1638 }
1639
1640 /* Called when user tries to insert an entry of this type. */
1641 static int
1642 tcp_checkentry(const char *tablename,
1643                const struct ip6t_ip6 *ipv6,
1644                void *matchinfo,
1645                unsigned int matchsize,
1646                unsigned int hook_mask)
1647 {
1648         const struct ip6t_tcp *tcpinfo = matchinfo;
1649
1650         /* Must specify proto == TCP, and no unknown invflags */
1651         return ipv6->proto == IPPROTO_TCP
1652                 && !(ipv6->invflags & IP6T_INV_PROTO)
1653                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1654                 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1655 }
1656
1657 static int
1658 udp_match(const struct sk_buff *skb,
1659           const struct net_device *in,
1660           const struct net_device *out,
1661           const void *matchinfo,
1662           int offset,
1663           unsigned int protoff,
1664           int *hotdrop)
1665 {
1666         struct udphdr _udph, *uh;
1667         const struct ip6t_udp *udpinfo = matchinfo;
1668
1669         /* Must not be a fragment. */
1670         if (offset)
1671                 return 0;
1672
1673         uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1674         if (uh == NULL) {
1675                 /* We've been asked to examine this packet, and we
1676                    can't.  Hence, no choice but to drop. */
1677                 duprintf("Dropping evil UDP tinygram.\n");
1678                 *hotdrop = 1;
1679                 return 0;
1680         }
1681
1682         return port_match(udpinfo->spts[0], udpinfo->spts[1],
1683                           ntohs(uh->source),
1684                           !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1685                 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1686                               ntohs(uh->dest),
1687                               !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1688 }
1689
1690 /* Called when user tries to insert an entry of this type. */
1691 static int
1692 udp_checkentry(const char *tablename,
1693                const struct ip6t_ip6 *ipv6,
1694                void *matchinfo,
1695                unsigned int matchinfosize,
1696                unsigned int hook_mask)
1697 {
1698         const struct ip6t_udp *udpinfo = matchinfo;
1699
1700         /* Must specify proto == UDP, and no unknown invflags */
1701         if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1702                 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1703                          IPPROTO_UDP);
1704                 return 0;
1705         }
1706         if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1707                 duprintf("ip6t_udp: matchsize %u != %u\n",
1708                          matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1709                 return 0;
1710         }
1711         if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1712                 duprintf("ip6t_udp: unknown flags %X\n",
1713                          udpinfo->invflags);
1714                 return 0;
1715         }
1716
1717         return 1;
1718 }
1719
1720 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1721 static inline int
1722 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1723                      u_int8_t type, u_int8_t code,
1724                      int invert)
1725 {
1726         return (type == test_type && code >= min_code && code <= max_code)
1727                 ^ invert;
1728 }
1729
1730 static int
1731 icmp6_match(const struct sk_buff *skb,
1732            const struct net_device *in,
1733            const struct net_device *out,
1734            const void *matchinfo,
1735            int offset,
1736            unsigned int protoff,
1737            int *hotdrop)
1738 {
1739         struct icmp6hdr _icmp, *ic;
1740         const struct ip6t_icmp *icmpinfo = matchinfo;
1741
1742         /* Must not be a fragment. */
1743         if (offset)
1744                 return 0;
1745
1746         ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1747         if (ic == NULL) {
1748                 /* We've been asked to examine this packet, and we
1749                    can't.  Hence, no choice but to drop. */
1750                 duprintf("Dropping evil ICMP tinygram.\n");
1751                 *hotdrop = 1;
1752                 return 0;
1753         }
1754
1755         return icmp6_type_code_match(icmpinfo->type,
1756                                      icmpinfo->code[0],
1757                                      icmpinfo->code[1],
1758                                      ic->icmp6_type, ic->icmp6_code,
1759                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
1760 }
1761
1762 /* Called when user tries to insert an entry of this type. */
1763 static int
1764 icmp6_checkentry(const char *tablename,
1765            const struct ip6t_ip6 *ipv6,
1766            void *matchinfo,
1767            unsigned int matchsize,
1768            unsigned int hook_mask)
1769 {
1770         const struct ip6t_icmp *icmpinfo = matchinfo;
1771
1772         /* Must specify proto == ICMP, and no unknown invflags */
1773         return ipv6->proto == IPPROTO_ICMPV6
1774                 && !(ipv6->invflags & IP6T_INV_PROTO)
1775                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1776                 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1777 }
1778
1779 /* The built-in targets: standard (NULL) and error. */
1780 static struct ip6t_target ip6t_standard_target = {
1781         .name           = IP6T_STANDARD_TARGET,
1782 };
1783
1784 static struct ip6t_target ip6t_error_target = {
1785         .name           = IP6T_ERROR_TARGET,
1786         .target         = ip6t_error,
1787 };
1788
1789 static struct nf_sockopt_ops ip6t_sockopts = {
1790         .pf             = PF_INET6,
1791         .set_optmin     = IP6T_BASE_CTL,
1792         .set_optmax     = IP6T_SO_SET_MAX+1,
1793         .set            = do_ip6t_set_ctl,
1794         .get_optmin     = IP6T_BASE_CTL,
1795         .get_optmax     = IP6T_SO_GET_MAX+1,
1796         .get            = do_ip6t_get_ctl,
1797 };
1798
1799 static struct ip6t_match tcp_matchstruct = {
1800         .name           = "tcp",
1801         .match          = &tcp_match,
1802         .checkentry     = &tcp_checkentry,
1803 };
1804
1805 static struct ip6t_match udp_matchstruct = {
1806         .name           = "udp",
1807         .match          = &udp_match,
1808         .checkentry     = &udp_checkentry,
1809 };
1810
1811 static struct ip6t_match icmp6_matchstruct = {
1812         .name           = "icmp6",
1813         .match          = &icmp6_match,
1814         .checkentry     = &icmp6_checkentry,
1815 };
1816
1817 #ifdef CONFIG_PROC_FS
1818 static inline int print_name(const char *i,
1819                              off_t start_offset, char *buffer, int length,
1820                              off_t *pos, unsigned int *count)
1821 {
1822         if ((*count)++ >= start_offset) {
1823                 unsigned int namelen;
1824
1825                 namelen = sprintf(buffer + *pos, "%s\n",
1826                                   i + sizeof(struct list_head));
1827                 if (*pos + namelen > length) {
1828                         /* Stop iterating */
1829                         return 1;
1830                 }
1831                 *pos += namelen;
1832         }
1833         return 0;
1834 }
1835
1836 static inline int print_target(const struct ip6t_target *t,
1837                                off_t start_offset, char *buffer, int length,
1838                                off_t *pos, unsigned int *count)
1839 {
1840         if (t == &ip6t_standard_target || t == &ip6t_error_target)
1841                 return 0;
1842         return print_name((char *)t, start_offset, buffer, length, pos, count);
1843 }
1844
1845 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1846 {
1847         off_t pos = 0;
1848         unsigned int count = 0;
1849
1850         if (down_interruptible(&ip6t_mutex) != 0)
1851                 return 0;
1852
1853         LIST_FIND(&ip6t_tables, print_name, char *,
1854                   offset, buffer, length, &pos, &count);
1855
1856         up(&ip6t_mutex);
1857
1858         /* `start' hack - see fs/proc/generic.c line ~105 */
1859         *start=(char *)((unsigned long)count-offset);
1860         return pos;
1861 }
1862
1863 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1864 {
1865         off_t pos = 0;
1866         unsigned int count = 0;
1867
1868         if (down_interruptible(&ip6t_mutex) != 0)
1869                 return 0;
1870
1871         LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1872                   offset, buffer, length, &pos, &count);
1873
1874         up(&ip6t_mutex);
1875
1876         *start = (char *)((unsigned long)count - offset);
1877         return pos;
1878 }
1879
1880 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1881 {
1882         off_t pos = 0;
1883         unsigned int count = 0;
1884
1885         if (down_interruptible(&ip6t_mutex) != 0)
1886                 return 0;
1887
1888         LIST_FIND(&ip6t_match, print_name, char *,
1889                   offset, buffer, length, &pos, &count);
1890
1891         up(&ip6t_mutex);
1892
1893         *start = (char *)((unsigned long)count - offset);
1894         return pos;
1895 }
1896
1897 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1898 { { "ip6_tables_names", ip6t_get_tables },
1899   { "ip6_tables_targets", ip6t_get_targets },
1900   { "ip6_tables_matches", ip6t_get_matches },
1901   { NULL, NULL} };
1902 #endif /*CONFIG_PROC_FS*/
1903
1904 static int __init init(void)
1905 {
1906         int ret;
1907
1908         /* Noone else will be downing sem now, so we won't sleep */
1909         down(&ip6t_mutex);
1910         list_append(&ip6t_target, &ip6t_standard_target);
1911         list_append(&ip6t_target, &ip6t_error_target);
1912         list_append(&ip6t_match, &tcp_matchstruct);
1913         list_append(&ip6t_match, &udp_matchstruct);
1914         list_append(&ip6t_match, &icmp6_matchstruct);
1915         up(&ip6t_mutex);
1916
1917         /* Register setsockopt */
1918         ret = nf_register_sockopt(&ip6t_sockopts);
1919         if (ret < 0) {
1920                 duprintf("Unable to register sockopts.\n");
1921                 return ret;
1922         }
1923
1924 #ifdef CONFIG_PROC_FS
1925         {
1926                 struct proc_dir_entry *proc;
1927                 int i;
1928
1929                 for (i = 0; ip6t_proc_entry[i].name; i++) {
1930                         proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1931                                                ip6t_proc_entry[i].get_info);
1932                         if (!proc) {
1933                                 while (--i >= 0)
1934                                        proc_net_remove(ip6t_proc_entry[i].name);
1935                                 nf_unregister_sockopt(&ip6t_sockopts);
1936                                 return -ENOMEM;
1937                         }
1938                         proc->owner = THIS_MODULE;
1939                 }
1940         }
1941 #endif
1942
1943         printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1944         return 0;
1945 }
1946
1947 static void __exit fini(void)
1948 {
1949         nf_unregister_sockopt(&ip6t_sockopts);
1950 #ifdef CONFIG_PROC_FS
1951         {
1952                 int i;
1953                 for (i = 0; ip6t_proc_entry[i].name; i++)
1954                         proc_net_remove(ip6t_proc_entry[i].name);
1955         }
1956 #endif
1957 }
1958
1959 EXPORT_SYMBOL(ip6t_register_table);
1960 EXPORT_SYMBOL(ip6t_unregister_table);
1961 EXPORT_SYMBOL(ip6t_do_table);
1962 EXPORT_SYMBOL(ip6t_register_match);
1963 EXPORT_SYMBOL(ip6t_unregister_match);
1964 EXPORT_SYMBOL(ip6t_register_target);
1965 EXPORT_SYMBOL(ip6t_unregister_target);
1966 EXPORT_SYMBOL(ip6t_ext_hdr);
1967
1968 module_init(init);
1969 module_exit(fini);