[NETFILTER]: {ip,ip6}_tables: fix format strings
[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         /* Hack: Causes ipchains to give correct error msg --RR */
1267         if (len != sizeof(tmp) + tmp.size)
1268                 return -ENOPROTOOPT;
1269
1270         /* overflow check */
1271         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1272                 return -ENOMEM;
1273
1274         newinfo = xt_alloc_table_info(tmp.size);
1275         if (!newinfo)
1276                 return -ENOMEM;
1277
1278         /* choose the copy that is on our node/cpu */
1279         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1280         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1281                            tmp.size) != 0) {
1282                 ret = -EFAULT;
1283                 goto free_newinfo;
1284         }
1285
1286         ret = translate_table(tmp.name, tmp.valid_hooks,
1287                               newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1288                               tmp.hook_entry, tmp.underflow);
1289         if (ret != 0)
1290                 goto free_newinfo;
1291
1292         duprintf("ip_tables: Translated table\n");
1293
1294         ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
1295                            tmp.num_counters, tmp.counters);
1296         if (ret)
1297                 goto free_newinfo_untrans;
1298         return 0;
1299
1300  free_newinfo_untrans:
1301         IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1302  free_newinfo:
1303         xt_free_table_info(newinfo);
1304         return ret;
1305 }
1306
1307 /* We're lazy, and add to the first CPU; overflow works its fey magic
1308  * and everything is OK. */
1309 static inline int
1310 add_counter_to_entry(struct ipt_entry *e,
1311                      const struct xt_counters addme[],
1312                      unsigned int *i)
1313 {
1314 #if 0
1315         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1316                  *i,
1317                  (long unsigned int)e->counters.pcnt,
1318                  (long unsigned int)e->counters.bcnt,
1319                  (long unsigned int)addme[*i].pcnt,
1320                  (long unsigned int)addme[*i].bcnt);
1321 #endif
1322
1323         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1324
1325         (*i)++;
1326         return 0;
1327 }
1328
1329 static int
1330 do_add_counters(void __user *user, unsigned int len, int compat)
1331 {
1332         unsigned int i;
1333         struct xt_counters_info tmp;
1334         struct xt_counters *paddc;
1335         unsigned int num_counters;
1336         char *name;
1337         int size;
1338         void *ptmp;
1339         struct xt_table *t;
1340         struct xt_table_info *private;
1341         int ret = 0;
1342         void *loc_cpu_entry;
1343 #ifdef CONFIG_COMPAT
1344         struct compat_xt_counters_info compat_tmp;
1345
1346         if (compat) {
1347                 ptmp = &compat_tmp;
1348                 size = sizeof(struct compat_xt_counters_info);
1349         } else
1350 #endif
1351         {
1352                 ptmp = &tmp;
1353                 size = sizeof(struct xt_counters_info);
1354         }
1355
1356         if (copy_from_user(ptmp, user, size) != 0)
1357                 return -EFAULT;
1358
1359 #ifdef CONFIG_COMPAT
1360         if (compat) {
1361                 num_counters = compat_tmp.num_counters;
1362                 name = compat_tmp.name;
1363         } else
1364 #endif
1365         {
1366                 num_counters = tmp.num_counters;
1367                 name = tmp.name;
1368         }
1369
1370         if (len != size + num_counters * sizeof(struct xt_counters))
1371                 return -EINVAL;
1372
1373         paddc = vmalloc_node(len - size, numa_node_id());
1374         if (!paddc)
1375                 return -ENOMEM;
1376
1377         if (copy_from_user(paddc, user + size, len - size) != 0) {
1378                 ret = -EFAULT;
1379                 goto free;
1380         }
1381
1382         t = xt_find_table_lock(AF_INET, name);
1383         if (!t || IS_ERR(t)) {
1384                 ret = t ? PTR_ERR(t) : -ENOENT;
1385                 goto free;
1386         }
1387
1388         write_lock_bh(&t->lock);
1389         private = t->private;
1390         if (private->number != num_counters) {
1391                 ret = -EINVAL;
1392                 goto unlock_up_free;
1393         }
1394
1395         i = 0;
1396         /* Choose the copy that is on our node */
1397         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1398         IPT_ENTRY_ITERATE(loc_cpu_entry,
1399                           private->size,
1400                           add_counter_to_entry,
1401                           paddc,
1402                           &i);
1403  unlock_up_free:
1404         write_unlock_bh(&t->lock);
1405         xt_table_unlock(t);
1406         module_put(t->me);
1407  free:
1408         vfree(paddc);
1409
1410         return ret;
1411 }
1412
1413 #ifdef CONFIG_COMPAT
1414 struct compat_ipt_replace {
1415         char                    name[IPT_TABLE_MAXNAMELEN];
1416         u32                     valid_hooks;
1417         u32                     num_entries;
1418         u32                     size;
1419         u32                     hook_entry[NF_INET_NUMHOOKS];
1420         u32                     underflow[NF_INET_NUMHOOKS];
1421         u32                     num_counters;
1422         compat_uptr_t           counters;       /* struct ipt_counters * */
1423         struct compat_ipt_entry entries[0];
1424 };
1425
1426 static int
1427 compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
1428                           compat_uint_t *size, struct xt_counters *counters,
1429                           unsigned int *i)
1430 {
1431         struct ipt_entry_target *t;
1432         struct compat_ipt_entry __user *ce;
1433         u_int16_t target_offset, next_offset;
1434         compat_uint_t origsize;
1435         int ret;
1436
1437         ret = -EFAULT;
1438         origsize = *size;
1439         ce = (struct compat_ipt_entry __user *)*dstptr;
1440         if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1441                 goto out;
1442
1443         if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1444                 goto out;
1445
1446         *dstptr += sizeof(struct compat_ipt_entry);
1447         *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1448
1449         ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1450         target_offset = e->target_offset - (origsize - *size);
1451         if (ret)
1452                 goto out;
1453         t = ipt_get_target(e);
1454         ret = xt_compat_target_to_user(t, dstptr, size);
1455         if (ret)
1456                 goto out;
1457         ret = -EFAULT;
1458         next_offset = e->next_offset - (origsize - *size);
1459         if (put_user(target_offset, &ce->target_offset))
1460                 goto out;
1461         if (put_user(next_offset, &ce->next_offset))
1462                 goto out;
1463
1464         (*i)++;
1465         return 0;
1466 out:
1467         return ret;
1468 }
1469
1470 static inline int
1471 compat_find_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 xt_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         *size += xt_compat_match_offset(match);
1489
1490         (*i)++;
1491         return 0;
1492 }
1493
1494 static inline int
1495 compat_release_match(struct ipt_entry_match *m, unsigned int *i)
1496 {
1497         if (i && (*i)-- == 0)
1498                 return 1;
1499
1500         module_put(m->u.kernel.match->me);
1501         return 0;
1502 }
1503
1504 static inline int
1505 compat_release_entry(struct compat_ipt_entry *e, unsigned int *i)
1506 {
1507         struct ipt_entry_target *t;
1508
1509         if (i && (*i)-- == 0)
1510                 return 1;
1511
1512         /* Cleanup all matches */
1513         COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL);
1514         t = compat_ipt_get_target(e);
1515         module_put(t->u.kernel.target->me);
1516         return 0;
1517 }
1518
1519 static inline int
1520 check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
1521                                   struct xt_table_info *newinfo,
1522                                   unsigned int *size,
1523                                   unsigned char *base,
1524                                   unsigned char *limit,
1525                                   unsigned int *hook_entries,
1526                                   unsigned int *underflows,
1527                                   unsigned int *i,
1528                                   const char *name)
1529 {
1530         struct ipt_entry_target *t;
1531         struct xt_target *target;
1532         unsigned int entry_offset;
1533         int ret, off, h, j;
1534
1535         duprintf("check_compat_entry_size_and_hooks %p\n", e);
1536         if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1537             || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1538                 duprintf("Bad offset %p, limit = %p\n", e, limit);
1539                 return -EINVAL;
1540         }
1541
1542         if (e->next_offset < sizeof(struct compat_ipt_entry) +
1543                              sizeof(struct compat_xt_entry_target)) {
1544                 duprintf("checking: element %p size %u\n",
1545                          e, e->next_offset);
1546                 return -EINVAL;
1547         }
1548
1549         /* For purposes of check_entry casting the compat entry is fine */
1550         ret = check_entry((struct ipt_entry *)e, name);
1551         if (ret)
1552                 return ret;
1553
1554         off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1555         entry_offset = (void *)e - (void *)base;
1556         j = 0;
1557         ret = COMPAT_IPT_MATCH_ITERATE(e, compat_find_calc_match, name,
1558                                        &e->ip, e->comefrom, &off, &j);
1559         if (ret != 0)
1560                 goto release_matches;
1561
1562         t = compat_ipt_get_target(e);
1563         target = try_then_request_module(xt_find_target(AF_INET,
1564                                                         t->u.user.name,
1565                                                         t->u.user.revision),
1566                                          "ipt_%s", t->u.user.name);
1567         if (IS_ERR(target) || !target) {
1568                 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1569                          t->u.user.name);
1570                 ret = target ? PTR_ERR(target) : -ENOENT;
1571                 goto release_matches;
1572         }
1573         t->u.kernel.target = target;
1574
1575         off += xt_compat_target_offset(target);
1576         *size += off;
1577         ret = xt_compat_add_offset(AF_INET, entry_offset, off);
1578         if (ret)
1579                 goto out;
1580
1581         /* Check hooks & underflows */
1582         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1583                 if ((unsigned char *)e - base == hook_entries[h])
1584                         newinfo->hook_entry[h] = hook_entries[h];
1585                 if ((unsigned char *)e - base == underflows[h])
1586                         newinfo->underflow[h] = underflows[h];
1587         }
1588
1589         /* Clear counters and comefrom */
1590         memset(&e->counters, 0, sizeof(e->counters));
1591         e->comefrom = 0;
1592
1593         (*i)++;
1594         return 0;
1595
1596 out:
1597         module_put(t->u.kernel.target->me);
1598 release_matches:
1599         IPT_MATCH_ITERATE(e, compat_release_match, &j);
1600         return ret;
1601 }
1602
1603 static int
1604 compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
1605                             unsigned int *size, const char *name,
1606                             struct xt_table_info *newinfo, unsigned char *base)
1607 {
1608         struct ipt_entry_target *t;
1609         struct xt_target *target;
1610         struct ipt_entry *de;
1611         unsigned int origsize;
1612         int ret, h;
1613
1614         ret = 0;
1615         origsize = *size;
1616         de = (struct ipt_entry *)*dstptr;
1617         memcpy(de, e, sizeof(struct ipt_entry));
1618         memcpy(&de->counters, &e->counters, sizeof(e->counters));
1619
1620         *dstptr += sizeof(struct ipt_entry);
1621         *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1622
1623         ret = COMPAT_IPT_MATCH_ITERATE(e, xt_compat_match_from_user,
1624                                        dstptr, size);
1625         if (ret)
1626                 return ret;
1627         de->target_offset = e->target_offset - (origsize - *size);
1628         t = compat_ipt_get_target(e);
1629         target = t->u.kernel.target;
1630         xt_compat_target_from_user(t, dstptr, size);
1631
1632         de->next_offset = e->next_offset - (origsize - *size);
1633         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1634                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1635                         newinfo->hook_entry[h] -= origsize - *size;
1636                 if ((unsigned char *)de - base < newinfo->underflow[h])
1637                         newinfo->underflow[h] -= origsize - *size;
1638         }
1639         return ret;
1640 }
1641
1642 static inline int compat_check_entry(struct ipt_entry *e, const char *name,
1643                                      unsigned int *i)
1644 {
1645         int j, ret;
1646
1647         j = 0;
1648         ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip,
1649                                 e->comefrom, &j);
1650         if (ret)
1651                 goto cleanup_matches;
1652
1653         ret = check_target(e, name);
1654         if (ret)
1655                 goto cleanup_matches;
1656
1657         (*i)++;
1658         return 0;
1659
1660  cleanup_matches:
1661         IPT_MATCH_ITERATE(e, cleanup_match, &j);
1662         return ret;
1663 }
1664
1665 static int
1666 translate_compat_table(const char *name,
1667                        unsigned int valid_hooks,
1668                        struct xt_table_info **pinfo,
1669                        void **pentry0,
1670                        unsigned int total_size,
1671                        unsigned int number,
1672                        unsigned int *hook_entries,
1673                        unsigned int *underflows)
1674 {
1675         unsigned int i, j;
1676         struct xt_table_info *newinfo, *info;
1677         void *pos, *entry0, *entry1;
1678         unsigned int size;
1679         int ret;
1680
1681         info = *pinfo;
1682         entry0 = *pentry0;
1683         size = total_size;
1684         info->number = number;
1685
1686         /* Init all hooks to impossible value. */
1687         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1688                 info->hook_entry[i] = 0xFFFFFFFF;
1689                 info->underflow[i] = 0xFFFFFFFF;
1690         }
1691
1692         duprintf("translate_compat_table: size %u\n", info->size);
1693         j = 0;
1694         xt_compat_lock(AF_INET);
1695         /* Walk through entries, checking offsets. */
1696         ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size,
1697                                        check_compat_entry_size_and_hooks,
1698                                        info, &size, entry0,
1699                                        entry0 + total_size,
1700                                        hook_entries, underflows, &j, name);
1701         if (ret != 0)
1702                 goto out_unlock;
1703
1704         ret = -EINVAL;
1705         if (j != number) {
1706                 duprintf("translate_compat_table: %u not %u entries\n",
1707                          j, number);
1708                 goto out_unlock;
1709         }
1710
1711         /* Check hooks all assigned */
1712         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1713                 /* Only hooks which are valid */
1714                 if (!(valid_hooks & (1 << i)))
1715                         continue;
1716                 if (info->hook_entry[i] == 0xFFFFFFFF) {
1717                         duprintf("Invalid hook entry %u %u\n",
1718                                  i, hook_entries[i]);
1719                         goto out_unlock;
1720                 }
1721                 if (info->underflow[i] == 0xFFFFFFFF) {
1722                         duprintf("Invalid underflow %u %u\n",
1723                                  i, underflows[i]);
1724                         goto out_unlock;
1725                 }
1726         }
1727
1728         ret = -ENOMEM;
1729         newinfo = xt_alloc_table_info(size);
1730         if (!newinfo)
1731                 goto out_unlock;
1732
1733         newinfo->number = number;
1734         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1735                 newinfo->hook_entry[i] = info->hook_entry[i];
1736                 newinfo->underflow[i] = info->underflow[i];
1737         }
1738         entry1 = newinfo->entries[raw_smp_processor_id()];
1739         pos = entry1;
1740         size = total_size;
1741         ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size,
1742                                        compat_copy_entry_from_user,
1743                                        &pos, &size, name, newinfo, entry1);
1744         xt_compat_flush_offsets(AF_INET);
1745         xt_compat_unlock(AF_INET);
1746         if (ret)
1747                 goto free_newinfo;
1748
1749         ret = -ELOOP;
1750         if (!mark_source_chains(newinfo, valid_hooks, entry1))
1751                 goto free_newinfo;
1752
1753         i = 0;
1754         ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1755                                 name, &i);
1756         if (ret) {
1757                 j -= i;
1758                 COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1759                                                   compat_release_entry, &j);
1760                 IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1761                 xt_free_table_info(newinfo);
1762                 return ret;
1763         }
1764
1765         /* And one copy for every other CPU */
1766         for_each_possible_cpu(i)
1767                 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1768                         memcpy(newinfo->entries[i], entry1, newinfo->size);
1769
1770         *pinfo = newinfo;
1771         *pentry0 = entry1;
1772         xt_free_table_info(info);
1773         return 0;
1774
1775 free_newinfo:
1776         xt_free_table_info(newinfo);
1777 out:
1778         COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1779         return ret;
1780 out_unlock:
1781         xt_compat_flush_offsets(AF_INET);
1782         xt_compat_unlock(AF_INET);
1783         goto out;
1784 }
1785
1786 static int
1787 compat_do_replace(void __user *user, unsigned int len)
1788 {
1789         int ret;
1790         struct compat_ipt_replace tmp;
1791         struct xt_table_info *newinfo;
1792         void *loc_cpu_entry;
1793
1794         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1795                 return -EFAULT;
1796
1797         /* Hack: Causes ipchains to give correct error msg --RR */
1798         if (len != sizeof(tmp) + tmp.size)
1799                 return -ENOPROTOOPT;
1800
1801         /* overflow check */
1802         if (tmp.size >= INT_MAX / num_possible_cpus())
1803                 return -ENOMEM;
1804         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1805                 return -ENOMEM;
1806
1807         newinfo = xt_alloc_table_info(tmp.size);
1808         if (!newinfo)
1809                 return -ENOMEM;
1810
1811         /* choose the copy that is on our node/cpu */
1812         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1813         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1814                            tmp.size) != 0) {
1815                 ret = -EFAULT;
1816                 goto free_newinfo;
1817         }
1818
1819         ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1820                                      &newinfo, &loc_cpu_entry, tmp.size,
1821                                      tmp.num_entries, tmp.hook_entry,
1822                                      tmp.underflow);
1823         if (ret != 0)
1824                 goto free_newinfo;
1825
1826         duprintf("compat_do_replace: Translated table\n");
1827
1828         ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
1829                            tmp.num_counters, compat_ptr(tmp.counters));
1830         if (ret)
1831                 goto free_newinfo_untrans;
1832         return 0;
1833
1834  free_newinfo_untrans:
1835         IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1836  free_newinfo:
1837         xt_free_table_info(newinfo);
1838         return ret;
1839 }
1840
1841 static int
1842 compat_do_ipt_set_ctl(struct sock *sk,  int cmd, void __user *user,
1843                       unsigned int len)
1844 {
1845         int ret;
1846
1847         if (!capable(CAP_NET_ADMIN))
1848                 return -EPERM;
1849
1850         switch (cmd) {
1851         case IPT_SO_SET_REPLACE:
1852                 ret = compat_do_replace(user, len);
1853                 break;
1854
1855         case IPT_SO_SET_ADD_COUNTERS:
1856                 ret = do_add_counters(user, len, 1);
1857                 break;
1858
1859         default:
1860                 duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
1861                 ret = -EINVAL;
1862         }
1863
1864         return ret;
1865 }
1866
1867 struct compat_ipt_get_entries {
1868         char name[IPT_TABLE_MAXNAMELEN];
1869         compat_uint_t size;
1870         struct compat_ipt_entry entrytable[0];
1871 };
1872
1873 static int
1874 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1875                             void __user *userptr)
1876 {
1877         struct xt_counters *counters;
1878         struct xt_table_info *private = table->private;
1879         void __user *pos;
1880         unsigned int size;
1881         int ret = 0;
1882         void *loc_cpu_entry;
1883         unsigned int i = 0;
1884
1885         counters = alloc_counters(table);
1886         if (IS_ERR(counters))
1887                 return PTR_ERR(counters);
1888
1889         /* choose the copy that is on our node/cpu, ...
1890          * This choice is lazy (because current thread is
1891          * allowed to migrate to another cpu)
1892          */
1893         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1894         pos = userptr;
1895         size = total_size;
1896         ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1897                                 compat_copy_entry_to_user,
1898                                 &pos, &size, counters, &i);
1899
1900         vfree(counters);
1901         return ret;
1902 }
1903
1904 static int
1905 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1906 {
1907         int ret;
1908         struct compat_ipt_get_entries get;
1909         struct xt_table *t;
1910
1911         if (*len < sizeof(get)) {
1912                 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1913                 return -EINVAL;
1914         }
1915
1916         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1917                 return -EFAULT;
1918
1919         if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1920                 duprintf("compat_get_entries: %u != %zu\n",
1921                          *len, sizeof(get) + get.size);
1922                 return -EINVAL;
1923         }
1924
1925         xt_compat_lock(AF_INET);
1926         t = xt_find_table_lock(AF_INET, get.name);
1927         if (t && !IS_ERR(t)) {
1928                 struct xt_table_info *private = t->private;
1929                 struct xt_table_info info;
1930                 duprintf("t->private->number = %u\n", private->number);
1931                 ret = compat_table_info(private, &info);
1932                 if (!ret && get.size == info.size) {
1933                         ret = compat_copy_entries_to_user(private->size,
1934                                                           t, uptr->entrytable);
1935                 } else if (!ret) {
1936                         duprintf("compat_get_entries: I've got %u not %u!\n",
1937                                  private->size, get.size);
1938                         ret = -EINVAL;
1939                 }
1940                 xt_compat_flush_offsets(AF_INET);
1941                 module_put(t->me);
1942                 xt_table_unlock(t);
1943         } else
1944                 ret = t ? PTR_ERR(t) : -ENOENT;
1945
1946         xt_compat_unlock(AF_INET);
1947         return ret;
1948 }
1949
1950 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1951
1952 static int
1953 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1954 {
1955         int ret;
1956
1957         if (!capable(CAP_NET_ADMIN))
1958                 return -EPERM;
1959
1960         switch (cmd) {
1961         case IPT_SO_GET_INFO:
1962                 ret = get_info(user, len, 1);
1963                 break;
1964         case IPT_SO_GET_ENTRIES:
1965                 ret = compat_get_entries(user, len);
1966                 break;
1967         default:
1968                 ret = do_ipt_get_ctl(sk, cmd, user, len);
1969         }
1970         return ret;
1971 }
1972 #endif
1973
1974 static int
1975 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1976 {
1977         int ret;
1978
1979         if (!capable(CAP_NET_ADMIN))
1980                 return -EPERM;
1981
1982         switch (cmd) {
1983         case IPT_SO_SET_REPLACE:
1984                 ret = do_replace(user, len);
1985                 break;
1986
1987         case IPT_SO_SET_ADD_COUNTERS:
1988                 ret = do_add_counters(user, len, 0);
1989                 break;
1990
1991         default:
1992                 duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
1993                 ret = -EINVAL;
1994         }
1995
1996         return ret;
1997 }
1998
1999 static int
2000 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2001 {
2002         int ret;
2003
2004         if (!capable(CAP_NET_ADMIN))
2005                 return -EPERM;
2006
2007         switch (cmd) {
2008         case IPT_SO_GET_INFO:
2009                 ret = get_info(user, len, 0);
2010                 break;
2011
2012         case IPT_SO_GET_ENTRIES:
2013                 ret = get_entries(user, len);
2014                 break;
2015
2016         case IPT_SO_GET_REVISION_MATCH:
2017         case IPT_SO_GET_REVISION_TARGET: {
2018                 struct ipt_get_revision rev;
2019                 int target;
2020
2021                 if (*len != sizeof(rev)) {
2022                         ret = -EINVAL;
2023                         break;
2024                 }
2025                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2026                         ret = -EFAULT;
2027                         break;
2028                 }
2029
2030                 if (cmd == IPT_SO_GET_REVISION_TARGET)
2031                         target = 1;
2032                 else
2033                         target = 0;
2034
2035                 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2036                                                          rev.revision,
2037                                                          target, &ret),
2038                                         "ipt_%s", rev.name);
2039                 break;
2040         }
2041
2042         default:
2043                 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2044                 ret = -EINVAL;
2045         }
2046
2047         return ret;
2048 }
2049
2050 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2051 {
2052         int ret;
2053         struct xt_table_info *newinfo;
2054         struct xt_table_info bootstrap
2055                 = { 0, 0, 0, { 0 }, { 0 }, { } };
2056         void *loc_cpu_entry;
2057
2058         newinfo = xt_alloc_table_info(repl->size);
2059         if (!newinfo)
2060                 return -ENOMEM;
2061
2062         /* choose the copy on our node/cpu, but dont care about preemption */
2063         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2064         memcpy(loc_cpu_entry, repl->entries, repl->size);
2065
2066         ret = translate_table(table->name, table->valid_hooks,
2067                               newinfo, loc_cpu_entry, repl->size,
2068                               repl->num_entries,
2069                               repl->hook_entry,
2070                               repl->underflow);
2071         if (ret != 0) {
2072                 xt_free_table_info(newinfo);
2073                 return ret;
2074         }
2075
2076         ret = xt_register_table(table, &bootstrap, newinfo);
2077         if (ret != 0) {
2078                 xt_free_table_info(newinfo);
2079                 return ret;
2080         }
2081
2082         return 0;
2083 }
2084
2085 void ipt_unregister_table(struct xt_table *table)
2086 {
2087         struct xt_table_info *private;
2088         void *loc_cpu_entry;
2089
2090         private = xt_unregister_table(table);
2091
2092         /* Decrease module usage counts and free resources */
2093         loc_cpu_entry = private->entries[raw_smp_processor_id()];
2094         IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2095         xt_free_table_info(private);
2096 }
2097
2098 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2099 static inline bool
2100 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2101                      u_int8_t type, u_int8_t code,
2102                      bool invert)
2103 {
2104         return ((test_type == 0xFF) ||
2105                 (type == test_type && code >= min_code && code <= max_code))
2106                 ^ invert;
2107 }
2108
2109 static bool
2110 icmp_match(const struct sk_buff *skb,
2111            const struct net_device *in,
2112            const struct net_device *out,
2113            const struct xt_match *match,
2114            const void *matchinfo,
2115            int offset,
2116            unsigned int protoff,
2117            bool *hotdrop)
2118 {
2119         struct icmphdr _icmph, *ic;
2120         const struct ipt_icmp *icmpinfo = matchinfo;
2121
2122         /* Must not be a fragment. */
2123         if (offset)
2124                 return false;
2125
2126         ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2127         if (ic == NULL) {
2128                 /* We've been asked to examine this packet, and we
2129                  * can't.  Hence, no choice but to drop.
2130                  */
2131                 duprintf("Dropping evil ICMP tinygram.\n");
2132                 *hotdrop = true;
2133                 return false;
2134         }
2135
2136         return icmp_type_code_match(icmpinfo->type,
2137                                     icmpinfo->code[0],
2138                                     icmpinfo->code[1],
2139                                     ic->type, ic->code,
2140                                     !!(icmpinfo->invflags&IPT_ICMP_INV));
2141 }
2142
2143 /* Called when user tries to insert an entry of this type. */
2144 static bool
2145 icmp_checkentry(const char *tablename,
2146            const void *entry,
2147            const struct xt_match *match,
2148            void *matchinfo,
2149            unsigned int hook_mask)
2150 {
2151         const struct ipt_icmp *icmpinfo = matchinfo;
2152
2153         /* Must specify no unknown invflags */
2154         return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2155 }
2156
2157 /* The built-in targets: standard (NULL) and error. */
2158 static struct xt_target ipt_standard_target __read_mostly = {
2159         .name           = IPT_STANDARD_TARGET,
2160         .targetsize     = sizeof(int),
2161         .family         = AF_INET,
2162 #ifdef CONFIG_COMPAT
2163         .compatsize     = sizeof(compat_int_t),
2164         .compat_from_user = compat_standard_from_user,
2165         .compat_to_user = compat_standard_to_user,
2166 #endif
2167 };
2168
2169 static struct xt_target ipt_error_target __read_mostly = {
2170         .name           = IPT_ERROR_TARGET,
2171         .target         = ipt_error,
2172         .targetsize     = IPT_FUNCTION_MAXNAMELEN,
2173         .family         = AF_INET,
2174 };
2175
2176 static struct nf_sockopt_ops ipt_sockopts = {
2177         .pf             = PF_INET,
2178         .set_optmin     = IPT_BASE_CTL,
2179         .set_optmax     = IPT_SO_SET_MAX+1,
2180         .set            = do_ipt_set_ctl,
2181 #ifdef CONFIG_COMPAT
2182         .compat_set     = compat_do_ipt_set_ctl,
2183 #endif
2184         .get_optmin     = IPT_BASE_CTL,
2185         .get_optmax     = IPT_SO_GET_MAX+1,
2186         .get            = do_ipt_get_ctl,
2187 #ifdef CONFIG_COMPAT
2188         .compat_get     = compat_do_ipt_get_ctl,
2189 #endif
2190         .owner          = THIS_MODULE,
2191 };
2192
2193 static struct xt_match icmp_matchstruct __read_mostly = {
2194         .name           = "icmp",
2195         .match          = icmp_match,
2196         .matchsize      = sizeof(struct ipt_icmp),
2197         .checkentry     = icmp_checkentry,
2198         .proto          = IPPROTO_ICMP,
2199         .family         = AF_INET,
2200 };
2201
2202 static int __init ip_tables_init(void)
2203 {
2204         int ret;
2205
2206         ret = xt_proto_init(AF_INET);
2207         if (ret < 0)
2208                 goto err1;
2209
2210         /* Noone else will be downing sem now, so we won't sleep */
2211         ret = xt_register_target(&ipt_standard_target);
2212         if (ret < 0)
2213                 goto err2;
2214         ret = xt_register_target(&ipt_error_target);
2215         if (ret < 0)
2216                 goto err3;
2217         ret = xt_register_match(&icmp_matchstruct);
2218         if (ret < 0)
2219                 goto err4;
2220
2221         /* Register setsockopt */
2222         ret = nf_register_sockopt(&ipt_sockopts);
2223         if (ret < 0)
2224                 goto err5;
2225
2226         printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2227         return 0;
2228
2229 err5:
2230         xt_unregister_match(&icmp_matchstruct);
2231 err4:
2232         xt_unregister_target(&ipt_error_target);
2233 err3:
2234         xt_unregister_target(&ipt_standard_target);
2235 err2:
2236         xt_proto_fini(AF_INET);
2237 err1:
2238         return ret;
2239 }
2240
2241 static void __exit ip_tables_fini(void)
2242 {
2243         nf_unregister_sockopt(&ipt_sockopts);
2244
2245         xt_unregister_match(&icmp_matchstruct);
2246         xt_unregister_target(&ipt_error_target);
2247         xt_unregister_target(&ipt_standard_target);
2248
2249         xt_proto_fini(AF_INET);
2250 }
2251
2252 EXPORT_SYMBOL(ipt_register_table);
2253 EXPORT_SYMBOL(ipt_unregister_table);
2254 EXPORT_SYMBOL(ipt_do_table);
2255 module_init(ip_tables_init);
2256 module_exit(ip_tables_fini);