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