8ce5b6f76447f88bc97913d72c6b53f0812610a8
[linux-2.6.git] / net / ipv4 / netfilter / ip_tables.c
1 /*
2  * Packet matching code.
3  *
4  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5  * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12  *      - increase module usage count as soon as we have rules inside
13  *        a table
14  * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
15  *      - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
16  */
17 #include <linux/cache.h>
18 #include <linux/capability.h>
19 #include <linux/skbuff.h>
20 #include <linux/kmod.h>
21 #include <linux/vmalloc.h>
22 #include <linux/netdevice.h>
23 #include <linux/module.h>
24 #include <linux/icmp.h>
25 #include <net/ip.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
32
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter_ipv4/ip_tables.h>
35
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
38 MODULE_DESCRIPTION("IPv4 packet filter");
39
40 /*#define DEBUG_IP_FIREWALL*/
41 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
42 /*#define DEBUG_IP_FIREWALL_USER*/
43
44 #ifdef DEBUG_IP_FIREWALL
45 #define dprintf(format, args...)  printk(format , ## args)
46 #else
47 #define dprintf(format, args...)
48 #endif
49
50 #ifdef DEBUG_IP_FIREWALL_USER
51 #define duprintf(format, args...) printk(format , ## args)
52 #else
53 #define duprintf(format, args...)
54 #endif
55
56 #ifdef CONFIG_NETFILTER_DEBUG
57 #define IP_NF_ASSERT(x)                                         \
58 do {                                                            \
59         if (!(x))                                               \
60                 printk("IP_NF_ASSERT: %s:%s:%u\n",              \
61                        __FUNCTION__, __FILE__, __LINE__);       \
62 } while(0)
63 #else
64 #define IP_NF_ASSERT(x)
65 #endif
66
67 #if 0
68 /* All the better to debug you with... */
69 #define static
70 #define inline
71 #endif
72
73 /*
74    We keep a set of rules for each CPU, so we can avoid write-locking
75    them in the softirq when updating the counters and therefore
76    only need to read-lock in the softirq; doing a write_lock_bh() in user
77    context stops packets coming through and allows user context to read
78    the counters or update the rules.
79
80    Hence the start of any table is given by get_table() below.  */
81
82 /* Returns whether matches rule or not. */
83 static inline int
84 ip_packet_match(const struct iphdr *ip,
85                 const char *indev,
86                 const char *outdev,
87                 const struct ipt_ip *ipinfo,
88                 int isfrag)
89 {
90         size_t i;
91         unsigned long ret;
92
93 #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
94
95         if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
96                   IPT_INV_SRCIP)
97             || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
98                      IPT_INV_DSTIP)) {
99                 dprintf("Source or dest mismatch.\n");
100
101                 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
102                         NIPQUAD(ip->saddr),
103                         NIPQUAD(ipinfo->smsk.s_addr),
104                         NIPQUAD(ipinfo->src.s_addr),
105                         ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
106                 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
107                         NIPQUAD(ip->daddr),
108                         NIPQUAD(ipinfo->dmsk.s_addr),
109                         NIPQUAD(ipinfo->dst.s_addr),
110                         ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
111                 return 0;
112         }
113
114         /* Look for ifname matches; this should unroll nicely. */
115         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
116                 ret |= (((const unsigned long *)indev)[i]
117                         ^ ((const unsigned long *)ipinfo->iniface)[i])
118                         & ((const unsigned long *)ipinfo->iniface_mask)[i];
119         }
120
121         if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
122                 dprintf("VIA in mismatch (%s vs %s).%s\n",
123                         indev, ipinfo->iniface,
124                         ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
125                 return 0;
126         }
127
128         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
129                 ret |= (((const unsigned long *)outdev)[i]
130                         ^ ((const unsigned long *)ipinfo->outiface)[i])
131                         & ((const unsigned long *)ipinfo->outiface_mask)[i];
132         }
133
134         if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
135                 dprintf("VIA out mismatch (%s vs %s).%s\n",
136                         outdev, ipinfo->outiface,
137                         ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
138                 return 0;
139         }
140
141         /* Check specific protocol */
142         if (ipinfo->proto
143             && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
144                 dprintf("Packet protocol %hi does not match %hi.%s\n",
145                         ip->protocol, ipinfo->proto,
146                         ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
147                 return 0;
148         }
149
150         /* If we have a fragment rule but the packet is not a fragment
151          * then we return zero */
152         if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
153                 dprintf("Fragment rule but not fragment.%s\n",
154                         ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
155                 return 0;
156         }
157
158         return 1;
159 }
160
161 static inline int
162 ip_checkentry(const struct ipt_ip *ip)
163 {
164         if (ip->flags & ~IPT_F_MASK) {
165                 duprintf("Unknown flag bits set: %08X\n",
166                          ip->flags & ~IPT_F_MASK);
167                 return 0;
168         }
169         if (ip->invflags & ~IPT_INV_MASK) {
170                 duprintf("Unknown invflag bits set: %08X\n",
171                          ip->invflags & ~IPT_INV_MASK);
172                 return 0;
173         }
174         return 1;
175 }
176
177 static unsigned int
178 ipt_error(struct sk_buff **pskb,
179           const struct net_device *in,
180           const struct net_device *out,
181           unsigned int hooknum,
182           const struct xt_target *target,
183           const void *targinfo)
184 {
185         if (net_ratelimit())
186                 printk("ip_tables: error: `%s'\n", (char *)targinfo);
187
188         return NF_DROP;
189 }
190
191 static inline
192 int do_match(struct ipt_entry_match *m,
193              const struct sk_buff *skb,
194              const struct net_device *in,
195              const struct net_device *out,
196              int offset,
197              int *hotdrop)
198 {
199         /* Stop iteration if it doesn't match */
200         if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
201                                       offset, skb->nh.iph->ihl*4, hotdrop))
202                 return 1;
203         else
204                 return 0;
205 }
206
207 static inline struct ipt_entry *
208 get_entry(void *base, unsigned int offset)
209 {
210         return (struct ipt_entry *)(base + offset);
211 }
212
213 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
214 unsigned int
215 ipt_do_table(struct sk_buff **pskb,
216              unsigned int hook,
217              const struct net_device *in,
218              const struct net_device *out,
219              struct ipt_table *table)
220 {
221         static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
222         u_int16_t offset;
223         struct iphdr *ip;
224         u_int16_t datalen;
225         int hotdrop = 0;
226         /* Initializing verdict to NF_DROP keeps gcc happy. */
227         unsigned int verdict = NF_DROP;
228         const char *indev, *outdev;
229         void *table_base;
230         struct ipt_entry *e, *back;
231         struct xt_table_info *private;
232
233         /* Initialization */
234         ip = (*pskb)->nh.iph;
235         datalen = (*pskb)->len - ip->ihl * 4;
236         indev = in ? in->name : nulldevname;
237         outdev = out ? out->name : nulldevname;
238         /* We handle fragments by dealing with the first fragment as
239          * if it was a normal packet.  All other fragments are treated
240          * normally, except that they will NEVER match rules that ask
241          * things we don't know, ie. tcp syn flag or ports).  If the
242          * rule is also a fragment-specific rule, non-fragments won't
243          * match it. */
244         offset = ntohs(ip->frag_off) & IP_OFFSET;
245
246         read_lock_bh(&table->lock);
247         IP_NF_ASSERT(table->valid_hooks & (1 << hook));
248         private = table->private;
249         table_base = (void *)private->entries[smp_processor_id()];
250         e = get_entry(table_base, private->hook_entry[hook]);
251
252         /* For return from builtin chain */
253         back = get_entry(table_base, private->underflow[hook]);
254
255         do {
256                 IP_NF_ASSERT(e);
257                 IP_NF_ASSERT(back);
258                 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
259                         struct ipt_entry_target *t;
260
261                         if (IPT_MATCH_ITERATE(e, do_match,
262                                               *pskb, in, out,
263                                               offset, &hotdrop) != 0)
264                                 goto no_match;
265
266                         ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
267
268                         t = ipt_get_target(e);
269                         IP_NF_ASSERT(t->u.kernel.target);
270                         /* Standard target? */
271                         if (!t->u.kernel.target->target) {
272                                 int v;
273
274                                 v = ((struct ipt_standard_target *)t)->verdict;
275                                 if (v < 0) {
276                                         /* Pop from stack? */
277                                         if (v != IPT_RETURN) {
278                                                 verdict = (unsigned)(-v) - 1;
279                                                 break;
280                                         }
281                                         e = back;
282                                         back = get_entry(table_base,
283                                                          back->comefrom);
284                                         continue;
285                                 }
286                                 if (table_base + v != (void *)e + e->next_offset
287                                     && !(e->ip.flags & IPT_F_GOTO)) {
288                                         /* Save old back ptr in next entry */
289                                         struct ipt_entry *next
290                                                 = (void *)e + e->next_offset;
291                                         next->comefrom
292                                                 = (void *)back - table_base;
293                                         /* set back pointer to next entry */
294                                         back = next;
295                                 }
296
297                                 e = get_entry(table_base, v);
298                         } else {
299                                 /* Targets which reenter must return
300                                    abs. verdicts */
301 #ifdef CONFIG_NETFILTER_DEBUG
302                                 ((struct ipt_entry *)table_base)->comefrom
303                                         = 0xeeeeeeec;
304 #endif
305                                 verdict = t->u.kernel.target->target(pskb,
306                                                                      in, out,
307                                                                      hook,
308                                                                      t->u.kernel.target,
309                                                                      t->data);
310
311 #ifdef CONFIG_NETFILTER_DEBUG
312                                 if (((struct ipt_entry *)table_base)->comefrom
313                                     != 0xeeeeeeec
314                                     && verdict == IPT_CONTINUE) {
315                                         printk("Target %s reentered!\n",
316                                                t->u.kernel.target->name);
317                                         verdict = NF_DROP;
318                                 }
319                                 ((struct ipt_entry *)table_base)->comefrom
320                                         = 0x57acc001;
321 #endif
322                                 /* Target might have changed stuff. */
323                                 ip = (*pskb)->nh.iph;
324                                 datalen = (*pskb)->len - ip->ihl * 4;
325
326                                 if (verdict == IPT_CONTINUE)
327                                         e = (void *)e + e->next_offset;
328                                 else
329                                         /* Verdict */
330                                         break;
331                         }
332                 } else {
333
334                 no_match:
335                         e = (void *)e + e->next_offset;
336                 }
337         } while (!hotdrop);
338
339         read_unlock_bh(&table->lock);
340
341 #ifdef DEBUG_ALLOW_ALL
342         return NF_ACCEPT;
343 #else
344         if (hotdrop)
345                 return NF_DROP;
346         else return verdict;
347 #endif
348 }
349
350 /* All zeroes == unconditional rule. */
351 static inline int
352 unconditional(const struct ipt_ip *ip)
353 {
354         unsigned int i;
355
356         for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
357                 if (((__u32 *)ip)[i])
358                         return 0;
359
360         return 1;
361 }
362
363 /* Figures out from what hook each rule can be called: returns 0 if
364    there are loops.  Puts hook bitmask in comefrom. */
365 static int
366 mark_source_chains(struct xt_table_info *newinfo,
367                    unsigned int valid_hooks, void *entry0)
368 {
369         unsigned int hook;
370
371         /* No recursion; use packet counter to save back ptrs (reset
372            to 0 as we leave), and comefrom to save source hook bitmask */
373         for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
374                 unsigned int pos = newinfo->hook_entry[hook];
375                 struct ipt_entry *e
376                         = (struct ipt_entry *)(entry0 + pos);
377
378                 if (!(valid_hooks & (1 << hook)))
379                         continue;
380
381                 /* Set initial back pointer. */
382                 e->counters.pcnt = pos;
383
384                 for (;;) {
385                         struct ipt_standard_target *t
386                                 = (void *)ipt_get_target(e);
387
388                         if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
389                                 printk("iptables: loop hook %u pos %u %08X.\n",
390                                        hook, pos, e->comefrom);
391                                 return 0;
392                         }
393                         e->comefrom
394                                 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
395
396                         /* Unconditional return/END. */
397                         if (e->target_offset == sizeof(struct ipt_entry)
398                             && (strcmp(t->target.u.user.name,
399                                        IPT_STANDARD_TARGET) == 0)
400                             && t->verdict < 0
401                             && unconditional(&e->ip)) {
402                                 unsigned int oldpos, size;
403
404                                 /* Return: backtrack through the last
405                                    big jump. */
406                                 do {
407                                         e->comefrom ^= (1<<NF_IP_NUMHOOKS);
408 #ifdef DEBUG_IP_FIREWALL_USER
409                                         if (e->comefrom
410                                             & (1 << NF_IP_NUMHOOKS)) {
411                                                 duprintf("Back unset "
412                                                          "on hook %u "
413                                                          "rule %u\n",
414                                                          hook, pos);
415                                         }
416 #endif
417                                         oldpos = pos;
418                                         pos = e->counters.pcnt;
419                                         e->counters.pcnt = 0;
420
421                                         /* We're at the start. */
422                                         if (pos == oldpos)
423                                                 goto next;
424
425                                         e = (struct ipt_entry *)
426                                                 (entry0 + pos);
427                                 } while (oldpos == pos + e->next_offset);
428
429                                 /* Move along one */
430                                 size = e->next_offset;
431                                 e = (struct ipt_entry *)
432                                         (entry0 + pos + size);
433                                 e->counters.pcnt = pos;
434                                 pos += size;
435                         } else {
436                                 int newpos = t->verdict;
437
438                                 if (strcmp(t->target.u.user.name,
439                                            IPT_STANDARD_TARGET) == 0
440                                     && newpos >= 0) {
441                                         /* This a jump; chase it. */
442                                         duprintf("Jump rule %u -> %u\n",
443                                                  pos, newpos);
444                                 } else {
445                                         /* ... this is a fallthru */
446                                         newpos = pos + e->next_offset;
447                                 }
448                                 e = (struct ipt_entry *)
449                                         (entry0 + newpos);
450                                 e->counters.pcnt = pos;
451                                 pos = newpos;
452                         }
453                 }
454                 next:
455                 duprintf("Finished chain %u\n", hook);
456         }
457         return 1;
458 }
459
460 static inline int
461 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
462 {
463         if (i && (*i)-- == 0)
464                 return 1;
465
466         if (m->u.kernel.match->destroy)
467                 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
468                                            m->u.match_size - sizeof(*m));
469         module_put(m->u.kernel.match->me);
470         return 0;
471 }
472
473 static inline int
474 standard_check(const struct ipt_entry_target *t,
475                unsigned int max_offset)
476 {
477         struct ipt_standard_target *targ = (void *)t;
478
479         /* Check standard info. */
480         if (targ->verdict >= 0
481             && targ->verdict > max_offset - sizeof(struct ipt_entry)) {
482                 duprintf("ipt_standard_check: bad verdict (%i)\n",
483                          targ->verdict);
484                 return 0;
485         }
486         if (targ->verdict < -NF_MAX_VERDICT - 1) {
487                 duprintf("ipt_standard_check: bad negative verdict (%i)\n",
488                          targ->verdict);
489                 return 0;
490         }
491         return 1;
492 }
493
494 static inline int
495 check_match(struct ipt_entry_match *m,
496             const char *name,
497             const struct ipt_ip *ip,
498             unsigned int hookmask,
499             unsigned int *i)
500 {
501         struct ipt_match *match;
502         int ret;
503
504         match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
505                                                    m->u.user.revision),
506                                         "ipt_%s", m->u.user.name);
507         if (IS_ERR(match) || !match) {
508                 duprintf("check_match: `%s' not found\n", m->u.user.name);
509                 return match ? PTR_ERR(match) : -ENOENT;
510         }
511         m->u.kernel.match = match;
512
513         ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
514                              name, hookmask, ip->proto,
515                              ip->invflags & IPT_INV_PROTO);
516         if (ret)
517                 goto err;
518
519         if (m->u.kernel.match->checkentry
520             && !m->u.kernel.match->checkentry(name, ip, match, m->data,
521                                               m->u.match_size - sizeof(*m),
522                                               hookmask)) {
523                 duprintf("ip_tables: check failed for `%s'.\n",
524                          m->u.kernel.match->name);
525                 ret = -EINVAL;
526                 goto err;
527         }
528
529         (*i)++;
530         return 0;
531 err:
532         module_put(m->u.kernel.match->me);
533         return ret;
534 }
535
536 static struct ipt_target ipt_standard_target;
537
538 static inline int
539 check_entry(struct ipt_entry *e, const char *name, unsigned int size,
540             unsigned int *i)
541 {
542         struct ipt_entry_target *t;
543         struct ipt_target *target;
544         int ret;
545         unsigned int j;
546
547         if (!ip_checkentry(&e->ip)) {
548                 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
549                 return -EINVAL;
550         }
551
552         j = 0;
553         ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
554         if (ret != 0)
555                 goto cleanup_matches;
556
557         t = ipt_get_target(e);
558         target = try_then_request_module(xt_find_target(AF_INET,
559                                                      t->u.user.name,
560                                                      t->u.user.revision),
561                                          "ipt_%s", t->u.user.name);
562         if (IS_ERR(target) || !target) {
563                 duprintf("check_entry: `%s' not found\n", t->u.user.name);
564                 ret = target ? PTR_ERR(target) : -ENOENT;
565                 goto cleanup_matches;
566         }
567         t->u.kernel.target = target;
568
569         ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
570                               name, e->comefrom, e->ip.proto,
571                               e->ip.invflags & IPT_INV_PROTO);
572         if (ret)
573                 goto err;
574
575         if (t->u.kernel.target == &ipt_standard_target) {
576                 if (!standard_check(t, size)) {
577                         ret = -EINVAL;
578                         goto cleanup_matches;
579                 }
580         } else if (t->u.kernel.target->checkentry
581                    && !t->u.kernel.target->checkentry(name, e, target, t->data,
582                                                       t->u.target_size
583                                                       - sizeof(*t),
584                                                       e->comefrom)) {
585                 duprintf("ip_tables: check failed for `%s'.\n",
586                          t->u.kernel.target->name);
587                 ret = -EINVAL;
588                 goto err;
589         }
590
591         (*i)++;
592         return 0;
593  err:
594         module_put(t->u.kernel.target->me);
595  cleanup_matches:
596         IPT_MATCH_ITERATE(e, cleanup_match, &j);
597         return ret;
598 }
599
600 static inline int
601 check_entry_size_and_hooks(struct ipt_entry *e,
602                            struct xt_table_info *newinfo,
603                            unsigned char *base,
604                            unsigned char *limit,
605                            const unsigned int *hook_entries,
606                            const unsigned int *underflows,
607                            unsigned int *i)
608 {
609         unsigned int h;
610
611         if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
612             || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
613                 duprintf("Bad offset %p\n", e);
614                 return -EINVAL;
615         }
616
617         if (e->next_offset
618             < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
619                 duprintf("checking: element %p size %u\n",
620                          e, e->next_offset);
621                 return -EINVAL;
622         }
623
624         /* Check hooks & underflows */
625         for (h = 0; h < NF_IP_NUMHOOKS; h++) {
626                 if ((unsigned char *)e - base == hook_entries[h])
627                         newinfo->hook_entry[h] = hook_entries[h];
628                 if ((unsigned char *)e - base == underflows[h])
629                         newinfo->underflow[h] = underflows[h];
630         }
631
632         /* FIXME: underflows must be unconditional, standard verdicts
633            < 0 (not IPT_RETURN). --RR */
634
635         /* Clear counters and comefrom */
636         e->counters = ((struct xt_counters) { 0, 0 });
637         e->comefrom = 0;
638
639         (*i)++;
640         return 0;
641 }
642
643 static inline int
644 cleanup_entry(struct ipt_entry *e, unsigned int *i)
645 {
646         struct ipt_entry_target *t;
647
648         if (i && (*i)-- == 0)
649                 return 1;
650
651         /* Cleanup all matches */
652         IPT_MATCH_ITERATE(e, cleanup_match, NULL);
653         t = ipt_get_target(e);
654         if (t->u.kernel.target->destroy)
655                 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
656                                             t->u.target_size - sizeof(*t));
657         module_put(t->u.kernel.target->me);
658         return 0;
659 }
660
661 /* Checks and translates the user-supplied table segment (held in
662    newinfo) */
663 static int
664 translate_table(const char *name,
665                 unsigned int valid_hooks,
666                 struct xt_table_info *newinfo,
667                 void *entry0,
668                 unsigned int size,
669                 unsigned int number,
670                 const unsigned int *hook_entries,
671                 const unsigned int *underflows)
672 {
673         unsigned int i;
674         int ret;
675
676         newinfo->size = size;
677         newinfo->number = number;
678
679         /* Init all hooks to impossible value. */
680         for (i = 0; i < NF_IP_NUMHOOKS; i++) {
681                 newinfo->hook_entry[i] = 0xFFFFFFFF;
682                 newinfo->underflow[i] = 0xFFFFFFFF;
683         }
684
685         duprintf("translate_table: size %u\n", newinfo->size);
686         i = 0;
687         /* Walk through entries, checking offsets. */
688         ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
689                                 check_entry_size_and_hooks,
690                                 newinfo,
691                                 entry0,
692                                 entry0 + size,
693                                 hook_entries, underflows, &i);
694         if (ret != 0)
695                 return ret;
696
697         if (i != number) {
698                 duprintf("translate_table: %u not %u entries\n",
699                          i, number);
700                 return -EINVAL;
701         }
702
703         /* Check hooks all assigned */
704         for (i = 0; i < NF_IP_NUMHOOKS; i++) {
705                 /* Only hooks which are valid */
706                 if (!(valid_hooks & (1 << i)))
707                         continue;
708                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
709                         duprintf("Invalid hook entry %u %u\n",
710                                  i, hook_entries[i]);
711                         return -EINVAL;
712                 }
713                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
714                         duprintf("Invalid underflow %u %u\n",
715                                  i, underflows[i]);
716                         return -EINVAL;
717                 }
718         }
719
720         if (!mark_source_chains(newinfo, valid_hooks, entry0))
721                 return -ELOOP;
722
723         /* Finally, each sanity check must pass */
724         i = 0;
725         ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
726                                 check_entry, name, size, &i);
727
728         if (ret != 0) {
729                 IPT_ENTRY_ITERATE(entry0, newinfo->size,
730                                   cleanup_entry, &i);
731                 return ret;
732         }
733
734         /* And one copy for every other CPU */
735         for_each_possible_cpu(i) {
736                 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
737                         memcpy(newinfo->entries[i], entry0, newinfo->size);
738         }
739
740         return ret;
741 }
742
743 /* Gets counters. */
744 static inline int
745 add_entry_to_counter(const struct ipt_entry *e,
746                      struct xt_counters total[],
747                      unsigned int *i)
748 {
749         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
750
751         (*i)++;
752         return 0;
753 }
754
755 static inline int
756 set_entry_to_counter(const struct ipt_entry *e,
757                      struct ipt_counters total[],
758                      unsigned int *i)
759 {
760         SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
761
762         (*i)++;
763         return 0;
764 }
765
766 static void
767 get_counters(const struct xt_table_info *t,
768              struct xt_counters counters[])
769 {
770         unsigned int cpu;
771         unsigned int i;
772         unsigned int curcpu;
773
774         /* Instead of clearing (by a previous call to memset())
775          * the counters and using adds, we set the counters
776          * with data used by 'current' CPU
777          * We dont care about preemption here.
778          */
779         curcpu = raw_smp_processor_id();
780
781         i = 0;
782         IPT_ENTRY_ITERATE(t->entries[curcpu],
783                           t->size,
784                           set_entry_to_counter,
785                           counters,
786                           &i);
787
788         for_each_possible_cpu(cpu) {
789                 if (cpu == curcpu)
790                         continue;
791                 i = 0;
792                 IPT_ENTRY_ITERATE(t->entries[cpu],
793                                   t->size,
794                                   add_entry_to_counter,
795                                   counters,
796                                   &i);
797         }
798 }
799
800 static inline struct xt_counters * alloc_counters(struct ipt_table *table)
801 {
802         unsigned int countersize;
803         struct xt_counters *counters;
804         struct xt_table_info *private = table->private;
805
806         /* We need atomic snapshot of counters: rest doesn't change
807            (other than comefrom, which userspace doesn't care
808            about). */
809         countersize = sizeof(struct xt_counters) * private->number;
810         counters = vmalloc_node(countersize, numa_node_id());
811
812         if (counters == NULL)
813                 return ERR_PTR(-ENOMEM);
814
815         /* First, sum counters... */
816         write_lock_bh(&table->lock);
817         get_counters(private, counters);
818         write_unlock_bh(&table->lock);
819
820         return counters;
821 }
822
823 static int
824 copy_entries_to_user(unsigned int total_size,
825                      struct ipt_table *table,
826                      void __user *userptr)
827 {
828         unsigned int off, num;
829         struct ipt_entry *e;
830         struct xt_counters *counters;
831         struct xt_table_info *private = table->private;
832         int ret = 0;
833         void *loc_cpu_entry;
834
835         counters = alloc_counters(table);
836         if (IS_ERR(counters))
837                 return PTR_ERR(counters);
838
839         /* choose the copy that is on our node/cpu, ...
840          * This choice is lazy (because current thread is
841          * allowed to migrate to another cpu)
842          */
843         loc_cpu_entry = private->entries[raw_smp_processor_id()];
844         /* ... then copy entire thing ... */
845         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
846                 ret = -EFAULT;
847                 goto free_counters;
848         }
849
850         /* FIXME: use iterator macros --RR */
851         /* ... then go back and fix counters and names */
852         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
853                 unsigned int i;
854                 struct ipt_entry_match *m;
855                 struct ipt_entry_target *t;
856
857                 e = (struct ipt_entry *)(loc_cpu_entry + off);
858                 if (copy_to_user(userptr + off
859                                  + offsetof(struct ipt_entry, counters),
860                                  &counters[num],
861                                  sizeof(counters[num])) != 0) {
862                         ret = -EFAULT;
863                         goto free_counters;
864                 }
865
866                 for (i = sizeof(struct ipt_entry);
867                      i < e->target_offset;
868                      i += m->u.match_size) {
869                         m = (void *)e + i;
870
871                         if (copy_to_user(userptr + off + i
872                                          + offsetof(struct ipt_entry_match,
873                                                     u.user.name),
874                                          m->u.kernel.match->name,
875                                          strlen(m->u.kernel.match->name)+1)
876                             != 0) {
877                                 ret = -EFAULT;
878                                 goto free_counters;
879                         }
880                 }
881
882                 t = ipt_get_target(e);
883                 if (copy_to_user(userptr + off + e->target_offset
884                                  + offsetof(struct ipt_entry_target,
885                                             u.user.name),
886                                  t->u.kernel.target->name,
887                                  strlen(t->u.kernel.target->name)+1) != 0) {
888                         ret = -EFAULT;
889                         goto free_counters;
890                 }
891         }
892
893  free_counters:
894         vfree(counters);
895         return ret;
896 }
897
898 #ifdef CONFIG_COMPAT
899 struct compat_delta {
900         struct compat_delta *next;
901         u_int16_t offset;
902         short delta;
903 };
904
905 static struct compat_delta *compat_offsets = NULL;
906
907 static int compat_add_offset(u_int16_t offset, short delta)
908 {
909         struct compat_delta *tmp;
910
911         tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
912         if (!tmp)
913                 return -ENOMEM;
914         tmp->offset = offset;
915         tmp->delta = delta;
916         if (compat_offsets) {
917                 tmp->next = compat_offsets->next;
918                 compat_offsets->next = tmp;
919         } else {
920                 compat_offsets = tmp;
921                 tmp->next = NULL;
922         }
923         return 0;
924 }
925
926 static void compat_flush_offsets(void)
927 {
928         struct compat_delta *tmp, *next;
929
930         if (compat_offsets) {
931                 for(tmp = compat_offsets; tmp; tmp = next) {
932                         next = tmp->next;
933                         kfree(tmp);
934                 }
935                 compat_offsets = NULL;
936         }
937 }
938
939 static short compat_calc_jump(u_int16_t offset)
940 {
941         struct compat_delta *tmp;
942         short delta;
943
944         for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
945                 if (tmp->offset < offset)
946                         delta += tmp->delta;
947         return delta;
948 }
949
950 struct compat_ipt_standard_target
951 {
952         struct compat_xt_entry_target target;
953         compat_int_t verdict;
954 };
955
956 struct compat_ipt_standard
957 {
958         struct compat_ipt_entry entry;
959         struct compat_ipt_standard_target target;
960 };
961
962 #define IPT_ST_LEN              XT_ALIGN(sizeof(struct ipt_standard_target))
963 #define IPT_ST_COMPAT_LEN       COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target))
964 #define IPT_ST_OFFSET           (IPT_ST_LEN - IPT_ST_COMPAT_LEN)
965
966 static int compat_ipt_standard_fn(void *target,
967                 void **dstptr, int *size, int convert)
968 {
969         struct compat_ipt_standard_target compat_st, *pcompat_st;
970         struct ipt_standard_target st, *pst;
971         int ret;
972
973         ret = 0;
974         switch (convert) {
975                 case COMPAT_TO_USER:
976                         pst = target;
977                         memcpy(&compat_st.target, &pst->target,
978                                 sizeof(compat_st.target));
979                         compat_st.verdict = pst->verdict;
980                         if (compat_st.verdict > 0)
981                                 compat_st.verdict -=
982                                         compat_calc_jump(compat_st.verdict);
983                         compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN;
984                         if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN))
985                                 ret = -EFAULT;
986                         *size -= IPT_ST_OFFSET;
987                         *dstptr += IPT_ST_COMPAT_LEN;
988                         break;
989                 case COMPAT_FROM_USER:
990                         pcompat_st = target;
991                         memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN);
992                         st.verdict = pcompat_st->verdict;
993                         if (st.verdict > 0)
994                                 st.verdict += compat_calc_jump(st.verdict);
995                         st.target.u.user.target_size = IPT_ST_LEN;
996                         memcpy(*dstptr, &st, IPT_ST_LEN);
997                         *size += IPT_ST_OFFSET;
998                         *dstptr += IPT_ST_LEN;
999                         break;
1000                 case COMPAT_CALC_SIZE:
1001                         *size += IPT_ST_OFFSET;
1002                         break;
1003                 default:
1004                         ret = -ENOPROTOOPT;
1005                         break;
1006         }
1007         return ret;
1008 }
1009
1010 static inline int
1011 compat_calc_match(struct ipt_entry_match *m, int * size)
1012 {
1013         if (m->u.kernel.match->compat)
1014                 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1015         else
1016                 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1017         return 0;
1018 }
1019
1020 static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
1021                 void *base, struct xt_table_info *newinfo)
1022 {
1023         struct ipt_entry_target *t;
1024         u_int16_t entry_offset;
1025         int off, i, ret;
1026
1027         off = 0;
1028         entry_offset = (void *)e - base;
1029         IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1030         t = ipt_get_target(e);
1031         if (t->u.kernel.target->compat)
1032                 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1033         else
1034                 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1035         newinfo->size -= off;
1036         ret = compat_add_offset(entry_offset, off);
1037         if (ret)
1038                 return ret;
1039
1040         for (i = 0; i< NF_IP_NUMHOOKS; i++) {
1041                 if (info->hook_entry[i] && (e < (struct ipt_entry *)
1042                                 (base + info->hook_entry[i])))
1043                         newinfo->hook_entry[i] -= off;
1044                 if (info->underflow[i] && (e < (struct ipt_entry *)
1045                                 (base + info->underflow[i])))
1046                         newinfo->underflow[i] -= off;
1047         }
1048         return 0;
1049 }
1050
1051 static int compat_table_info(struct xt_table_info *info,
1052                 struct xt_table_info *newinfo)
1053 {
1054         void *loc_cpu_entry;
1055         int i;
1056
1057         if (!newinfo || !info)
1058                 return -EINVAL;
1059
1060         memset(newinfo, 0, sizeof(struct xt_table_info));
1061         newinfo->size = info->size;
1062         newinfo->number = info->number;
1063         for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1064                 newinfo->hook_entry[i] = info->hook_entry[i];
1065                 newinfo->underflow[i] = info->underflow[i];
1066         }
1067         loc_cpu_entry = info->entries[raw_smp_processor_id()];
1068         return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1069                         compat_calc_entry, info, loc_cpu_entry, newinfo);
1070 }
1071 #endif
1072
1073 static int get_info(void __user *user, int *len, int compat)
1074 {
1075         char name[IPT_TABLE_MAXNAMELEN];
1076         struct ipt_table *t;
1077         int ret;
1078
1079         if (*len != sizeof(struct ipt_getinfo)) {
1080                 duprintf("length %u != %u\n", *len,
1081                         (unsigned int)sizeof(struct ipt_getinfo));
1082                 return -EINVAL;
1083         }
1084
1085         if (copy_from_user(name, user, sizeof(name)) != 0)
1086                 return -EFAULT;
1087
1088         name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1089 #ifdef CONFIG_COMPAT
1090         if (compat)
1091                 xt_compat_lock(AF_INET);
1092 #endif
1093         t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1094                         "iptable_%s", name);
1095         if (t && !IS_ERR(t)) {
1096                 struct ipt_getinfo info;
1097                 struct xt_table_info *private = t->private;
1098
1099 #ifdef CONFIG_COMPAT
1100                 if (compat) {
1101                         struct xt_table_info tmp;
1102                         ret = compat_table_info(private, &tmp);
1103                         compat_flush_offsets();
1104                         private =  &tmp;
1105                 }
1106 #endif
1107                 info.valid_hooks = t->valid_hooks;
1108                 memcpy(info.hook_entry, private->hook_entry,
1109                                 sizeof(info.hook_entry));
1110                 memcpy(info.underflow, private->underflow,
1111                                 sizeof(info.underflow));
1112                 info.num_entries = private->number;
1113                 info.size = private->size;
1114                 strcpy(info.name, name);
1115
1116                 if (copy_to_user(user, &info, *len) != 0)
1117                         ret = -EFAULT;
1118                 else
1119                         ret = 0;
1120
1121                 xt_table_unlock(t);
1122                 module_put(t->me);
1123         } else
1124                 ret = t ? PTR_ERR(t) : -ENOENT;
1125 #ifdef CONFIG_COMPAT
1126         if (compat)
1127                 xt_compat_unlock(AF_INET);
1128 #endif
1129         return ret;
1130 }
1131
1132 static int
1133 get_entries(struct ipt_get_entries __user *uptr, int *len)
1134 {
1135         int ret;
1136         struct ipt_get_entries get;
1137         struct ipt_table *t;
1138
1139         if (*len < sizeof(get)) {
1140                 duprintf("get_entries: %u < %d\n", *len,
1141                                 (unsigned int)sizeof(get));
1142                 return -EINVAL;
1143         }
1144         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1145                 return -EFAULT;
1146         if (*len != sizeof(struct ipt_get_entries) + get.size) {
1147                 duprintf("get_entries: %u != %u\n", *len,
1148                                 (unsigned int)(sizeof(struct ipt_get_entries) +
1149                                 get.size));
1150                 return -EINVAL;
1151         }
1152
1153         t = xt_find_table_lock(AF_INET, get.name);
1154         if (t && !IS_ERR(t)) {
1155                 struct xt_table_info *private = t->private;
1156                 duprintf("t->private->number = %u\n",
1157                          private->number);
1158                 if (get.size == private->size)
1159                         ret = copy_entries_to_user(private->size,
1160                                                    t, uptr->entrytable);
1161                 else {
1162                         duprintf("get_entries: I've got %u not %u!\n",
1163                                  private->size,
1164                                  get.size);
1165                         ret = -EINVAL;
1166                 }
1167                 module_put(t->me);
1168                 xt_table_unlock(t);
1169         } else
1170                 ret = t ? PTR_ERR(t) : -ENOENT;
1171
1172         return ret;
1173 }
1174
1175 static int
1176 __do_replace(const char *name, unsigned int valid_hooks,
1177                 struct xt_table_info *newinfo, unsigned int num_counters,
1178                 void __user *counters_ptr)
1179 {
1180         int ret;
1181         struct ipt_table *t;
1182         struct xt_table_info *oldinfo;
1183         struct xt_counters *counters;
1184         void *loc_cpu_old_entry;
1185
1186         ret = 0;
1187         counters = vmalloc(num_counters * sizeof(struct xt_counters));
1188         if (!counters) {
1189                 ret = -ENOMEM;
1190                 goto out;
1191         }
1192
1193         t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1194                                     "iptable_%s", name);
1195         if (!t || IS_ERR(t)) {
1196                 ret = t ? PTR_ERR(t) : -ENOENT;
1197                 goto free_newinfo_counters_untrans;
1198         }
1199
1200         /* You lied! */
1201         if (valid_hooks != t->valid_hooks) {
1202                 duprintf("Valid hook crap: %08X vs %08X\n",
1203                          valid_hooks, t->valid_hooks);
1204                 ret = -EINVAL;
1205                 goto put_module;
1206         }
1207
1208         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1209         if (!oldinfo)
1210                 goto put_module;
1211
1212         /* Update module usage count based on number of rules */
1213         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1214                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1215         if ((oldinfo->number > oldinfo->initial_entries) ||
1216             (newinfo->number <= oldinfo->initial_entries))
1217                 module_put(t->me);
1218         if ((oldinfo->number > oldinfo->initial_entries) &&
1219             (newinfo->number <= oldinfo->initial_entries))
1220                 module_put(t->me);
1221
1222         /* Get the old counters. */
1223         get_counters(oldinfo, counters);
1224         /* Decrease module usage counts and free resource */
1225         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1226         IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1227         xt_free_table_info(oldinfo);
1228         if (copy_to_user(counters_ptr, counters,
1229                          sizeof(struct xt_counters) * num_counters) != 0)
1230                 ret = -EFAULT;
1231         vfree(counters);
1232         xt_table_unlock(t);
1233         return ret;
1234
1235  put_module:
1236         module_put(t->me);
1237         xt_table_unlock(t);
1238  free_newinfo_counters_untrans:
1239         vfree(counters);
1240  out:
1241         return ret;
1242 }
1243
1244 static int
1245 do_replace(void __user *user, unsigned int len)
1246 {
1247         int ret;
1248         struct ipt_replace tmp;
1249         struct xt_table_info *newinfo;
1250         void *loc_cpu_entry;
1251
1252         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1253                 return -EFAULT;
1254
1255         /* Hack: Causes ipchains to give correct error msg --RR */
1256         if (len != sizeof(tmp) + tmp.size)
1257                 return -ENOPROTOOPT;
1258
1259         /* overflow check */
1260         if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1261                         SMP_CACHE_BYTES)
1262                 return -ENOMEM;
1263         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1264                 return -ENOMEM;
1265
1266         newinfo = xt_alloc_table_info(tmp.size);
1267         if (!newinfo)
1268                 return -ENOMEM;
1269
1270         /* choose the copy that is our node/cpu */
1271         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1272         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1273                            tmp.size) != 0) {
1274                 ret = -EFAULT;
1275                 goto free_newinfo;
1276         }
1277
1278         ret = translate_table(tmp.name, tmp.valid_hooks,
1279                               newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1280                               tmp.hook_entry, tmp.underflow);
1281         if (ret != 0)
1282                 goto free_newinfo;
1283
1284         duprintf("ip_tables: Translated table\n");
1285
1286         ret = __do_replace(tmp.name, tmp.valid_hooks,
1287                               newinfo, tmp.num_counters,
1288                               tmp.counters);
1289         if (ret)
1290                 goto free_newinfo_untrans;
1291         return 0;
1292
1293  free_newinfo_untrans:
1294         IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1295  free_newinfo:
1296         xt_free_table_info(newinfo);
1297         return ret;
1298 }
1299
1300 /* We're lazy, and add to the first CPU; overflow works its fey magic
1301  * and everything is OK. */
1302 static inline int
1303 add_counter_to_entry(struct ipt_entry *e,
1304                      const struct xt_counters addme[],
1305                      unsigned int *i)
1306 {
1307 #if 0
1308         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1309                  *i,
1310                  (long unsigned int)e->counters.pcnt,
1311                  (long unsigned int)e->counters.bcnt,
1312                  (long unsigned int)addme[*i].pcnt,
1313                  (long unsigned int)addme[*i].bcnt);
1314 #endif
1315
1316         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1317
1318         (*i)++;
1319         return 0;
1320 }
1321
1322 static int
1323 do_add_counters(void __user *user, unsigned int len, int compat)
1324 {
1325         unsigned int i;
1326         struct xt_counters_info tmp;
1327         struct xt_counters *paddc;
1328         unsigned int num_counters;
1329         char *name;
1330         int size;
1331         void *ptmp;
1332         struct ipt_table *t;
1333         struct xt_table_info *private;
1334         int ret = 0;
1335         void *loc_cpu_entry;
1336 #ifdef CONFIG_COMPAT
1337         struct compat_xt_counters_info compat_tmp;
1338
1339         if (compat) {
1340                 ptmp = &compat_tmp;
1341                 size = sizeof(struct compat_xt_counters_info);
1342         } else
1343 #endif
1344         {
1345                 ptmp = &tmp;
1346                 size = sizeof(struct xt_counters_info);
1347         }
1348
1349         if (copy_from_user(ptmp, user, size) != 0)
1350                 return -EFAULT;
1351
1352 #ifdef CONFIG_COMPAT
1353         if (compat) {
1354                 num_counters = compat_tmp.num_counters;
1355                 name = compat_tmp.name;
1356         } else
1357 #endif
1358         {
1359                 num_counters = tmp.num_counters;
1360                 name = tmp.name;
1361         }
1362
1363         if (len != size + num_counters * sizeof(struct xt_counters))
1364                 return -EINVAL;
1365
1366         paddc = vmalloc_node(len - size, numa_node_id());
1367         if (!paddc)
1368                 return -ENOMEM;
1369
1370         if (copy_from_user(paddc, user + size, len - size) != 0) {
1371                 ret = -EFAULT;
1372                 goto free;
1373         }
1374
1375         t = xt_find_table_lock(AF_INET, name);
1376         if (!t || IS_ERR(t)) {
1377                 ret = t ? PTR_ERR(t) : -ENOENT;
1378                 goto free;
1379         }
1380
1381         write_lock_bh(&t->lock);
1382         private = t->private;
1383         if (private->number != num_counters) {
1384                 ret = -EINVAL;
1385                 goto unlock_up_free;
1386         }
1387
1388         i = 0;
1389         /* Choose the copy that is on our node */
1390         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1391         IPT_ENTRY_ITERATE(loc_cpu_entry,
1392                           private->size,
1393                           add_counter_to_entry,
1394                           paddc,
1395                           &i);
1396  unlock_up_free:
1397         write_unlock_bh(&t->lock);
1398         xt_table_unlock(t);
1399         module_put(t->me);
1400  free:
1401         vfree(paddc);
1402
1403         return ret;
1404 }
1405
1406 #ifdef CONFIG_COMPAT
1407 struct compat_ipt_replace {
1408         char                    name[IPT_TABLE_MAXNAMELEN];
1409         u32                     valid_hooks;
1410         u32                     num_entries;
1411         u32                     size;
1412         u32                     hook_entry[NF_IP_NUMHOOKS];
1413         u32                     underflow[NF_IP_NUMHOOKS];
1414         u32                     num_counters;
1415         compat_uptr_t           counters;       /* struct ipt_counters * */
1416         struct compat_ipt_entry entries[0];
1417 };
1418
1419 static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1420                 void __user **dstptr, compat_uint_t *size)
1421 {
1422         if (m->u.kernel.match->compat)
1423                 return m->u.kernel.match->compat(m, dstptr, size,
1424                                 COMPAT_TO_USER);
1425         else
1426                 return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
1427 }
1428
1429 static int compat_copy_entry_to_user(struct ipt_entry *e,
1430                 void __user **dstptr, compat_uint_t *size)
1431 {
1432         struct ipt_entry_target __user *t;
1433         struct compat_ipt_entry __user *ce;
1434         u_int16_t target_offset, next_offset;
1435         compat_uint_t origsize;
1436         int ret;
1437
1438         ret = -EFAULT;
1439         origsize = *size;
1440         ce = (struct compat_ipt_entry __user *)*dstptr;
1441         if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1442                 goto out;
1443
1444         *dstptr += sizeof(struct compat_ipt_entry);
1445         ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1446         target_offset = e->target_offset - (origsize - *size);
1447         if (ret)
1448                 goto out;
1449         t = ipt_get_target(e);
1450         if (t->u.kernel.target->compat)
1451                 ret = t->u.kernel.target->compat(t, dstptr, size,
1452                                 COMPAT_TO_USER);
1453         else
1454                 ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
1455         if (ret)
1456                 goto out;
1457         ret = -EFAULT;
1458         next_offset = e->next_offset - (origsize - *size);
1459         if (put_user(target_offset, &ce->target_offset))
1460                 goto out;
1461         if (put_user(next_offset, &ce->next_offset))
1462                 goto out;
1463         return 0;
1464 out:
1465         return ret;
1466 }
1467
1468 static inline int
1469 compat_check_calc_match(struct ipt_entry_match *m,
1470             const char *name,
1471             const struct ipt_ip *ip,
1472             unsigned int hookmask,
1473             int *size, int *i)
1474 {
1475         struct ipt_match *match;
1476
1477         match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1478                                                    m->u.user.revision),
1479                                         "ipt_%s", m->u.user.name);
1480         if (IS_ERR(match) || !match) {
1481                 duprintf("compat_check_calc_match: `%s' not found\n",
1482                                 m->u.user.name);
1483                 return match ? PTR_ERR(match) : -ENOENT;
1484         }
1485         m->u.kernel.match = match;
1486
1487         if (m->u.kernel.match->compat)
1488                 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1489         else
1490                 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1491
1492         (*i)++;
1493         return 0;
1494 }
1495
1496 static inline int
1497 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1498                            struct xt_table_info *newinfo,
1499                            unsigned int *size,
1500                            unsigned char *base,
1501                            unsigned char *limit,
1502                            unsigned int *hook_entries,
1503                            unsigned int *underflows,
1504                            unsigned int *i,
1505                            const char *name)
1506 {
1507         struct ipt_entry_target *t;
1508         struct ipt_target *target;
1509         u_int16_t entry_offset;
1510         int ret, off, h, j;
1511
1512         duprintf("check_compat_entry_size_and_hooks %p\n", e);
1513         if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1514             || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1515                 duprintf("Bad offset %p, limit = %p\n", e, limit);
1516                 return -EINVAL;
1517         }
1518
1519         if (e->next_offset < sizeof(struct compat_ipt_entry) +
1520                         sizeof(struct compat_xt_entry_target)) {
1521                 duprintf("checking: element %p size %u\n",
1522                          e, e->next_offset);
1523                 return -EINVAL;
1524         }
1525
1526         if (!ip_checkentry(&e->ip)) {
1527                 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
1528                 return -EINVAL;
1529         }
1530
1531         off = 0;
1532         entry_offset = (void *)e - (void *)base;
1533         j = 0;
1534         ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1535                         e->comefrom, &off, &j);
1536         if (ret != 0)
1537                 goto out;
1538
1539         t = ipt_get_target(e);
1540         target = try_then_request_module(xt_find_target(AF_INET,
1541                                                      t->u.user.name,
1542                                                      t->u.user.revision),
1543                                          "ipt_%s", t->u.user.name);
1544         if (IS_ERR(target) || !target) {
1545                 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1546                 ret = target ? PTR_ERR(target) : -ENOENT;
1547                 goto out;
1548         }
1549         t->u.kernel.target = target;
1550
1551         if (t->u.kernel.target->compat)
1552                 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1553         else
1554                 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1555         *size += off;
1556         ret = compat_add_offset(entry_offset, off);
1557         if (ret)
1558                 goto out;
1559
1560         /* Check hooks & underflows */
1561         for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1562                 if ((unsigned char *)e - base == hook_entries[h])
1563                         newinfo->hook_entry[h] = hook_entries[h];
1564                 if ((unsigned char *)e - base == underflows[h])
1565                         newinfo->underflow[h] = underflows[h];
1566         }
1567
1568         /* Clear counters and comefrom */
1569         e->counters = ((struct ipt_counters) { 0, 0 });
1570         e->comefrom = 0;
1571
1572         (*i)++;
1573         return 0;
1574 out:
1575         IPT_MATCH_ITERATE(e, cleanup_match, &j);
1576         return ret;
1577 }
1578
1579 static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1580         void **dstptr, compat_uint_t *size, const char *name,
1581         const struct ipt_ip *ip, unsigned int hookmask)
1582 {
1583         struct ipt_entry_match *dm;
1584         struct ipt_match *match;
1585         int ret;
1586
1587         dm = (struct ipt_entry_match *)*dstptr;
1588         match = m->u.kernel.match;
1589         if (match->compat)
1590                 match->compat(m, dstptr, size, COMPAT_FROM_USER);
1591         else
1592                 xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
1593
1594         ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1595                              name, hookmask, ip->proto,
1596                              ip->invflags & IPT_INV_PROTO);
1597         if (ret)
1598                 return ret;
1599
1600         if (m->u.kernel.match->checkentry
1601             && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
1602                                               dm->u.match_size - sizeof(*dm),
1603                                               hookmask)) {
1604                 duprintf("ip_tables: check failed for `%s'.\n",
1605                          m->u.kernel.match->name);
1606                 return -EINVAL;
1607         }
1608         return 0;
1609 }
1610
1611 static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1612         unsigned int *size, const char *name,
1613         struct xt_table_info *newinfo, unsigned char *base)
1614 {
1615         struct ipt_entry_target *t;
1616         struct ipt_target *target;
1617         struct ipt_entry *de;
1618         unsigned int origsize;
1619         int ret, h;
1620
1621         ret = 0;
1622         origsize = *size;
1623         de = (struct ipt_entry *)*dstptr;
1624         memcpy(de, e, sizeof(struct ipt_entry));
1625
1626         *dstptr += sizeof(struct compat_ipt_entry);
1627         ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1628                         name, &de->ip, de->comefrom);
1629         if (ret)
1630                 goto out;
1631         de->target_offset = e->target_offset - (origsize - *size);
1632         t = ipt_get_target(e);
1633         target = t->u.kernel.target;
1634         if (target->compat)
1635                 target->compat(t, dstptr, size, COMPAT_FROM_USER);
1636         else
1637                 xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
1638
1639         de->next_offset = e->next_offset - (origsize - *size);
1640         for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1641                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1642                         newinfo->hook_entry[h] -= origsize - *size;
1643                 if ((unsigned char *)de - base < newinfo->underflow[h])
1644                         newinfo->underflow[h] -= origsize - *size;
1645         }
1646
1647         t = ipt_get_target(de);
1648         target = t->u.kernel.target;
1649         ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
1650                               name, e->comefrom, e->ip.proto,
1651                               e->ip.invflags & IPT_INV_PROTO);
1652         if (ret)
1653                 goto out;
1654
1655         ret = -EINVAL;
1656         if (t->u.kernel.target == &ipt_standard_target) {
1657                 if (!standard_check(t, *size))
1658                         goto out;
1659         } else if (t->u.kernel.target->checkentry
1660                    && !t->u.kernel.target->checkentry(name, de, target,
1661                                 t->data, t->u.target_size - sizeof(*t),
1662                                 de->comefrom)) {
1663                 duprintf("ip_tables: compat: check failed for `%s'.\n",
1664                          t->u.kernel.target->name);
1665                 goto out;
1666         }
1667         ret = 0;
1668 out:
1669         return ret;
1670 }
1671
1672 static int
1673 translate_compat_table(const char *name,
1674                 unsigned int valid_hooks,
1675                 struct xt_table_info **pinfo,
1676                 void **pentry0,
1677                 unsigned int total_size,
1678                 unsigned int number,
1679                 unsigned int *hook_entries,
1680                 unsigned int *underflows)
1681 {
1682         unsigned int i;
1683         struct xt_table_info *newinfo, *info;
1684         void *pos, *entry0, *entry1;
1685         unsigned int size;
1686         int ret;
1687
1688         info = *pinfo;
1689         entry0 = *pentry0;
1690         size = total_size;
1691         info->number = number;
1692
1693         /* Init all hooks to impossible value. */
1694         for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1695                 info->hook_entry[i] = 0xFFFFFFFF;
1696                 info->underflow[i] = 0xFFFFFFFF;
1697         }
1698
1699         duprintf("translate_compat_table: size %u\n", info->size);
1700         i = 0;
1701         xt_compat_lock(AF_INET);
1702         /* Walk through entries, checking offsets. */
1703         ret = IPT_ENTRY_ITERATE(entry0, total_size,
1704                                 check_compat_entry_size_and_hooks,
1705                                 info, &size, entry0,
1706                                 entry0 + total_size,
1707                                 hook_entries, underflows, &i, name);
1708         if (ret != 0)
1709                 goto out_unlock;
1710
1711         ret = -EINVAL;
1712         if (i != number) {
1713                 duprintf("translate_compat_table: %u not %u entries\n",
1714                          i, number);
1715                 goto out_unlock;
1716         }
1717
1718         /* Check hooks all assigned */
1719         for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1720                 /* Only hooks which are valid */
1721                 if (!(valid_hooks & (1 << i)))
1722                         continue;
1723                 if (info->hook_entry[i] == 0xFFFFFFFF) {
1724                         duprintf("Invalid hook entry %u %u\n",
1725                                  i, hook_entries[i]);
1726                         goto out_unlock;
1727                 }
1728                 if (info->underflow[i] == 0xFFFFFFFF) {
1729                         duprintf("Invalid underflow %u %u\n",
1730                                  i, underflows[i]);
1731                         goto out_unlock;
1732                 }
1733         }
1734
1735         ret = -ENOMEM;
1736         newinfo = xt_alloc_table_info(size);
1737         if (!newinfo)
1738                 goto out_unlock;
1739
1740         newinfo->number = number;
1741         for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1742                 newinfo->hook_entry[i] = info->hook_entry[i];
1743                 newinfo->underflow[i] = info->underflow[i];
1744         }
1745         entry1 = newinfo->entries[raw_smp_processor_id()];
1746         pos = entry1;
1747         size =  total_size;
1748         ret = IPT_ENTRY_ITERATE(entry0, total_size,
1749                         compat_copy_entry_from_user, &pos, &size,
1750                         name, newinfo, entry1);
1751         compat_flush_offsets();
1752         xt_compat_unlock(AF_INET);
1753         if (ret)
1754                 goto free_newinfo;
1755
1756         ret = -ELOOP;
1757         if (!mark_source_chains(newinfo, valid_hooks, entry1))
1758                 goto free_newinfo;
1759
1760         /* And one copy for every other CPU */
1761         for_each_possible_cpu(i)
1762                 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1763                         memcpy(newinfo->entries[i], entry1, newinfo->size);
1764
1765         *pinfo = newinfo;
1766         *pentry0 = entry1;
1767         xt_free_table_info(info);
1768         return 0;
1769
1770 free_newinfo:
1771         xt_free_table_info(newinfo);
1772 out:
1773         return ret;
1774 out_unlock:
1775         xt_compat_unlock(AF_INET);
1776         goto out;
1777 }
1778
1779 static int
1780 compat_do_replace(void __user *user, unsigned int len)
1781 {
1782         int ret;
1783         struct compat_ipt_replace tmp;
1784         struct xt_table_info *newinfo;
1785         void *loc_cpu_entry;
1786
1787         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1788                 return -EFAULT;
1789
1790         /* Hack: Causes ipchains to give correct error msg --RR */
1791         if (len != sizeof(tmp) + tmp.size)
1792                 return -ENOPROTOOPT;
1793
1794         /* overflow check */
1795         if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1796                         SMP_CACHE_BYTES)
1797                 return -ENOMEM;
1798         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1799                 return -ENOMEM;
1800
1801         newinfo = xt_alloc_table_info(tmp.size);
1802         if (!newinfo)
1803                 return -ENOMEM;
1804
1805         /* choose the copy that is our node/cpu */
1806         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1807         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1808                            tmp.size) != 0) {
1809                 ret = -EFAULT;
1810                 goto free_newinfo;
1811         }
1812
1813         ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1814                               &newinfo, &loc_cpu_entry, tmp.size,
1815                               tmp.num_entries, tmp.hook_entry, tmp.underflow);
1816         if (ret != 0)
1817                 goto free_newinfo;
1818
1819         duprintf("compat_do_replace: Translated table\n");
1820
1821         ret = __do_replace(tmp.name, tmp.valid_hooks,
1822                               newinfo, tmp.num_counters,
1823                               compat_ptr(tmp.counters));
1824         if (ret)
1825                 goto free_newinfo_untrans;
1826         return 0;
1827
1828  free_newinfo_untrans:
1829         IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1830  free_newinfo:
1831         xt_free_table_info(newinfo);
1832         return ret;
1833 }
1834
1835 static int
1836 compat_do_ipt_set_ctl(struct sock *sk,  int cmd, void __user *user,
1837                 unsigned int len)
1838 {
1839         int ret;
1840
1841         if (!capable(CAP_NET_ADMIN))
1842                 return -EPERM;
1843
1844         switch (cmd) {
1845         case IPT_SO_SET_REPLACE:
1846                 ret = compat_do_replace(user, len);
1847                 break;
1848
1849         case IPT_SO_SET_ADD_COUNTERS:
1850                 ret = do_add_counters(user, len, 1);
1851                 break;
1852
1853         default:
1854                 duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
1855                 ret = -EINVAL;
1856         }
1857
1858         return ret;
1859 }
1860
1861 struct compat_ipt_get_entries
1862 {
1863         char name[IPT_TABLE_MAXNAMELEN];
1864         compat_uint_t size;
1865         struct compat_ipt_entry entrytable[0];
1866 };
1867
1868 static int compat_copy_entries_to_user(unsigned int total_size,
1869                      struct ipt_table *table, void __user *userptr)
1870 {
1871         unsigned int off, num;
1872         struct compat_ipt_entry e;
1873         struct xt_counters *counters;
1874         struct xt_table_info *private = table->private;
1875         void __user *pos;
1876         unsigned int size;
1877         int ret = 0;
1878         void *loc_cpu_entry;
1879
1880         counters = alloc_counters(table);
1881         if (IS_ERR(counters))
1882                 return PTR_ERR(counters);
1883
1884         /* choose the copy that is on our node/cpu, ...
1885          * This choice is lazy (because current thread is
1886          * allowed to migrate to another cpu)
1887          */
1888         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1889         pos = userptr;
1890         size = total_size;
1891         ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1892                         compat_copy_entry_to_user, &pos, &size);
1893         if (ret)
1894                 goto free_counters;
1895
1896         /* ... then go back and fix counters and names */
1897         for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1898                 unsigned int i;
1899                 struct ipt_entry_match m;
1900                 struct ipt_entry_target t;
1901
1902                 ret = -EFAULT;
1903                 if (copy_from_user(&e, userptr + off,
1904                                         sizeof(struct compat_ipt_entry)))
1905                         goto free_counters;
1906                 if (copy_to_user(userptr + off +
1907                         offsetof(struct compat_ipt_entry, counters),
1908                          &counters[num], sizeof(counters[num])))
1909                         goto free_counters;
1910
1911                 for (i = sizeof(struct compat_ipt_entry);
1912                                 i < e.target_offset; i += m.u.match_size) {
1913                         if (copy_from_user(&m, userptr + off + i,
1914                                         sizeof(struct ipt_entry_match)))
1915                                 goto free_counters;
1916                         if (copy_to_user(userptr + off + i +
1917                                 offsetof(struct ipt_entry_match, u.user.name),
1918                                 m.u.kernel.match->name,
1919                                 strlen(m.u.kernel.match->name) + 1))
1920                                 goto free_counters;
1921                 }
1922
1923                 if (copy_from_user(&t, userptr + off + e.target_offset,
1924                                         sizeof(struct ipt_entry_target)))
1925                         goto free_counters;
1926                 if (copy_to_user(userptr + off + e.target_offset +
1927                         offsetof(struct ipt_entry_target, u.user.name),
1928                         t.u.kernel.target->name,
1929                         strlen(t.u.kernel.target->name) + 1))
1930                         goto free_counters;
1931         }
1932         ret = 0;
1933 free_counters:
1934         vfree(counters);
1935         return ret;
1936 }
1937
1938 static int
1939 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1940 {
1941         int ret;
1942         struct compat_ipt_get_entries get;
1943         struct ipt_table *t;
1944
1945
1946         if (*len < sizeof(get)) {
1947                 duprintf("compat_get_entries: %u < %u\n",
1948                                 *len, (unsigned int)sizeof(get));
1949                 return -EINVAL;
1950         }
1951
1952         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1953                 return -EFAULT;
1954
1955         if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1956                 duprintf("compat_get_entries: %u != %u\n", *len,
1957                         (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1958                         get.size));
1959                 return -EINVAL;
1960         }
1961
1962         xt_compat_lock(AF_INET);
1963         t = xt_find_table_lock(AF_INET, get.name);
1964         if (t && !IS_ERR(t)) {
1965                 struct xt_table_info *private = t->private;
1966                 struct xt_table_info info;
1967                 duprintf("t->private->number = %u\n",
1968                          private->number);
1969                 ret = compat_table_info(private, &info);
1970                 if (!ret && get.size == info.size) {
1971                         ret = compat_copy_entries_to_user(private->size,
1972                                                    t, uptr->entrytable);
1973                 } else if (!ret) {
1974                         duprintf("compat_get_entries: I've got %u not %u!\n",
1975                                  private->size,
1976                                  get.size);
1977                         ret = -EINVAL;
1978                 }
1979                 compat_flush_offsets();
1980                 module_put(t->me);
1981                 xt_table_unlock(t);
1982         } else
1983                 ret = t ? PTR_ERR(t) : -ENOENT;
1984
1985         xt_compat_unlock(AF_INET);
1986         return ret;
1987 }
1988
1989 static int
1990 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1991 {
1992         int ret;
1993
1994         switch (cmd) {
1995         case IPT_SO_GET_INFO:
1996                 ret = get_info(user, len, 1);
1997                 break;
1998         case IPT_SO_GET_ENTRIES:
1999                 ret = compat_get_entries(user, len);
2000                 break;
2001         default:
2002                 duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd);
2003                 ret = -EINVAL;
2004         }
2005         return ret;
2006 }
2007 #endif
2008
2009 static int
2010 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2011 {
2012         int ret;
2013
2014         if (!capable(CAP_NET_ADMIN))
2015                 return -EPERM;
2016
2017         switch (cmd) {
2018         case IPT_SO_SET_REPLACE:
2019                 ret = do_replace(user, len);
2020                 break;
2021
2022         case IPT_SO_SET_ADD_COUNTERS:
2023                 ret = do_add_counters(user, len, 0);
2024                 break;
2025
2026         default:
2027                 duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
2028                 ret = -EINVAL;
2029         }
2030
2031         return ret;
2032 }
2033
2034 static int
2035 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2036 {
2037         int ret;
2038
2039         if (!capable(CAP_NET_ADMIN))
2040                 return -EPERM;
2041
2042         switch (cmd) {
2043         case IPT_SO_GET_INFO:
2044                 ret = get_info(user, len, 0);
2045                 break;
2046
2047         case IPT_SO_GET_ENTRIES:
2048                 ret = get_entries(user, len);
2049                 break;
2050
2051         case IPT_SO_GET_REVISION_MATCH:
2052         case IPT_SO_GET_REVISION_TARGET: {
2053                 struct ipt_get_revision rev;
2054                 int target;
2055
2056                 if (*len != sizeof(rev)) {
2057                         ret = -EINVAL;
2058                         break;
2059                 }
2060                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2061                         ret = -EFAULT;
2062                         break;
2063                 }
2064
2065                 if (cmd == IPT_SO_GET_REVISION_TARGET)
2066                         target = 1;
2067                 else
2068                         target = 0;
2069
2070                 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2071                                                          rev.revision,
2072                                                          target, &ret),
2073                                         "ipt_%s", rev.name);
2074                 break;
2075         }
2076
2077         default:
2078                 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2079                 ret = -EINVAL;
2080         }
2081
2082         return ret;
2083 }
2084
2085 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2086 {
2087         int ret;
2088         struct xt_table_info *newinfo;
2089         static struct xt_table_info bootstrap
2090                 = { 0, 0, 0, { 0 }, { 0 }, { } };
2091         void *loc_cpu_entry;
2092
2093         newinfo = xt_alloc_table_info(repl->size);
2094         if (!newinfo)
2095                 return -ENOMEM;
2096
2097         /* choose the copy on our node/cpu
2098          * but dont care of preemption
2099          */
2100         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2101         memcpy(loc_cpu_entry, repl->entries, repl->size);
2102
2103         ret = translate_table(table->name, table->valid_hooks,
2104                               newinfo, loc_cpu_entry, repl->size,
2105                               repl->num_entries,
2106                               repl->hook_entry,
2107                               repl->underflow);
2108         if (ret != 0) {
2109                 xt_free_table_info(newinfo);
2110                 return ret;
2111         }
2112
2113         ret = xt_register_table(table, &bootstrap, newinfo);
2114         if (ret != 0) {
2115                 xt_free_table_info(newinfo);
2116                 return ret;
2117         }
2118
2119         return 0;
2120 }
2121
2122 void ipt_unregister_table(struct ipt_table *table)
2123 {
2124         struct xt_table_info *private;
2125         void *loc_cpu_entry;
2126
2127         private = xt_unregister_table(table);
2128
2129         /* Decrease module usage counts and free resources */
2130         loc_cpu_entry = private->entries[raw_smp_processor_id()];
2131         IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2132         xt_free_table_info(private);
2133 }
2134
2135 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2136 static inline int
2137 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2138                      u_int8_t type, u_int8_t code,
2139                      int invert)
2140 {
2141         return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2142                 ^ invert;
2143 }
2144
2145 static int
2146 icmp_match(const struct sk_buff *skb,
2147            const struct net_device *in,
2148            const struct net_device *out,
2149            const struct xt_match *match,
2150            const void *matchinfo,
2151            int offset,
2152            unsigned int protoff,
2153            int *hotdrop)
2154 {
2155         struct icmphdr _icmph, *ic;
2156         const struct ipt_icmp *icmpinfo = matchinfo;
2157
2158         /* Must not be a fragment. */
2159         if (offset)
2160                 return 0;
2161
2162         ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2163         if (ic == NULL) {
2164                 /* We've been asked to examine this packet, and we
2165                  * can't.  Hence, no choice but to drop.
2166                  */
2167                 duprintf("Dropping evil ICMP tinygram.\n");
2168                 *hotdrop = 1;
2169                 return 0;
2170         }
2171
2172         return icmp_type_code_match(icmpinfo->type,
2173                                     icmpinfo->code[0],
2174                                     icmpinfo->code[1],
2175                                     ic->type, ic->code,
2176                                     !!(icmpinfo->invflags&IPT_ICMP_INV));
2177 }
2178
2179 /* Called when user tries to insert an entry of this type. */
2180 static int
2181 icmp_checkentry(const char *tablename,
2182            const void *info,
2183            const struct xt_match *match,
2184            void *matchinfo,
2185            unsigned int matchsize,
2186            unsigned int hook_mask)
2187 {
2188         const struct ipt_icmp *icmpinfo = matchinfo;
2189
2190         /* Must specify no unknown invflags */
2191         return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2192 }
2193
2194 /* The built-in targets: standard (NULL) and error. */
2195 static struct ipt_target ipt_standard_target = {
2196         .name           = IPT_STANDARD_TARGET,
2197         .targetsize     = sizeof(int),
2198         .family         = AF_INET,
2199 #ifdef CONFIG_COMPAT
2200         .compat         = &compat_ipt_standard_fn,
2201 #endif
2202 };
2203
2204 static struct ipt_target ipt_error_target = {
2205         .name           = IPT_ERROR_TARGET,
2206         .target         = ipt_error,
2207         .targetsize     = IPT_FUNCTION_MAXNAMELEN,
2208         .family         = AF_INET,
2209 };
2210
2211 static struct nf_sockopt_ops ipt_sockopts = {
2212         .pf             = PF_INET,
2213         .set_optmin     = IPT_BASE_CTL,
2214         .set_optmax     = IPT_SO_SET_MAX+1,
2215         .set            = do_ipt_set_ctl,
2216 #ifdef CONFIG_COMPAT
2217         .compat_set     = compat_do_ipt_set_ctl,
2218 #endif
2219         .get_optmin     = IPT_BASE_CTL,
2220         .get_optmax     = IPT_SO_GET_MAX+1,
2221         .get            = do_ipt_get_ctl,
2222 #ifdef CONFIG_COMPAT
2223         .compat_get     = compat_do_ipt_get_ctl,
2224 #endif
2225 };
2226
2227 static struct ipt_match icmp_matchstruct = {
2228         .name           = "icmp",
2229         .match          = icmp_match,
2230         .matchsize      = sizeof(struct ipt_icmp),
2231         .proto          = IPPROTO_ICMP,
2232         .family         = AF_INET,
2233         .checkentry     = icmp_checkentry,
2234 };
2235
2236 static int __init ip_tables_init(void)
2237 {
2238         int ret;
2239
2240         ret = xt_proto_init(AF_INET);
2241         if (ret < 0)
2242                 goto err1;
2243
2244         /* Noone else will be downing sem now, so we won't sleep */
2245         ret = xt_register_target(&ipt_standard_target);
2246         if (ret < 0)
2247                 goto err2;
2248         ret = xt_register_target(&ipt_error_target);
2249         if (ret < 0)
2250                 goto err3;
2251         ret = xt_register_match(&icmp_matchstruct);
2252         if (ret < 0)
2253                 goto err4;
2254
2255         /* Register setsockopt */
2256         ret = nf_register_sockopt(&ipt_sockopts);
2257         if (ret < 0)
2258                 goto err5;
2259
2260         printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2261         return 0;
2262
2263 err5:
2264         xt_unregister_match(&icmp_matchstruct);
2265 err4:
2266         xt_unregister_target(&ipt_error_target);
2267 err3:
2268         xt_unregister_target(&ipt_standard_target);
2269 err2:
2270         xt_proto_fini(AF_INET);
2271 err1:
2272         return ret;
2273 }
2274
2275 static void __exit ip_tables_fini(void)
2276 {
2277         nf_unregister_sockopt(&ipt_sockopts);
2278
2279         xt_unregister_match(&icmp_matchstruct);
2280         xt_unregister_target(&ipt_error_target);
2281         xt_unregister_target(&ipt_standard_target);
2282
2283         xt_proto_fini(AF_INET);
2284 }
2285
2286 EXPORT_SYMBOL(ipt_register_table);
2287 EXPORT_SYMBOL(ipt_unregister_table);
2288 EXPORT_SYMBOL(ipt_do_table);
2289 module_init(ip_tables_init);
2290 module_exit(ip_tables_fini);