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