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