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