Update from upstream with manual merge of Yasunori Goto's
[linux-drm-fsl-dcu.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 #include <linux/cpumask.h>
32
33 #include <linux/netfilter_ipv6/ip6_tables.h>
34
35 MODULE_LICENSE("GPL");
36 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
37 MODULE_DESCRIPTION("IPv6 packet filter");
38
39 #define IPV6_HDR_LEN    (sizeof(struct ipv6hdr))
40 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
41
42 /*#define DEBUG_IP_FIREWALL*/
43 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
44 /*#define DEBUG_IP_FIREWALL_USER*/
45
46 #ifdef DEBUG_IP_FIREWALL
47 #define dprintf(format, args...)  printk(format , ## args)
48 #else
49 #define dprintf(format, args...)
50 #endif
51
52 #ifdef DEBUG_IP_FIREWALL_USER
53 #define duprintf(format, args...) printk(format , ## args)
54 #else
55 #define duprintf(format, args...)
56 #endif
57
58 #ifdef CONFIG_NETFILTER_DEBUG
59 #define IP_NF_ASSERT(x)                                         \
60 do {                                                            \
61         if (!(x))                                               \
62                 printk("IP_NF_ASSERT: %s:%s:%u\n",              \
63                        __FUNCTION__, __FILE__, __LINE__);       \
64 } while(0)
65 #else
66 #define IP_NF_ASSERT(x)
67 #endif
68 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
69
70 static DECLARE_MUTEX(ip6t_mutex);
71
72 /* Must have mutex */
73 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
75 #include <linux/netfilter_ipv4/listhelp.h>
76
77 #if 0
78 /* All the better to debug you with... */
79 #define static
80 #define inline
81 #endif
82
83 /* Locking is simple: we assume at worst case there will be one packet
84    in user context and one from bottom halves (or soft irq if Alexey's
85    softnet patch was applied).
86
87    We keep a set of rules for each CPU, so we can avoid write-locking
88    them; doing a readlock_bh() stops packets coming through if we're
89    in user context.
90
91    To be cache friendly on SMP, we arrange them like so:
92    [ n-entries ]
93    ... cache-align padding ...
94    [ n-entries ]
95
96    Hence the start of any table is given by get_table() below.  */
97
98 /* The table itself */
99 struct ip6t_table_info
100 {
101         /* Size per table */
102         unsigned int size;
103         /* Number of entries: FIXME. --RR */
104         unsigned int number;
105         /* Initial number of entries. Needed for module usage count */
106         unsigned int initial_entries;
107
108         /* Entry points and underflows */
109         unsigned int hook_entry[NF_IP6_NUMHOOKS];
110         unsigned int underflow[NF_IP6_NUMHOOKS];
111
112         /* ip6t_entry tables: one per CPU */
113         char entries[0] ____cacheline_aligned;
114 };
115
116 static LIST_HEAD(ip6t_target);
117 static LIST_HEAD(ip6t_match);
118 static LIST_HEAD(ip6t_tables);
119 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
120
121 #ifdef CONFIG_SMP
122 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
123 #else
124 #define TABLE_OFFSET(t,p) 0
125 #endif
126
127 #if 0
128 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
129 #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; })
130 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
131 #endif
132
133 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
134                               struct in6_addr addr2)
135 {
136         int i;
137         for( i = 0; i < 16; i++){
138                 if((addr1.s6_addr[i] & mask.s6_addr[i]) != 
139                    (addr2.s6_addr[i] & mask.s6_addr[i]))
140                         return 1;
141         }
142         return 0;
143 }
144
145 /* Check for an extension */
146 int 
147 ip6t_ext_hdr(u8 nexthdr)
148 {
149         return ( (nexthdr == IPPROTO_HOPOPTS)   ||
150                  (nexthdr == IPPROTO_ROUTING)   ||
151                  (nexthdr == IPPROTO_FRAGMENT)  ||
152                  (nexthdr == IPPROTO_ESP)       ||
153                  (nexthdr == IPPROTO_AH)        ||
154                  (nexthdr == IPPROTO_NONE)      ||
155                  (nexthdr == IPPROTO_DSTOPTS) );
156 }
157
158 /* Returns whether matches rule or not. */
159 static inline int
160 ip6_packet_match(const struct sk_buff *skb,
161                  const char *indev,
162                  const char *outdev,
163                  const struct ip6t_ip6 *ip6info,
164                  unsigned int *protoff,
165                  int *fragoff)
166 {
167         size_t i;
168         unsigned long ret;
169         const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
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 _hdr, *hp;
221                 u_int16_t ptr;          /* Header offset in skb */
222                 u_int16_t hdrlen;       /* Header */
223                 u_int16_t _fragoff = 0, *fp = NULL;
224
225                 ptr = IPV6_HDR_LEN;
226
227                 while (ip6t_ext_hdr(currenthdr)) {
228                         /* Is there enough space for the next ext header? */
229                         if (skb->len - ptr < IPV6_OPTHDR_LEN)
230                                 return 0;
231
232                         /* NONE or ESP: there isn't protocol part */
233                         /* If we want to count these packets in '-p all',
234                          * we will change the return 0 to 1*/
235                         if ((currenthdr == IPPROTO_NONE) || 
236                                 (currenthdr == IPPROTO_ESP))
237                                 break;
238
239                         hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
240                         BUG_ON(hp == NULL);
241
242                         /* Size calculation */
243                         if (currenthdr == IPPROTO_FRAGMENT) {
244                                 fp = skb_header_pointer(skb,
245                                                    ptr+offsetof(struct frag_hdr,
246                                                                 frag_off),
247                                                    sizeof(_fragoff),
248                                                    &_fragoff);
249                                 if (fp == NULL)
250                                         return 0;
251
252                                 _fragoff = ntohs(*fp) & ~0x7;
253                                 hdrlen = 8;
254                         } else if (currenthdr == IPPROTO_AH)
255                                 hdrlen = (hp->hdrlen+2)<<2;
256                         else
257                                 hdrlen = ipv6_optlen(hp);
258
259                         currenthdr = hp->nexthdr;
260                         ptr += hdrlen;
261                         /* ptr is too large */
262                         if ( ptr > skb->len ) 
263                                 return 0;
264                         if (_fragoff) {
265                                 if (ip6t_ext_hdr(currenthdr))
266                                         return 0;
267                                 break;
268                         }
269                 }
270
271                 *protoff = ptr;
272                 *fragoff = _fragoff;
273
274                 /* currenthdr contains the protocol header */
275
276                 dprintf("Packet protocol %hi ?= %s%hi.\n",
277                                 currenthdr, 
278                                 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
279                                 ip6info->proto);
280
281                 if (ip6info->proto == currenthdr) {
282                         if(ip6info->invflags & IP6T_INV_PROTO) {
283                                 return 0;
284                         }
285                         return 1;
286                 }
287
288                 /* We need match for the '-p all', too! */
289                 if ((ip6info->proto != 0) &&
290                         !(ip6info->invflags & IP6T_INV_PROTO))
291                         return 0;
292         }
293         return 1;
294 }
295
296 /* should be ip6 safe */
297 static inline int 
298 ip6_checkentry(const struct ip6t_ip6 *ipv6)
299 {
300         if (ipv6->flags & ~IP6T_F_MASK) {
301                 duprintf("Unknown flag bits set: %08X\n",
302                          ipv6->flags & ~IP6T_F_MASK);
303                 return 0;
304         }
305         if (ipv6->invflags & ~IP6T_INV_MASK) {
306                 duprintf("Unknown invflag bits set: %08X\n",
307                          ipv6->invflags & ~IP6T_INV_MASK);
308                 return 0;
309         }
310         return 1;
311 }
312
313 static unsigned int
314 ip6t_error(struct sk_buff **pskb,
315           const struct net_device *in,
316           const struct net_device *out,
317           unsigned int hooknum,
318           const void *targinfo,
319           void *userinfo)
320 {
321         if (net_ratelimit())
322                 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
323
324         return NF_DROP;
325 }
326
327 static inline
328 int do_match(struct ip6t_entry_match *m,
329              const struct sk_buff *skb,
330              const struct net_device *in,
331              const struct net_device *out,
332              int offset,
333              unsigned int protoff,
334              int *hotdrop)
335 {
336         /* Stop iteration if it doesn't match */
337         if (!m->u.kernel.match->match(skb, in, out, m->data,
338                                       offset, protoff, hotdrop))
339                 return 1;
340         else
341                 return 0;
342 }
343
344 static inline struct ip6t_entry *
345 get_entry(void *base, unsigned int offset)
346 {
347         return (struct ip6t_entry *)(base + offset);
348 }
349
350 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
351 unsigned int
352 ip6t_do_table(struct sk_buff **pskb,
353               unsigned int hook,
354               const struct net_device *in,
355               const struct net_device *out,
356               struct ip6t_table *table,
357               void *userdata)
358 {
359         static const char nulldevname[IFNAMSIZ];
360         int offset = 0;
361         unsigned int protoff = 0;
362         int hotdrop = 0;
363         /* Initializing verdict to NF_DROP keeps gcc happy. */
364         unsigned int verdict = NF_DROP;
365         const char *indev, *outdev;
366         void *table_base;
367         struct ip6t_entry *e, *back;
368
369         /* Initialization */
370         indev = in ? in->name : nulldevname;
371         outdev = out ? out->name : nulldevname;
372
373         /* We handle fragments by dealing with the first fragment as
374          * if it was a normal packet.  All other fragments are treated
375          * normally, except that they will NEVER match rules that ask
376          * things we don't know, ie. tcp syn flag or ports).  If the
377          * rule is also a fragment-specific rule, non-fragments won't
378          * match it. */
379
380         read_lock_bh(&table->lock);
381         IP_NF_ASSERT(table->valid_hooks & (1 << hook));
382         table_base = (void *)table->private->entries
383                 + TABLE_OFFSET(table->private, smp_processor_id());
384         e = get_entry(table_base, table->private->hook_entry[hook]);
385
386 #ifdef CONFIG_NETFILTER_DEBUG
387         /* Check noone else using our table */
388         if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
389             && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
390                 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
391                        smp_processor_id(),
392                        table->name,
393                        &((struct ip6t_entry *)table_base)->comefrom,
394                        ((struct ip6t_entry *)table_base)->comefrom);
395         }
396         ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
397 #endif
398
399         /* For return from builtin chain */
400         back = get_entry(table_base, table->private->underflow[hook]);
401
402         do {
403                 IP_NF_ASSERT(e);
404                 IP_NF_ASSERT(back);
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 != (void *)e + e->next_offset
438                                     && !(e->ipv6.flags & IP6T_F_GOTO)) {
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_each_cpu(i) {
955                 if (i == 0)
956                         continue;
957                 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i,
958                        newinfo->entries,
959                        SMP_ALIGN(newinfo->size));
960         }
961
962         return ret;
963 }
964
965 static struct ip6t_table_info *
966 replace_table(struct ip6t_table *table,
967               unsigned int num_counters,
968               struct ip6t_table_info *newinfo,
969               int *error)
970 {
971         struct ip6t_table_info *oldinfo;
972
973 #ifdef CONFIG_NETFILTER_DEBUG
974         {
975                 struct ip6t_entry *table_base;
976                 unsigned int i;
977
978                 for_each_cpu(i) {
979                         table_base =
980                                 (void *)newinfo->entries
981                                 + TABLE_OFFSET(newinfo, i);
982
983                         table_base->comefrom = 0xdead57ac;
984                 }
985         }
986 #endif
987
988         /* Do the substitution. */
989         write_lock_bh(&table->lock);
990         /* Check inside lock: is the old number correct? */
991         if (num_counters != table->private->number) {
992                 duprintf("num_counters != table->private->number (%u/%u)\n",
993                          num_counters, table->private->number);
994                 write_unlock_bh(&table->lock);
995                 *error = -EAGAIN;
996                 return NULL;
997         }
998         oldinfo = table->private;
999         table->private = newinfo;
1000         newinfo->initial_entries = oldinfo->initial_entries;
1001         write_unlock_bh(&table->lock);
1002
1003         return oldinfo;
1004 }
1005
1006 /* Gets counters. */
1007 static inline int
1008 add_entry_to_counter(const struct ip6t_entry *e,
1009                      struct ip6t_counters total[],
1010                      unsigned int *i)
1011 {
1012         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1013
1014         (*i)++;
1015         return 0;
1016 }
1017
1018 static void
1019 get_counters(const struct ip6t_table_info *t,
1020              struct ip6t_counters counters[])
1021 {
1022         unsigned int cpu;
1023         unsigned int i;
1024
1025         for_each_cpu(cpu) {
1026                 i = 0;
1027                 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1028                                   t->size,
1029                                   add_entry_to_counter,
1030                                   counters,
1031                                   &i);
1032         }
1033 }
1034
1035 static int
1036 copy_entries_to_user(unsigned int total_size,
1037                      struct ip6t_table *table,
1038                      void __user *userptr)
1039 {
1040         unsigned int off, num, countersize;
1041         struct ip6t_entry *e;
1042         struct ip6t_counters *counters;
1043         int ret = 0;
1044
1045         /* We need atomic snapshot of counters: rest doesn't change
1046            (other than comefrom, which userspace doesn't care
1047            about). */
1048         countersize = sizeof(struct ip6t_counters) * table->private->number;
1049         counters = vmalloc(countersize);
1050
1051         if (counters == NULL)
1052                 return -ENOMEM;
1053
1054         /* First, sum counters... */
1055         memset(counters, 0, countersize);
1056         write_lock_bh(&table->lock);
1057         get_counters(table->private, counters);
1058         write_unlock_bh(&table->lock);
1059
1060         /* ... then copy entire thing from CPU 0... */
1061         if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1062                 ret = -EFAULT;
1063                 goto free_counters;
1064         }
1065
1066         /* FIXME: use iterator macros --RR */
1067         /* ... then go back and fix counters and names */
1068         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1069                 unsigned int i;
1070                 struct ip6t_entry_match *m;
1071                 struct ip6t_entry_target *t;
1072
1073                 e = (struct ip6t_entry *)(table->private->entries + off);
1074                 if (copy_to_user(userptr + off
1075                                  + offsetof(struct ip6t_entry, counters),
1076                                  &counters[num],
1077                                  sizeof(counters[num])) != 0) {
1078                         ret = -EFAULT;
1079                         goto free_counters;
1080                 }
1081
1082                 for (i = sizeof(struct ip6t_entry);
1083                      i < e->target_offset;
1084                      i += m->u.match_size) {
1085                         m = (void *)e + i;
1086
1087                         if (copy_to_user(userptr + off + i
1088                                          + offsetof(struct ip6t_entry_match,
1089                                                     u.user.name),
1090                                          m->u.kernel.match->name,
1091                                          strlen(m->u.kernel.match->name)+1)
1092                             != 0) {
1093                                 ret = -EFAULT;
1094                                 goto free_counters;
1095                         }
1096                 }
1097
1098                 t = ip6t_get_target(e);
1099                 if (copy_to_user(userptr + off + e->target_offset
1100                                  + offsetof(struct ip6t_entry_target,
1101                                             u.user.name),
1102                                  t->u.kernel.target->name,
1103                                  strlen(t->u.kernel.target->name)+1) != 0) {
1104                         ret = -EFAULT;
1105                         goto free_counters;
1106                 }
1107         }
1108
1109  free_counters:
1110         vfree(counters);
1111         return ret;
1112 }
1113
1114 static int
1115 get_entries(const struct ip6t_get_entries *entries,
1116             struct ip6t_get_entries __user *uptr)
1117 {
1118         int ret;
1119         struct ip6t_table *t;
1120
1121         t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1122         if (t) {
1123                 duprintf("t->private->number = %u\n",
1124                          t->private->number);
1125                 if (entries->size == t->private->size)
1126                         ret = copy_entries_to_user(t->private->size,
1127                                                    t, uptr->entrytable);
1128                 else {
1129                         duprintf("get_entries: I've got %u not %u!\n",
1130                                  t->private->size,
1131                                  entries->size);
1132                         ret = -EINVAL;
1133                 }
1134                 up(&ip6t_mutex);
1135         } else
1136                 duprintf("get_entries: Can't find %s!\n",
1137                          entries->name);
1138
1139         return ret;
1140 }
1141
1142 static int
1143 do_replace(void __user *user, unsigned int len)
1144 {
1145         int ret;
1146         struct ip6t_replace tmp;
1147         struct ip6t_table *t;
1148         struct ip6t_table_info *newinfo, *oldinfo;
1149         struct ip6t_counters *counters;
1150
1151         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1152                 return -EFAULT;
1153
1154         /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1155         if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1156                 return -ENOMEM;
1157
1158         newinfo = vmalloc(sizeof(struct ip6t_table_info)
1159                           + SMP_ALIGN(tmp.size) *
1160                                         (highest_possible_processor_id()+1));
1161         if (!newinfo)
1162                 return -ENOMEM;
1163
1164         if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1165                            tmp.size) != 0) {
1166                 ret = -EFAULT;
1167                 goto free_newinfo;
1168         }
1169
1170         counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1171         if (!counters) {
1172                 ret = -ENOMEM;
1173                 goto free_newinfo;
1174         }
1175         memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1176
1177         ret = translate_table(tmp.name, tmp.valid_hooks,
1178                               newinfo, tmp.size, tmp.num_entries,
1179                               tmp.hook_entry, tmp.underflow);
1180         if (ret != 0)
1181                 goto free_newinfo_counters;
1182
1183         duprintf("ip_tables: Translated table\n");
1184
1185         t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1186         if (!t)
1187                 goto free_newinfo_counters_untrans;
1188
1189         /* You lied! */
1190         if (tmp.valid_hooks != t->valid_hooks) {
1191                 duprintf("Valid hook crap: %08X vs %08X\n",
1192                          tmp.valid_hooks, t->valid_hooks);
1193                 ret = -EINVAL;
1194                 goto free_newinfo_counters_untrans_unlock;
1195         }
1196
1197         /* Get a reference in advance, we're not allowed fail later */
1198         if (!try_module_get(t->me)) {
1199                 ret = -EBUSY;
1200                 goto free_newinfo_counters_untrans_unlock;
1201         }
1202
1203         oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1204         if (!oldinfo)
1205                 goto put_module;
1206
1207         /* Update module usage count based on number of rules */
1208         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1209                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1210         if ((oldinfo->number > oldinfo->initial_entries) || 
1211             (newinfo->number <= oldinfo->initial_entries)) 
1212                 module_put(t->me);
1213         if ((oldinfo->number > oldinfo->initial_entries) &&
1214             (newinfo->number <= oldinfo->initial_entries))
1215                 module_put(t->me);
1216
1217         /* Get the old counters. */
1218         get_counters(oldinfo, counters);
1219         /* Decrease module usage counts and free resource */
1220         IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1221         vfree(oldinfo);
1222         /* Silent error: too late now. */
1223         if (copy_to_user(tmp.counters, counters,
1224                          sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1225                 ret = -EFAULT;
1226         vfree(counters);
1227         up(&ip6t_mutex);
1228         return ret;
1229
1230  put_module:
1231         module_put(t->me);
1232  free_newinfo_counters_untrans_unlock:
1233         up(&ip6t_mutex);
1234  free_newinfo_counters_untrans:
1235         IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1236  free_newinfo_counters:
1237         vfree(counters);
1238  free_newinfo:
1239         vfree(newinfo);
1240         return ret;
1241 }
1242
1243 /* We're lazy, and add to the first CPU; overflow works its fey magic
1244  * and everything is OK. */
1245 static inline int
1246 add_counter_to_entry(struct ip6t_entry *e,
1247                      const struct ip6t_counters addme[],
1248                      unsigned int *i)
1249 {
1250 #if 0
1251         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1252                  *i,
1253                  (long unsigned int)e->counters.pcnt,
1254                  (long unsigned int)e->counters.bcnt,
1255                  (long unsigned int)addme[*i].pcnt,
1256                  (long unsigned int)addme[*i].bcnt);
1257 #endif
1258
1259         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1260
1261         (*i)++;
1262         return 0;
1263 }
1264
1265 static int
1266 do_add_counters(void __user *user, unsigned int len)
1267 {
1268         unsigned int i;
1269         struct ip6t_counters_info tmp, *paddc;
1270         struct ip6t_table *t;
1271         int ret;
1272
1273         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1274                 return -EFAULT;
1275
1276         if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1277                 return -EINVAL;
1278
1279         paddc = vmalloc(len);
1280         if (!paddc)
1281                 return -ENOMEM;
1282
1283         if (copy_from_user(paddc, user, len) != 0) {
1284                 ret = -EFAULT;
1285                 goto free;
1286         }
1287
1288         t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1289         if (!t)
1290                 goto free;
1291
1292         write_lock_bh(&t->lock);
1293         if (t->private->number != paddc->num_counters) {
1294                 ret = -EINVAL;
1295                 goto unlock_up_free;
1296         }
1297
1298         i = 0;
1299         IP6T_ENTRY_ITERATE(t->private->entries,
1300                           t->private->size,
1301                           add_counter_to_entry,
1302                           paddc->counters,
1303                           &i);
1304  unlock_up_free:
1305         write_unlock_bh(&t->lock);
1306         up(&ip6t_mutex);
1307  free:
1308         vfree(paddc);
1309
1310         return ret;
1311 }
1312
1313 static int
1314 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1315 {
1316         int ret;
1317
1318         if (!capable(CAP_NET_ADMIN))
1319                 return -EPERM;
1320
1321         switch (cmd) {
1322         case IP6T_SO_SET_REPLACE:
1323                 ret = do_replace(user, len);
1324                 break;
1325
1326         case IP6T_SO_SET_ADD_COUNTERS:
1327                 ret = do_add_counters(user, len);
1328                 break;
1329
1330         default:
1331                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1332                 ret = -EINVAL;
1333         }
1334
1335         return ret;
1336 }
1337
1338 static int
1339 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1340 {
1341         int ret;
1342
1343         if (!capable(CAP_NET_ADMIN))
1344                 return -EPERM;
1345
1346         switch (cmd) {
1347         case IP6T_SO_GET_INFO: {
1348                 char name[IP6T_TABLE_MAXNAMELEN];
1349                 struct ip6t_table *t;
1350
1351                 if (*len != sizeof(struct ip6t_getinfo)) {
1352                         duprintf("length %u != %u\n", *len,
1353                                  sizeof(struct ip6t_getinfo));
1354                         ret = -EINVAL;
1355                         break;
1356                 }
1357
1358                 if (copy_from_user(name, user, sizeof(name)) != 0) {
1359                         ret = -EFAULT;
1360                         break;
1361                 }
1362                 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1363                 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1364                 if (t) {
1365                         struct ip6t_getinfo info;
1366
1367                         info.valid_hooks = t->valid_hooks;
1368                         memcpy(info.hook_entry, t->private->hook_entry,
1369                                sizeof(info.hook_entry));
1370                         memcpy(info.underflow, t->private->underflow,
1371                                sizeof(info.underflow));
1372                         info.num_entries = t->private->number;
1373                         info.size = t->private->size;
1374                         memcpy(info.name, name, sizeof(info.name));
1375
1376                         if (copy_to_user(user, &info, *len) != 0)
1377                                 ret = -EFAULT;
1378                         else
1379                                 ret = 0;
1380
1381                         up(&ip6t_mutex);
1382                 }
1383         }
1384         break;
1385
1386         case IP6T_SO_GET_ENTRIES: {
1387                 struct ip6t_get_entries get;
1388
1389                 if (*len < sizeof(get)) {
1390                         duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1391                         ret = -EINVAL;
1392                 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1393                         ret = -EFAULT;
1394                 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1395                         duprintf("get_entries: %u != %u\n", *len,
1396                                  sizeof(struct ip6t_get_entries) + get.size);
1397                         ret = -EINVAL;
1398                 } else
1399                         ret = get_entries(&get, user);
1400                 break;
1401         }
1402
1403         default:
1404                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1405                 ret = -EINVAL;
1406         }
1407
1408         return ret;
1409 }
1410
1411 /* Registration hooks for targets. */
1412 int
1413 ip6t_register_target(struct ip6t_target *target)
1414 {
1415         int ret;
1416
1417         ret = down_interruptible(&ip6t_mutex);
1418         if (ret != 0)
1419                 return ret;
1420
1421         if (!list_named_insert(&ip6t_target, target)) {
1422                 duprintf("ip6t_register_target: `%s' already in list!\n",
1423                          target->name);
1424                 ret = -EINVAL;
1425         }
1426         up(&ip6t_mutex);
1427         return ret;
1428 }
1429
1430 void
1431 ip6t_unregister_target(struct ip6t_target *target)
1432 {
1433         down(&ip6t_mutex);
1434         LIST_DELETE(&ip6t_target, target);
1435         up(&ip6t_mutex);
1436 }
1437
1438 int
1439 ip6t_register_match(struct ip6t_match *match)
1440 {
1441         int ret;
1442
1443         ret = down_interruptible(&ip6t_mutex);
1444         if (ret != 0)
1445                 return ret;
1446
1447         if (!list_named_insert(&ip6t_match, match)) {
1448                 duprintf("ip6t_register_match: `%s' already in list!\n",
1449                          match->name);
1450                 ret = -EINVAL;
1451         }
1452         up(&ip6t_mutex);
1453
1454         return ret;
1455 }
1456
1457 void
1458 ip6t_unregister_match(struct ip6t_match *match)
1459 {
1460         down(&ip6t_mutex);
1461         LIST_DELETE(&ip6t_match, match);
1462         up(&ip6t_mutex);
1463 }
1464
1465 int ip6t_register_table(struct ip6t_table *table,
1466                         const struct ip6t_replace *repl)
1467 {
1468         int ret;
1469         struct ip6t_table_info *newinfo;
1470         static struct ip6t_table_info bootstrap
1471                 = { 0, 0, 0, { 0 }, { 0 }, { } };
1472
1473         newinfo = vmalloc(sizeof(struct ip6t_table_info)
1474                           + SMP_ALIGN(repl->size) *
1475                                         (highest_possible_processor_id()+1));
1476         if (!newinfo)
1477                 return -ENOMEM;
1478
1479         memcpy(newinfo->entries, repl->entries, repl->size);
1480
1481         ret = translate_table(table->name, table->valid_hooks,
1482                               newinfo, repl->size,
1483                               repl->num_entries,
1484                               repl->hook_entry,
1485                               repl->underflow);
1486         if (ret != 0) {
1487                 vfree(newinfo);
1488                 return ret;
1489         }
1490
1491         ret = down_interruptible(&ip6t_mutex);
1492         if (ret != 0) {
1493                 vfree(newinfo);
1494                 return ret;
1495         }
1496
1497         /* Don't autoload: we'd eat our tail... */
1498         if (list_named_find(&ip6t_tables, table->name)) {
1499                 ret = -EEXIST;
1500                 goto free_unlock;
1501         }
1502
1503         /* Simplifies replace_table code. */
1504         table->private = &bootstrap;
1505         if (!replace_table(table, 0, newinfo, &ret))
1506                 goto free_unlock;
1507
1508         duprintf("table->private->number = %u\n",
1509                  table->private->number);
1510
1511         /* save number of initial entries */
1512         table->private->initial_entries = table->private->number;
1513
1514         rwlock_init(&table->lock);
1515         list_prepend(&ip6t_tables, table);
1516
1517  unlock:
1518         up(&ip6t_mutex);
1519         return ret;
1520
1521  free_unlock:
1522         vfree(newinfo);
1523         goto unlock;
1524 }
1525
1526 void ip6t_unregister_table(struct ip6t_table *table)
1527 {
1528         down(&ip6t_mutex);
1529         LIST_DELETE(&ip6t_tables, table);
1530         up(&ip6t_mutex);
1531
1532         /* Decrease module usage counts and free resources */
1533         IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1534                           cleanup_entry, NULL);
1535         vfree(table->private);
1536 }
1537
1538 /* Returns 1 if the port is matched by the range, 0 otherwise */
1539 static inline int
1540 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1541 {
1542         int ret;
1543
1544         ret = (port >= min && port <= max) ^ invert;
1545         return ret;
1546 }
1547
1548 static int
1549 tcp_find_option(u_int8_t option,
1550                 const struct sk_buff *skb,
1551                 unsigned int tcpoff,
1552                 unsigned int optlen,
1553                 int invert,
1554                 int *hotdrop)
1555 {
1556         /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1557         u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1558         unsigned int i;
1559
1560         duprintf("tcp_match: finding option\n");
1561         if (!optlen)
1562                 return invert;
1563         /* If we don't have the whole header, drop packet. */
1564         op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1565                                 _opt);
1566         if (op == NULL) {
1567                 *hotdrop = 1;
1568                 return 0;
1569         }
1570
1571         for (i = 0; i < optlen; ) {
1572                 if (op[i] == option) return !invert;
1573                 if (op[i] < 2) i++;
1574                 else i += op[i+1]?:1;
1575         }
1576
1577         return invert;
1578 }
1579
1580 static int
1581 tcp_match(const struct sk_buff *skb,
1582           const struct net_device *in,
1583           const struct net_device *out,
1584           const void *matchinfo,
1585           int offset,
1586           unsigned int protoff,
1587           int *hotdrop)
1588 {
1589         struct tcphdr _tcph, *th;
1590         const struct ip6t_tcp *tcpinfo = matchinfo;
1591
1592         if (offset) {
1593                 /* To quote Alan:
1594
1595                    Don't allow a fragment of TCP 8 bytes in. Nobody normal
1596                    causes this. Its a cracker trying to break in by doing a
1597                    flag overwrite to pass the direction checks.
1598                 */
1599                 if (offset == 1) {
1600                         duprintf("Dropping evil TCP offset=1 frag.\n");
1601                         *hotdrop = 1;
1602                 }
1603                 /* Must not be a fragment. */
1604                 return 0;
1605         }
1606
1607 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1608
1609         th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1610         if (th == NULL) {
1611                 /* We've been asked to examine this packet, and we
1612                    can't.  Hence, no choice but to drop. */
1613                 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1614                 *hotdrop = 1;
1615                 return 0;
1616         }
1617
1618         if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1619                         ntohs(th->source),
1620                         !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1621                 return 0;
1622         if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1623                         ntohs(th->dest),
1624                         !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1625                 return 0;
1626         if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1627                       == tcpinfo->flg_cmp,
1628                       IP6T_TCP_INV_FLAGS))
1629                 return 0;
1630         if (tcpinfo->option) {
1631                 if (th->doff * 4 < sizeof(_tcph)) {
1632                         *hotdrop = 1;
1633                         return 0;
1634                 }
1635                 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1636                                      th->doff*4 - sizeof(*th),
1637                                      tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1638                                      hotdrop))
1639                         return 0;
1640         }
1641         return 1;
1642 }
1643
1644 /* Called when user tries to insert an entry of this type. */
1645 static int
1646 tcp_checkentry(const char *tablename,
1647                const struct ip6t_ip6 *ipv6,
1648                void *matchinfo,
1649                unsigned int matchsize,
1650                unsigned int hook_mask)
1651 {
1652         const struct ip6t_tcp *tcpinfo = matchinfo;
1653
1654         /* Must specify proto == TCP, and no unknown invflags */
1655         return ipv6->proto == IPPROTO_TCP
1656                 && !(ipv6->invflags & IP6T_INV_PROTO)
1657                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1658                 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1659 }
1660
1661 static int
1662 udp_match(const struct sk_buff *skb,
1663           const struct net_device *in,
1664           const struct net_device *out,
1665           const void *matchinfo,
1666           int offset,
1667           unsigned int protoff,
1668           int *hotdrop)
1669 {
1670         struct udphdr _udph, *uh;
1671         const struct ip6t_udp *udpinfo = matchinfo;
1672
1673         /* Must not be a fragment. */
1674         if (offset)
1675                 return 0;
1676
1677         uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1678         if (uh == NULL) {
1679                 /* We've been asked to examine this packet, and we
1680                    can't.  Hence, no choice but to drop. */
1681                 duprintf("Dropping evil UDP tinygram.\n");
1682                 *hotdrop = 1;
1683                 return 0;
1684         }
1685
1686         return port_match(udpinfo->spts[0], udpinfo->spts[1],
1687                           ntohs(uh->source),
1688                           !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1689                 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1690                               ntohs(uh->dest),
1691                               !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1692 }
1693
1694 /* Called when user tries to insert an entry of this type. */
1695 static int
1696 udp_checkentry(const char *tablename,
1697                const struct ip6t_ip6 *ipv6,
1698                void *matchinfo,
1699                unsigned int matchinfosize,
1700                unsigned int hook_mask)
1701 {
1702         const struct ip6t_udp *udpinfo = matchinfo;
1703
1704         /* Must specify proto == UDP, and no unknown invflags */
1705         if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1706                 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1707                          IPPROTO_UDP);
1708                 return 0;
1709         }
1710         if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1711                 duprintf("ip6t_udp: matchsize %u != %u\n",
1712                          matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1713                 return 0;
1714         }
1715         if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1716                 duprintf("ip6t_udp: unknown flags %X\n",
1717                          udpinfo->invflags);
1718                 return 0;
1719         }
1720
1721         return 1;
1722 }
1723
1724 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1725 static inline int
1726 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1727                      u_int8_t type, u_int8_t code,
1728                      int invert)
1729 {
1730         return (type == test_type && code >= min_code && code <= max_code)
1731                 ^ invert;
1732 }
1733
1734 static int
1735 icmp6_match(const struct sk_buff *skb,
1736            const struct net_device *in,
1737            const struct net_device *out,
1738            const void *matchinfo,
1739            int offset,
1740            unsigned int protoff,
1741            int *hotdrop)
1742 {
1743         struct icmp6hdr _icmp, *ic;
1744         const struct ip6t_icmp *icmpinfo = matchinfo;
1745
1746         /* Must not be a fragment. */
1747         if (offset)
1748                 return 0;
1749
1750         ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1751         if (ic == NULL) {
1752                 /* We've been asked to examine this packet, and we
1753                    can't.  Hence, no choice but to drop. */
1754                 duprintf("Dropping evil ICMP tinygram.\n");
1755                 *hotdrop = 1;
1756                 return 0;
1757         }
1758
1759         return icmp6_type_code_match(icmpinfo->type,
1760                                      icmpinfo->code[0],
1761                                      icmpinfo->code[1],
1762                                      ic->icmp6_type, ic->icmp6_code,
1763                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
1764 }
1765
1766 /* Called when user tries to insert an entry of this type. */
1767 static int
1768 icmp6_checkentry(const char *tablename,
1769            const struct ip6t_ip6 *ipv6,
1770            void *matchinfo,
1771            unsigned int matchsize,
1772            unsigned int hook_mask)
1773 {
1774         const struct ip6t_icmp *icmpinfo = matchinfo;
1775
1776         /* Must specify proto == ICMP, and no unknown invflags */
1777         return ipv6->proto == IPPROTO_ICMPV6
1778                 && !(ipv6->invflags & IP6T_INV_PROTO)
1779                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1780                 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1781 }
1782
1783 /* The built-in targets: standard (NULL) and error. */
1784 static struct ip6t_target ip6t_standard_target = {
1785         .name           = IP6T_STANDARD_TARGET,
1786 };
1787
1788 static struct ip6t_target ip6t_error_target = {
1789         .name           = IP6T_ERROR_TARGET,
1790         .target         = ip6t_error,
1791 };
1792
1793 static struct nf_sockopt_ops ip6t_sockopts = {
1794         .pf             = PF_INET6,
1795         .set_optmin     = IP6T_BASE_CTL,
1796         .set_optmax     = IP6T_SO_SET_MAX+1,
1797         .set            = do_ip6t_set_ctl,
1798         .get_optmin     = IP6T_BASE_CTL,
1799         .get_optmax     = IP6T_SO_GET_MAX+1,
1800         .get            = do_ip6t_get_ctl,
1801 };
1802
1803 static struct ip6t_match tcp_matchstruct = {
1804         .name           = "tcp",
1805         .match          = &tcp_match,
1806         .checkentry     = &tcp_checkentry,
1807 };
1808
1809 static struct ip6t_match udp_matchstruct = {
1810         .name           = "udp",
1811         .match          = &udp_match,
1812         .checkentry     = &udp_checkentry,
1813 };
1814
1815 static struct ip6t_match icmp6_matchstruct = {
1816         .name           = "icmp6",
1817         .match          = &icmp6_match,
1818         .checkentry     = &icmp6_checkentry,
1819 };
1820
1821 #ifdef CONFIG_PROC_FS
1822 static inline int print_name(const char *i,
1823                              off_t start_offset, char *buffer, int length,
1824                              off_t *pos, unsigned int *count)
1825 {
1826         if ((*count)++ >= start_offset) {
1827                 unsigned int namelen;
1828
1829                 namelen = sprintf(buffer + *pos, "%s\n",
1830                                   i + sizeof(struct list_head));
1831                 if (*pos + namelen > length) {
1832                         /* Stop iterating */
1833                         return 1;
1834                 }
1835                 *pos += namelen;
1836         }
1837         return 0;
1838 }
1839
1840 static inline int print_target(const struct ip6t_target *t,
1841                                off_t start_offset, char *buffer, int length,
1842                                off_t *pos, unsigned int *count)
1843 {
1844         if (t == &ip6t_standard_target || t == &ip6t_error_target)
1845                 return 0;
1846         return print_name((char *)t, start_offset, buffer, length, pos, count);
1847 }
1848
1849 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1850 {
1851         off_t pos = 0;
1852         unsigned int count = 0;
1853
1854         if (down_interruptible(&ip6t_mutex) != 0)
1855                 return 0;
1856
1857         LIST_FIND(&ip6t_tables, print_name, char *,
1858                   offset, buffer, length, &pos, &count);
1859
1860         up(&ip6t_mutex);
1861
1862         /* `start' hack - see fs/proc/generic.c line ~105 */
1863         *start=(char *)((unsigned long)count-offset);
1864         return pos;
1865 }
1866
1867 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1868 {
1869         off_t pos = 0;
1870         unsigned int count = 0;
1871
1872         if (down_interruptible(&ip6t_mutex) != 0)
1873                 return 0;
1874
1875         LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1876                   offset, buffer, length, &pos, &count);
1877
1878         up(&ip6t_mutex);
1879
1880         *start = (char *)((unsigned long)count - offset);
1881         return pos;
1882 }
1883
1884 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1885 {
1886         off_t pos = 0;
1887         unsigned int count = 0;
1888
1889         if (down_interruptible(&ip6t_mutex) != 0)
1890                 return 0;
1891
1892         LIST_FIND(&ip6t_match, print_name, char *,
1893                   offset, buffer, length, &pos, &count);
1894
1895         up(&ip6t_mutex);
1896
1897         *start = (char *)((unsigned long)count - offset);
1898         return pos;
1899 }
1900
1901 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1902 { { "ip6_tables_names", ip6t_get_tables },
1903   { "ip6_tables_targets", ip6t_get_targets },
1904   { "ip6_tables_matches", ip6t_get_matches },
1905   { NULL, NULL} };
1906 #endif /*CONFIG_PROC_FS*/
1907
1908 static int __init init(void)
1909 {
1910         int ret;
1911
1912         /* Noone else will be downing sem now, so we won't sleep */
1913         down(&ip6t_mutex);
1914         list_append(&ip6t_target, &ip6t_standard_target);
1915         list_append(&ip6t_target, &ip6t_error_target);
1916         list_append(&ip6t_match, &tcp_matchstruct);
1917         list_append(&ip6t_match, &udp_matchstruct);
1918         list_append(&ip6t_match, &icmp6_matchstruct);
1919         up(&ip6t_mutex);
1920
1921         /* Register setsockopt */
1922         ret = nf_register_sockopt(&ip6t_sockopts);
1923         if (ret < 0) {
1924                 duprintf("Unable to register sockopts.\n");
1925                 return ret;
1926         }
1927
1928 #ifdef CONFIG_PROC_FS
1929         {
1930                 struct proc_dir_entry *proc;
1931                 int i;
1932
1933                 for (i = 0; ip6t_proc_entry[i].name; i++) {
1934                         proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1935                                                ip6t_proc_entry[i].get_info);
1936                         if (!proc) {
1937                                 while (--i >= 0)
1938                                        proc_net_remove(ip6t_proc_entry[i].name);
1939                                 nf_unregister_sockopt(&ip6t_sockopts);
1940                                 return -ENOMEM;
1941                         }
1942                         proc->owner = THIS_MODULE;
1943                 }
1944         }
1945 #endif
1946
1947         printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1948         return 0;
1949 }
1950
1951 static void __exit fini(void)
1952 {
1953         nf_unregister_sockopt(&ip6t_sockopts);
1954 #ifdef CONFIG_PROC_FS
1955         {
1956                 int i;
1957                 for (i = 0; ip6t_proc_entry[i].name; i++)
1958                         proc_net_remove(ip6t_proc_entry[i].name);
1959         }
1960 #endif
1961 }
1962
1963 /*
1964  * find specified header up to transport protocol header.
1965  * If found target header, the offset to the header is set to *offset
1966  * and return 0. otherwise, return -1.
1967  *
1968  * Notes: - non-1st Fragment Header isn't skipped.
1969  *        - ESP header isn't skipped.
1970  *        - The target header may be trancated.
1971  */
1972 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
1973 {
1974         unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1975         u8 nexthdr = skb->nh.ipv6h->nexthdr;
1976         unsigned int len = skb->len - start;
1977
1978         while (nexthdr != target) {
1979                 struct ipv6_opt_hdr _hdr, *hp;
1980                 unsigned int hdrlen;
1981
1982                 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
1983                         return -1;
1984                 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1985                 if (hp == NULL)
1986                         return -1;
1987                 if (nexthdr == NEXTHDR_FRAGMENT) {
1988                         unsigned short _frag_off, *fp;
1989                         fp = skb_header_pointer(skb,
1990                                                 start+offsetof(struct frag_hdr,
1991                                                                frag_off),
1992                                                 sizeof(_frag_off),
1993                                                 &_frag_off);
1994                         if (fp == NULL)
1995                                 return -1;
1996
1997                         if (ntohs(*fp) & ~0x7)
1998                                 return -1;
1999                         hdrlen = 8;
2000                 } else if (nexthdr == NEXTHDR_AUTH)
2001                         hdrlen = (hp->hdrlen + 2) << 2; 
2002                 else
2003                         hdrlen = ipv6_optlen(hp); 
2004
2005                 nexthdr = hp->nexthdr;
2006                 len -= hdrlen;
2007                 start += hdrlen;
2008         }
2009
2010         *offset = start;
2011         return 0;
2012 }
2013
2014 EXPORT_SYMBOL(ip6t_register_table);
2015 EXPORT_SYMBOL(ip6t_unregister_table);
2016 EXPORT_SYMBOL(ip6t_do_table);
2017 EXPORT_SYMBOL(ip6t_register_match);
2018 EXPORT_SYMBOL(ip6t_unregister_match);
2019 EXPORT_SYMBOL(ip6t_register_target);
2020 EXPORT_SYMBOL(ip6t_unregister_target);
2021 EXPORT_SYMBOL(ip6t_ext_hdr);
2022 EXPORT_SYMBOL(ipv6_find_hdr);
2023
2024 module_init(init);
2025 module_exit(fini);