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