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