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