[PATCH] capable/capability.h (net/)
[safe/jmp/linux-2.6] / net / ipv4 / netfilter / arp_tables.c
1 /*
2  * Packet matching code for ARP packets.
3  *
4  * Based heavily, if not almost entirely, upon ip_tables.c framework.
5  *
6  * Some ARP specific bits are:
7  *
8  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
9  *
10  */
11
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/skbuff.h>
15 #include <linux/netdevice.h>
16 #include <linux/capability.h>
17 #include <linux/if_arp.h>
18 #include <linux/kmod.h>
19 #include <linux/vmalloc.h>
20 #include <linux/proc_fs.h>
21 #include <linux/module.h>
22 #include <linux/init.h>
23
24 #include <asm/uaccess.h>
25 #include <asm/semaphore.h>
26
27 #include <linux/netfilter_arp/arp_tables.h>
28
29 MODULE_LICENSE("GPL");
30 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
31 MODULE_DESCRIPTION("arptables core");
32
33 /*#define DEBUG_ARP_TABLES*/
34 /*#define DEBUG_ARP_TABLES_USER*/
35
36 #ifdef DEBUG_ARP_TABLES
37 #define dprintf(format, args...)  printk(format , ## args)
38 #else
39 #define dprintf(format, args...)
40 #endif
41
42 #ifdef DEBUG_ARP_TABLES_USER
43 #define duprintf(format, args...) printk(format , ## args)
44 #else
45 #define duprintf(format, args...)
46 #endif
47
48 #ifdef CONFIG_NETFILTER_DEBUG
49 #define ARP_NF_ASSERT(x)                                        \
50 do {                                                            \
51         if (!(x))                                               \
52                 printk("ARP_NF_ASSERT: %s:%s:%u\n",             \
53                        __FUNCTION__, __FILE__, __LINE__);       \
54 } while(0)
55 #else
56 #define ARP_NF_ASSERT(x)
57 #endif
58 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
59
60 static DECLARE_MUTEX(arpt_mutex);
61
62 #define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
63 #define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
64 #include <linux/netfilter_ipv4/listhelp.h>
65
66 struct arpt_table_info {
67         unsigned int size;
68         unsigned int number;
69         unsigned int initial_entries;
70         unsigned int hook_entry[NF_ARP_NUMHOOKS];
71         unsigned int underflow[NF_ARP_NUMHOOKS];
72         void *entries[NR_CPUS];
73 };
74
75 static LIST_HEAD(arpt_target);
76 static LIST_HEAD(arpt_tables);
77 #define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
78 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
79
80 static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
81                                       char *hdr_addr, int len)
82 {
83         int i, ret;
84
85         if (len > ARPT_DEV_ADDR_LEN_MAX)
86                 len = ARPT_DEV_ADDR_LEN_MAX;
87
88         ret = 0;
89         for (i = 0; i < len; i++)
90                 ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i];
91
92         return (ret != 0);
93 }
94
95 /* Returns whether packet matches rule or not. */
96 static inline int arp_packet_match(const struct arphdr *arphdr,
97                                    struct net_device *dev,
98                                    const char *indev,
99                                    const char *outdev,
100                                    const struct arpt_arp *arpinfo)
101 {
102         char *arpptr = (char *)(arphdr + 1);
103         char *src_devaddr, *tgt_devaddr;
104         u32 src_ipaddr, tgt_ipaddr;
105         int i, ret;
106
107 #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg))
108
109         if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop,
110                   ARPT_INV_ARPOP)) {
111                 dprintf("ARP operation field mismatch.\n");
112                 dprintf("ar_op: %04x info->arpop: %04x info->arpop_mask: %04x\n",
113                         arphdr->ar_op, arpinfo->arpop, arpinfo->arpop_mask);
114                 return 0;
115         }
116
117         if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd,
118                   ARPT_INV_ARPHRD)) {
119                 dprintf("ARP hardware address format mismatch.\n");
120                 dprintf("ar_hrd: %04x info->arhrd: %04x info->arhrd_mask: %04x\n",
121                         arphdr->ar_hrd, arpinfo->arhrd, arpinfo->arhrd_mask);
122                 return 0;
123         }
124
125         if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro,
126                   ARPT_INV_ARPPRO)) {
127                 dprintf("ARP protocol address format mismatch.\n");
128                 dprintf("ar_pro: %04x info->arpro: %04x info->arpro_mask: %04x\n",
129                         arphdr->ar_pro, arpinfo->arpro, arpinfo->arpro_mask);
130                 return 0;
131         }
132
133         if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln,
134                   ARPT_INV_ARPHLN)) {
135                 dprintf("ARP hardware address length mismatch.\n");
136                 dprintf("ar_hln: %02x info->arhln: %02x info->arhln_mask: %02x\n",
137                         arphdr->ar_hln, arpinfo->arhln, arpinfo->arhln_mask);
138                 return 0;
139         }
140
141         src_devaddr = arpptr;
142         arpptr += dev->addr_len;
143         memcpy(&src_ipaddr, arpptr, sizeof(u32));
144         arpptr += sizeof(u32);
145         tgt_devaddr = arpptr;
146         arpptr += dev->addr_len;
147         memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
148
149         if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len),
150                   ARPT_INV_SRCDEVADDR) ||
151             FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len),
152                   ARPT_INV_TGTDEVADDR)) {
153                 dprintf("Source or target device address mismatch.\n");
154
155                 return 0;
156         }
157
158         if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr,
159                   ARPT_INV_SRCIP) ||
160             FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr),
161                   ARPT_INV_TGTIP)) {
162                 dprintf("Source or target IP address mismatch.\n");
163
164                 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
165                         NIPQUAD(src_ipaddr),
166                         NIPQUAD(arpinfo->smsk.s_addr),
167                         NIPQUAD(arpinfo->src.s_addr),
168                         arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");
169                 dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
170                         NIPQUAD(tgt_ipaddr),
171                         NIPQUAD(arpinfo->tmsk.s_addr),
172                         NIPQUAD(arpinfo->tgt.s_addr),
173                         arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : "");
174                 return 0;
175         }
176
177         /* Look for ifname matches.  */
178         for (i = 0, ret = 0; i < IFNAMSIZ; i++) {
179                 ret |= (indev[i] ^ arpinfo->iniface[i])
180                         & arpinfo->iniface_mask[i];
181         }
182
183         if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
184                 dprintf("VIA in mismatch (%s vs %s).%s\n",
185                         indev, arpinfo->iniface,
186                         arpinfo->invflags&ARPT_INV_VIA_IN ?" (INV)":"");
187                 return 0;
188         }
189
190         for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
191                 unsigned long odev;
192                 memcpy(&odev, outdev + i*sizeof(unsigned long),
193                        sizeof(unsigned long));
194                 ret |= (odev
195                         ^ ((const unsigned long *)arpinfo->outiface)[i])
196                         & ((const unsigned long *)arpinfo->outiface_mask)[i];
197         }
198
199         if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
200                 dprintf("VIA out mismatch (%s vs %s).%s\n",
201                         outdev, arpinfo->outiface,
202                         arpinfo->invflags&ARPT_INV_VIA_OUT ?" (INV)":"");
203                 return 0;
204         }
205
206         return 1;
207 }
208
209 static inline int arp_checkentry(const struct arpt_arp *arp)
210 {
211         if (arp->flags & ~ARPT_F_MASK) {
212                 duprintf("Unknown flag bits set: %08X\n",
213                          arp->flags & ~ARPT_F_MASK);
214                 return 0;
215         }
216         if (arp->invflags & ~ARPT_INV_MASK) {
217                 duprintf("Unknown invflag bits set: %08X\n",
218                          arp->invflags & ~ARPT_INV_MASK);
219                 return 0;
220         }
221
222         return 1;
223 }
224
225 static unsigned int arpt_error(struct sk_buff **pskb,
226                                unsigned int hooknum,
227                                const struct net_device *in,
228                                const struct net_device *out,
229                                const void *targinfo,
230                                void *userinfo)
231 {
232         if (net_ratelimit())
233                 printk("arp_tables: error: '%s'\n", (char *)targinfo);
234
235         return NF_DROP;
236 }
237
238 static inline struct arpt_entry *get_entry(void *base, unsigned int offset)
239 {
240         return (struct arpt_entry *)(base + offset);
241 }
242
243 unsigned int arpt_do_table(struct sk_buff **pskb,
244                            unsigned int hook,
245                            const struct net_device *in,
246                            const struct net_device *out,
247                            struct arpt_table *table,
248                            void *userdata)
249 {
250         static const char nulldevname[IFNAMSIZ];
251         unsigned int verdict = NF_DROP;
252         struct arphdr *arp;
253         int hotdrop = 0;
254         struct arpt_entry *e, *back;
255         const char *indev, *outdev;
256         void *table_base;
257
258         /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
259         if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) +
260                                      (2 * (*pskb)->dev->addr_len) +
261                                      (2 * sizeof(u32)))))
262                 return NF_DROP;
263
264         indev = in ? in->name : nulldevname;
265         outdev = out ? out->name : nulldevname;
266
267         read_lock_bh(&table->lock);
268         table_base = (void *)table->private->entries[smp_processor_id()];
269         e = get_entry(table_base, table->private->hook_entry[hook]);
270         back = get_entry(table_base, table->private->underflow[hook]);
271
272         arp = (*pskb)->nh.arph;
273         do {
274                 if (arp_packet_match(arp, (*pskb)->dev, indev, outdev, &e->arp)) {
275                         struct arpt_entry_target *t;
276                         int hdr_len;
277
278                         hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
279                                 (2 * (*pskb)->dev->addr_len);
280                         ADD_COUNTER(e->counters, hdr_len, 1);
281
282                         t = arpt_get_target(e);
283
284                         /* Standard target? */
285                         if (!t->u.kernel.target->target) {
286                                 int v;
287
288                                 v = ((struct arpt_standard_target *)t)->verdict;
289                                 if (v < 0) {
290                                         /* Pop from stack? */
291                                         if (v != ARPT_RETURN) {
292                                                 verdict = (unsigned)(-v) - 1;
293                                                 break;
294                                         }
295                                         e = back;
296                                         back = get_entry(table_base,
297                                                          back->comefrom);
298                                         continue;
299                                 }
300                                 if (table_base + v
301                                     != (void *)e + e->next_offset) {
302                                         /* Save old back ptr in next entry */
303                                         struct arpt_entry *next
304                                                 = (void *)e + e->next_offset;
305                                         next->comefrom =
306                                                 (void *)back - table_base;
307
308                                         /* set back pointer to next entry */
309                                         back = next;
310                                 }
311
312                                 e = get_entry(table_base, v);
313                         } else {
314                                 /* Targets which reenter must return
315                                  * abs. verdicts
316                                  */
317                                 verdict = t->u.kernel.target->target(pskb,
318                                                                      hook,
319                                                                      in, out,
320                                                                      t->data,
321                                                                      userdata);
322
323                                 /* Target might have changed stuff. */
324                                 arp = (*pskb)->nh.arph;
325
326                                 if (verdict == ARPT_CONTINUE)
327                                         e = (void *)e + e->next_offset;
328                                 else
329                                         /* Verdict */
330                                         break;
331                         }
332                 } else {
333                         e = (void *)e + e->next_offset;
334                 }
335         } while (!hotdrop);
336         read_unlock_bh(&table->lock);
337
338         if (hotdrop)
339                 return NF_DROP;
340         else
341                 return verdict;
342 }
343
344 /*
345  * These are weird, but module loading must not be done with mutex
346  * held (since they will register), and we have to have a single
347  * function to use try_then_request_module().
348  */
349
350 /* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
351 static inline struct arpt_table *find_table_lock(const char *name)
352 {
353         struct arpt_table *t;
354
355         if (down_interruptible(&arpt_mutex) != 0)
356                 return ERR_PTR(-EINTR);
357
358         list_for_each_entry(t, &arpt_tables, list)
359                 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
360                         return t;
361         up(&arpt_mutex);
362         return NULL;
363 }
364
365
366 /* Find target, grabs ref.  Returns ERR_PTR() on error. */
367 static inline struct arpt_target *find_target(const char *name, u8 revision)
368 {
369         struct arpt_target *t;
370         int err = 0;
371
372         if (down_interruptible(&arpt_mutex) != 0)
373                 return ERR_PTR(-EINTR);
374
375         list_for_each_entry(t, &arpt_target, list) {
376                 if (strcmp(t->name, name) == 0) {
377                         if (t->revision == revision) {
378                                 if (try_module_get(t->me)) {
379                                         up(&arpt_mutex);
380                                         return t;
381                                 }
382                         } else
383                                 err = -EPROTOTYPE; /* Found something. */
384                 }
385         }
386         up(&arpt_mutex);
387         return ERR_PTR(err);
388 }
389
390 struct arpt_target *arpt_find_target(const char *name, u8 revision)
391 {
392         struct arpt_target *target;
393
394         target = try_then_request_module(find_target(name, revision),
395                                          "arpt_%s", name);
396         if (IS_ERR(target) || !target)
397                 return NULL;
398         return target;
399 }
400
401 static int target_revfn(const char *name, u8 revision, int *bestp)
402 {
403         struct arpt_target *t;
404         int have_rev = 0;
405
406         list_for_each_entry(t, &arpt_target, list) {
407                 if (strcmp(t->name, name) == 0) {
408                         if (t->revision > *bestp)
409                                 *bestp = t->revision;
410                         if (t->revision == revision)
411                                 have_rev =1;
412                 }
413         }
414         return have_rev;
415 }
416
417 /* Returns true or false (if no such extension at all) */
418 static inline int find_revision(const char *name, u8 revision,
419                                 int (*revfn)(const char *, u8, int *),
420                                 int *err)
421 {
422         int have_rev, best = -1;
423
424         if (down_interruptible(&arpt_mutex) != 0) {
425                 *err = -EINTR;
426                 return 1;
427         }
428         have_rev = revfn(name, revision, &best);
429         up(&arpt_mutex);
430
431         /* Nothing at all?  Return 0 to try loading module. */
432         if (best == -1) {
433                 *err = -ENOENT;
434                 return 0;
435         }
436
437         *err = best;
438         if (!have_rev)
439                 *err = -EPROTONOSUPPORT;
440         return 1;
441 }
442
443
444 /* All zeroes == unconditional rule. */
445 static inline int unconditional(const struct arpt_arp *arp)
446 {
447         unsigned int i;
448
449         for (i = 0; i < sizeof(*arp)/sizeof(__u32); i++)
450                 if (((__u32 *)arp)[i])
451                         return 0;
452
453         return 1;
454 }
455
456 /* Figures out from what hook each rule can be called: returns 0 if
457  * there are loops.  Puts hook bitmask in comefrom.
458  */
459 static int mark_source_chains(struct arpt_table_info *newinfo,
460                               unsigned int valid_hooks, void *entry0)
461 {
462         unsigned int hook;
463
464         /* No recursion; use packet counter to save back ptrs (reset
465          * to 0 as we leave), and comefrom to save source hook bitmask.
466          */
467         for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) {
468                 unsigned int pos = newinfo->hook_entry[hook];
469                 struct arpt_entry *e
470                         = (struct arpt_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 arpt_standard_target *t
480                                 = (void *)arpt_get_target(e);
481
482                         if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
483                                 printk("arptables: loop hook %u pos %u %08X.\n",
484                                        hook, pos, e->comefrom);
485                                 return 0;
486                         }
487                         e->comefrom
488                                 |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));
489
490                         /* Unconditional return/END. */
491                         if (e->target_offset == sizeof(struct arpt_entry)
492                             && (strcmp(t->target.u.user.name,
493                                        ARPT_STANDARD_TARGET) == 0)
494                             && t->verdict < 0
495                             && unconditional(&e->arp)) {
496                                 unsigned int oldpos, size;
497
498                                 /* Return: backtrack through the last
499                                  * big jump.
500                                  */
501                                 do {
502                                         e->comefrom ^= (1<<NF_ARP_NUMHOOKS);
503                                         oldpos = pos;
504                                         pos = e->counters.pcnt;
505                                         e->counters.pcnt = 0;
506
507                                         /* We're at the start. */
508                                         if (pos == oldpos)
509                                                 goto next;
510
511                                         e = (struct arpt_entry *)
512                                                 (entry0 + pos);
513                                 } while (oldpos == pos + e->next_offset);
514
515                                 /* Move along one */
516                                 size = e->next_offset;
517                                 e = (struct arpt_entry *)
518                                         (entry0 + pos + size);
519                                 e->counters.pcnt = pos;
520                                 pos += size;
521                         } else {
522                                 int newpos = t->verdict;
523
524                                 if (strcmp(t->target.u.user.name,
525                                            ARPT_STANDARD_TARGET) == 0
526                                     && newpos >= 0) {
527                                         /* This a jump; chase it. */
528                                         duprintf("Jump rule %u -> %u\n",
529                                                  pos, newpos);
530                                 } else {
531                                         /* ... this is a fallthru */
532                                         newpos = pos + e->next_offset;
533                                 }
534                                 e = (struct arpt_entry *)
535                                         (entry0 + newpos);
536                                 e->counters.pcnt = pos;
537                                 pos = newpos;
538                         }
539                 }
540                 next:
541                 duprintf("Finished chain %u\n", hook);
542         }
543         return 1;
544 }
545
546 static inline int standard_check(const struct arpt_entry_target *t,
547                                  unsigned int max_offset)
548 {
549         struct arpt_standard_target *targ = (void *)t;
550
551         /* Check standard info. */
552         if (t->u.target_size
553             != ARPT_ALIGN(sizeof(struct arpt_standard_target))) {
554                 duprintf("arpt_standard_check: target size %u != %Zu\n",
555                          t->u.target_size,
556                          ARPT_ALIGN(sizeof(struct arpt_standard_target)));
557                 return 0;
558         }
559
560         if (targ->verdict >= 0
561             && targ->verdict > max_offset - sizeof(struct arpt_entry)) {
562                 duprintf("arpt_standard_check: bad verdict (%i)\n",
563                          targ->verdict);
564                 return 0;
565         }
566
567         if (targ->verdict < -NF_MAX_VERDICT - 1) {
568                 duprintf("arpt_standard_check: bad negative verdict (%i)\n",
569                          targ->verdict);
570                 return 0;
571         }
572         return 1;
573 }
574
575 static struct arpt_target arpt_standard_target;
576
577 static inline int check_entry(struct arpt_entry *e, const char *name, unsigned int size,
578                               unsigned int *i)
579 {
580         struct arpt_entry_target *t;
581         struct arpt_target *target;
582         int ret;
583
584         if (!arp_checkentry(&e->arp)) {
585                 duprintf("arp_tables: arp check failed %p %s.\n", e, name);
586                 return -EINVAL;
587         }
588
589         t = arpt_get_target(e);
590         target = try_then_request_module(find_target(t->u.user.name,
591                                                      t->u.user.revision),
592                                          "arpt_%s", t->u.user.name);
593         if (IS_ERR(target) || !target) {
594                 duprintf("check_entry: `%s' not found\n", t->u.user.name);
595                 ret = target ? PTR_ERR(target) : -ENOENT;
596                 goto out;
597         }
598         t->u.kernel.target = target;
599
600         if (t->u.kernel.target == &arpt_standard_target) {
601                 if (!standard_check(t, size)) {
602                         ret = -EINVAL;
603                         goto out;
604                 }
605         } else if (t->u.kernel.target->checkentry
606                    && !t->u.kernel.target->checkentry(name, e, t->data,
607                                                       t->u.target_size
608                                                       - sizeof(*t),
609                                                       e->comefrom)) {
610                 module_put(t->u.kernel.target->me);
611                 duprintf("arp_tables: check failed for `%s'.\n",
612                          t->u.kernel.target->name);
613                 ret = -EINVAL;
614                 goto out;
615         }
616
617         (*i)++;
618         return 0;
619
620 out:
621         return ret;
622 }
623
624 static inline int check_entry_size_and_hooks(struct arpt_entry *e,
625                                              struct arpt_table_info *newinfo,
626                                              unsigned char *base,
627                                              unsigned char *limit,
628                                              const unsigned int *hook_entries,
629                                              const unsigned int *underflows,
630                                              unsigned int *i)
631 {
632         unsigned int h;
633
634         if ((unsigned long)e % __alignof__(struct arpt_entry) != 0
635             || (unsigned char *)e + sizeof(struct arpt_entry) >= limit) {
636                 duprintf("Bad offset %p\n", e);
637                 return -EINVAL;
638         }
639
640         if (e->next_offset
641             < sizeof(struct arpt_entry) + sizeof(struct arpt_entry_target)) {
642                 duprintf("checking: element %p size %u\n",
643                          e, e->next_offset);
644                 return -EINVAL;
645         }
646
647         /* Check hooks & underflows */
648         for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
649                 if ((unsigned char *)e - base == hook_entries[h])
650                         newinfo->hook_entry[h] = hook_entries[h];
651                 if ((unsigned char *)e - base == underflows[h])
652                         newinfo->underflow[h] = underflows[h];
653         }
654
655         /* FIXME: underflows must be unconditional, standard verdicts
656            < 0 (not ARPT_RETURN). --RR */
657
658         /* Clear counters and comefrom */
659         e->counters = ((struct arpt_counters) { 0, 0 });
660         e->comefrom = 0;
661
662         (*i)++;
663         return 0;
664 }
665
666 static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
667 {
668         struct arpt_entry_target *t;
669
670         if (i && (*i)-- == 0)
671                 return 1;
672
673         t = arpt_get_target(e);
674         if (t->u.kernel.target->destroy)
675                 t->u.kernel.target->destroy(t->data,
676                                             t->u.target_size - sizeof(*t));
677         module_put(t->u.kernel.target->me);
678         return 0;
679 }
680
681 /* Checks and translates the user-supplied table segment (held in
682  * newinfo).
683  */
684 static int translate_table(const char *name,
685                            unsigned int valid_hooks,
686                            struct arpt_table_info *newinfo,
687                            void *entry0,
688                            unsigned int size,
689                            unsigned int number,
690                            const unsigned int *hook_entries,
691                            const unsigned int *underflows)
692 {
693         unsigned int i;
694         int ret;
695
696         newinfo->size = size;
697         newinfo->number = number;
698
699         /* Init all hooks to impossible value. */
700         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
701                 newinfo->hook_entry[i] = 0xFFFFFFFF;
702                 newinfo->underflow[i] = 0xFFFFFFFF;
703         }
704
705         duprintf("translate_table: size %u\n", newinfo->size);
706         i = 0;
707
708         /* Walk through entries, checking offsets. */
709         ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
710                                  check_entry_size_and_hooks,
711                                  newinfo,
712                                  entry0,
713                                  entry0 + size,
714                                  hook_entries, underflows, &i);
715         duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);
716         if (ret != 0)
717                 return ret;
718
719         if (i != number) {
720                 duprintf("translate_table: %u not %u entries\n",
721                          i, number);
722                 return -EINVAL;
723         }
724
725         /* Check hooks all assigned */
726         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
727                 /* Only hooks which are valid */
728                 if (!(valid_hooks & (1 << i)))
729                         continue;
730                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
731                         duprintf("Invalid hook entry %u %u\n",
732                                  i, hook_entries[i]);
733                         return -EINVAL;
734                 }
735                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
736                         duprintf("Invalid underflow %u %u\n",
737                                  i, underflows[i]);
738                         return -EINVAL;
739                 }
740         }
741
742         if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
743                 duprintf("Looping hook\n");
744                 return -ELOOP;
745         }
746
747         /* Finally, each sanity check must pass */
748         i = 0;
749         ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
750                                  check_entry, name, size, &i);
751
752         if (ret != 0) {
753                 ARPT_ENTRY_ITERATE(entry0, newinfo->size,
754                                    cleanup_entry, &i);
755                 return ret;
756         }
757
758         /* And one copy for every other CPU */
759         for_each_cpu(i) {
760                 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
761                         memcpy(newinfo->entries[i], entry0, newinfo->size);
762         }
763
764         return ret;
765 }
766
767 static struct arpt_table_info *replace_table(struct arpt_table *table,
768                                              unsigned int num_counters,
769                                              struct arpt_table_info *newinfo,
770                                              int *error)
771 {
772         struct arpt_table_info *oldinfo;
773
774         /* Do the substitution. */
775         write_lock_bh(&table->lock);
776         /* Check inside lock: is the old number correct? */
777         if (num_counters != table->private->number) {
778                 duprintf("num_counters != table->private->number (%u/%u)\n",
779                          num_counters, table->private->number);
780                 write_unlock_bh(&table->lock);
781                 *error = -EAGAIN;
782                 return NULL;
783         }
784         oldinfo = table->private;
785         table->private = newinfo;
786         newinfo->initial_entries = oldinfo->initial_entries;
787         write_unlock_bh(&table->lock);
788
789         return oldinfo;
790 }
791
792 /* Gets counters. */
793 static inline int add_entry_to_counter(const struct arpt_entry *e,
794                                        struct arpt_counters total[],
795                                        unsigned int *i)
796 {
797         ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
798
799         (*i)++;
800         return 0;
801 }
802
803 static inline int set_entry_to_counter(const struct arpt_entry *e,
804                                        struct arpt_counters total[],
805                                        unsigned int *i)
806 {
807         SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
808
809         (*i)++;
810         return 0;
811 }
812
813 static void get_counters(const struct arpt_table_info *t,
814                          struct arpt_counters counters[])
815 {
816         unsigned int cpu;
817         unsigned int i;
818         unsigned int curcpu;
819
820         /* Instead of clearing (by a previous call to memset())
821          * the counters and using adds, we set the counters
822          * with data used by 'current' CPU
823          * We dont care about preemption here.
824          */
825         curcpu = raw_smp_processor_id();
826
827         i = 0;
828         ARPT_ENTRY_ITERATE(t->entries[curcpu],
829                            t->size,
830                            set_entry_to_counter,
831                            counters,
832                            &i);
833
834         for_each_cpu(cpu) {
835                 if (cpu == curcpu)
836                         continue;
837                 i = 0;
838                 ARPT_ENTRY_ITERATE(t->entries[cpu],
839                                    t->size,
840                                    add_entry_to_counter,
841                                    counters,
842                                    &i);
843         }
844 }
845
846 static int copy_entries_to_user(unsigned int total_size,
847                                 struct arpt_table *table,
848                                 void __user *userptr)
849 {
850         unsigned int off, num, countersize;
851         struct arpt_entry *e;
852         struct arpt_counters *counters;
853         int ret = 0;
854         void *loc_cpu_entry;
855
856         /* We need atomic snapshot of counters: rest doesn't change
857          * (other than comefrom, which userspace doesn't care
858          * about).
859          */
860         countersize = sizeof(struct arpt_counters) * table->private->number;
861         counters = vmalloc(countersize);
862
863         if (counters == NULL)
864                 return -ENOMEM;
865
866         /* First, sum counters... */
867         write_lock_bh(&table->lock);
868         get_counters(table->private, counters);
869         write_unlock_bh(&table->lock);
870
871         loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
872         /* ... then copy entire thing ... */
873         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
874                 ret = -EFAULT;
875                 goto free_counters;
876         }
877
878         /* FIXME: use iterator macros --RR */
879         /* ... then go back and fix counters and names */
880         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
881                 struct arpt_entry_target *t;
882
883                 e = (struct arpt_entry *)(loc_cpu_entry + off);
884                 if (copy_to_user(userptr + off
885                                  + offsetof(struct arpt_entry, counters),
886                                  &counters[num],
887                                  sizeof(counters[num])) != 0) {
888                         ret = -EFAULT;
889                         goto free_counters;
890                 }
891
892                 t = arpt_get_target(e);
893                 if (copy_to_user(userptr + off + e->target_offset
894                                  + offsetof(struct arpt_entry_target,
895                                             u.user.name),
896                                  t->u.kernel.target->name,
897                                  strlen(t->u.kernel.target->name)+1) != 0) {
898                         ret = -EFAULT;
899                         goto free_counters;
900                 }
901         }
902
903  free_counters:
904         vfree(counters);
905         return ret;
906 }
907
908 static int get_entries(const struct arpt_get_entries *entries,
909                        struct arpt_get_entries __user *uptr)
910 {
911         int ret;
912         struct arpt_table *t;
913
914         t = find_table_lock(entries->name);
915         if (t || !IS_ERR(t)) {
916                 duprintf("t->private->number = %u\n",
917                          t->private->number);
918                 if (entries->size == t->private->size)
919                         ret = copy_entries_to_user(t->private->size,
920                                                    t, uptr->entrytable);
921                 else {
922                         duprintf("get_entries: I've got %u not %u!\n",
923                                  t->private->size,
924                                  entries->size);
925                         ret = -EINVAL;
926                 }
927                 module_put(t->me);
928                 up(&arpt_mutex);
929         } else
930                 ret = t ? PTR_ERR(t) : -ENOENT;
931
932         return ret;
933 }
934
935 static void free_table_info(struct arpt_table_info *info)
936 {
937         int cpu;
938         for_each_cpu(cpu) {
939                 if (info->size <= PAGE_SIZE)
940                         kfree(info->entries[cpu]);
941                 else
942                         vfree(info->entries[cpu]);
943         }
944         kfree(info);
945 }
946
947 static struct arpt_table_info *alloc_table_info(unsigned int size)
948 {
949         struct arpt_table_info *newinfo;
950         int cpu;
951         
952         newinfo = kzalloc(sizeof(struct arpt_table_info), GFP_KERNEL);
953         if (!newinfo)
954                 return NULL;
955
956         newinfo->size = size;
957
958         for_each_cpu(cpu) {
959                 if (size <= PAGE_SIZE)
960                         newinfo->entries[cpu] = kmalloc_node(size,
961                                                         GFP_KERNEL,
962                                                         cpu_to_node(cpu));
963                 else
964                         newinfo->entries[cpu] = vmalloc_node(size,
965                                                              cpu_to_node(cpu));
966
967                 if (newinfo->entries[cpu] == NULL) {
968                         free_table_info(newinfo);
969                         return NULL;
970                 }
971         }
972
973         return newinfo;
974 }
975
976 static int do_replace(void __user *user, unsigned int len)
977 {
978         int ret;
979         struct arpt_replace tmp;
980         struct arpt_table *t;
981         struct arpt_table_info *newinfo, *oldinfo;
982         struct arpt_counters *counters;
983         void *loc_cpu_entry, *loc_cpu_old_entry;
984
985         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
986                 return -EFAULT;
987
988         /* Hack: Causes ipchains to give correct error msg --RR */
989         if (len != sizeof(tmp) + tmp.size)
990                 return -ENOPROTOOPT;
991
992         /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
993         if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
994                 return -ENOMEM;
995
996         newinfo = alloc_table_info(tmp.size);
997         if (!newinfo)
998                 return -ENOMEM;
999
1000         /* choose the copy that is on our node/cpu */
1001         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1002         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1003                            tmp.size) != 0) {
1004                 ret = -EFAULT;
1005                 goto free_newinfo;
1006         }
1007
1008         counters = vmalloc(tmp.num_counters * sizeof(struct arpt_counters));
1009         if (!counters) {
1010                 ret = -ENOMEM;
1011                 goto free_newinfo;
1012         }
1013
1014         ret = translate_table(tmp.name, tmp.valid_hooks,
1015                               newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1016                               tmp.hook_entry, tmp.underflow);
1017         if (ret != 0)
1018                 goto free_newinfo_counters;
1019
1020         duprintf("arp_tables: Translated table\n");
1021
1022         t = try_then_request_module(find_table_lock(tmp.name),
1023                                     "arptable_%s", tmp.name);
1024         if (!t || IS_ERR(t)) {
1025                 ret = t ? PTR_ERR(t) : -ENOENT;
1026                 goto free_newinfo_counters_untrans;
1027         }
1028
1029         /* You lied! */
1030         if (tmp.valid_hooks != t->valid_hooks) {
1031                 duprintf("Valid hook crap: %08X vs %08X\n",
1032                          tmp.valid_hooks, t->valid_hooks);
1033                 ret = -EINVAL;
1034                 goto put_module;
1035         }
1036
1037         oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1038         if (!oldinfo)
1039                 goto put_module;
1040
1041         /* Update module usage count based on number of rules */
1042         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1043                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1044         if ((oldinfo->number > oldinfo->initial_entries) || 
1045             (newinfo->number <= oldinfo->initial_entries)) 
1046                 module_put(t->me);
1047         if ((oldinfo->number > oldinfo->initial_entries) &&
1048             (newinfo->number <= oldinfo->initial_entries))
1049                 module_put(t->me);
1050
1051         /* Get the old counters. */
1052         get_counters(oldinfo, counters);
1053         /* Decrease module usage counts and free resource */
1054         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1055         ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1056
1057         free_table_info(oldinfo);
1058         if (copy_to_user(tmp.counters, counters,
1059                          sizeof(struct arpt_counters) * tmp.num_counters) != 0)
1060                 ret = -EFAULT;
1061         vfree(counters);
1062         up(&arpt_mutex);
1063         return ret;
1064
1065  put_module:
1066         module_put(t->me);
1067         up(&arpt_mutex);
1068  free_newinfo_counters_untrans:
1069         ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1070  free_newinfo_counters:
1071         vfree(counters);
1072  free_newinfo:
1073         free_table_info(newinfo);
1074         return ret;
1075 }
1076
1077 /* We're lazy, and add to the first CPU; overflow works its fey magic
1078  * and everything is OK.
1079  */
1080 static inline int add_counter_to_entry(struct arpt_entry *e,
1081                                        const struct arpt_counters addme[],
1082                                        unsigned int *i)
1083 {
1084
1085         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1086
1087         (*i)++;
1088         return 0;
1089 }
1090
1091 static int do_add_counters(void __user *user, unsigned int len)
1092 {
1093         unsigned int i;
1094         struct arpt_counters_info tmp, *paddc;
1095         struct arpt_table *t;
1096         int ret = 0;
1097         void *loc_cpu_entry;
1098
1099         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1100                 return -EFAULT;
1101
1102         if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct arpt_counters))
1103                 return -EINVAL;
1104
1105         paddc = vmalloc(len);
1106         if (!paddc)
1107                 return -ENOMEM;
1108
1109         if (copy_from_user(paddc, user, len) != 0) {
1110                 ret = -EFAULT;
1111                 goto free;
1112         }
1113
1114         t = find_table_lock(tmp.name);
1115         if (!t || IS_ERR(t)) {
1116                 ret = t ? PTR_ERR(t) : -ENOENT;
1117                 goto free;
1118         }
1119
1120         write_lock_bh(&t->lock);
1121         if (t->private->number != paddc->num_counters) {
1122                 ret = -EINVAL;
1123                 goto unlock_up_free;
1124         }
1125
1126         i = 0;
1127         /* Choose the copy that is on our node */
1128         loc_cpu_entry = t->private->entries[smp_processor_id()];
1129         ARPT_ENTRY_ITERATE(loc_cpu_entry,
1130                            t->private->size,
1131                            add_counter_to_entry,
1132                            paddc->counters,
1133                            &i);
1134  unlock_up_free:
1135         write_unlock_bh(&t->lock);
1136         up(&arpt_mutex);
1137         module_put(t->me);
1138  free:
1139         vfree(paddc);
1140
1141         return ret;
1142 }
1143
1144 static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1145 {
1146         int ret;
1147
1148         if (!capable(CAP_NET_ADMIN))
1149                 return -EPERM;
1150
1151         switch (cmd) {
1152         case ARPT_SO_SET_REPLACE:
1153                 ret = do_replace(user, len);
1154                 break;
1155
1156         case ARPT_SO_SET_ADD_COUNTERS:
1157                 ret = do_add_counters(user, len);
1158                 break;
1159
1160         default:
1161                 duprintf("do_arpt_set_ctl:  unknown request %i\n", cmd);
1162                 ret = -EINVAL;
1163         }
1164
1165         return ret;
1166 }
1167
1168 static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1169 {
1170         int ret;
1171
1172         if (!capable(CAP_NET_ADMIN))
1173                 return -EPERM;
1174
1175         switch (cmd) {
1176         case ARPT_SO_GET_INFO: {
1177                 char name[ARPT_TABLE_MAXNAMELEN];
1178                 struct arpt_table *t;
1179
1180                 if (*len != sizeof(struct arpt_getinfo)) {
1181                         duprintf("length %u != %Zu\n", *len,
1182                                  sizeof(struct arpt_getinfo));
1183                         ret = -EINVAL;
1184                         break;
1185                 }
1186
1187                 if (copy_from_user(name, user, sizeof(name)) != 0) {
1188                         ret = -EFAULT;
1189                         break;
1190                 }
1191                 name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
1192
1193                 t = try_then_request_module(find_table_lock(name),
1194                                             "arptable_%s", name);
1195                 if (t && !IS_ERR(t)) {
1196                         struct arpt_getinfo info;
1197
1198                         info.valid_hooks = t->valid_hooks;
1199                         memcpy(info.hook_entry, t->private->hook_entry,
1200                                sizeof(info.hook_entry));
1201                         memcpy(info.underflow, t->private->underflow,
1202                                sizeof(info.underflow));
1203                         info.num_entries = t->private->number;
1204                         info.size = t->private->size;
1205                         strcpy(info.name, name);
1206
1207                         if (copy_to_user(user, &info, *len) != 0)
1208                                 ret = -EFAULT;
1209                         else
1210                                 ret = 0;
1211                         up(&arpt_mutex);
1212                         module_put(t->me);
1213                 } else
1214                         ret = t ? PTR_ERR(t) : -ENOENT;
1215         }
1216         break;
1217
1218         case ARPT_SO_GET_ENTRIES: {
1219                 struct arpt_get_entries get;
1220
1221                 if (*len < sizeof(get)) {
1222                         duprintf("get_entries: %u < %Zu\n", *len, sizeof(get));
1223                         ret = -EINVAL;
1224                 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1225                         ret = -EFAULT;
1226                 } else if (*len != sizeof(struct arpt_get_entries) + get.size) {
1227                         duprintf("get_entries: %u != %Zu\n", *len,
1228                                  sizeof(struct arpt_get_entries) + get.size);
1229                         ret = -EINVAL;
1230                 } else
1231                         ret = get_entries(&get, user);
1232                 break;
1233         }
1234
1235         case ARPT_SO_GET_REVISION_TARGET: {
1236                 struct arpt_get_revision rev;
1237
1238                 if (*len != sizeof(rev)) {
1239                         ret = -EINVAL;
1240                         break;
1241                 }
1242                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1243                         ret = -EFAULT;
1244                         break;
1245                 }
1246
1247                 try_then_request_module(find_revision(rev.name, rev.revision,
1248                                                       target_revfn, &ret),
1249                                         "arpt_%s", rev.name);
1250                 break;
1251         }
1252
1253         default:
1254                 duprintf("do_arpt_get_ctl: unknown request %i\n", cmd);
1255                 ret = -EINVAL;
1256         }
1257
1258         return ret;
1259 }
1260
1261 /* Registration hooks for targets. */
1262 int arpt_register_target(struct arpt_target *target)
1263 {
1264         int ret;
1265
1266         ret = down_interruptible(&arpt_mutex);
1267         if (ret != 0)
1268                 return ret;
1269
1270         list_add(&target->list, &arpt_target);
1271         up(&arpt_mutex);
1272
1273         return ret;
1274 }
1275
1276 void arpt_unregister_target(struct arpt_target *target)
1277 {
1278         down(&arpt_mutex);
1279         LIST_DELETE(&arpt_target, target);
1280         up(&arpt_mutex);
1281 }
1282
1283 int arpt_register_table(struct arpt_table *table,
1284                         const struct arpt_replace *repl)
1285 {
1286         int ret;
1287         struct arpt_table_info *newinfo;
1288         static struct arpt_table_info bootstrap
1289                 = { 0, 0, 0, { 0 }, { 0 }, { } };
1290         void *loc_cpu_entry;
1291
1292         newinfo = alloc_table_info(repl->size);
1293         if (!newinfo) {
1294                 ret = -ENOMEM;
1295                 return ret;
1296         }
1297
1298         /* choose the copy on our node/cpu */
1299         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1300         memcpy(loc_cpu_entry, repl->entries, repl->size);
1301
1302         ret = translate_table(table->name, table->valid_hooks,
1303                               newinfo, loc_cpu_entry, repl->size,
1304                               repl->num_entries,
1305                               repl->hook_entry,
1306                               repl->underflow);
1307         duprintf("arpt_register_table: translate table gives %d\n", ret);
1308         if (ret != 0) {
1309                 free_table_info(newinfo);
1310                 return ret;
1311         }
1312
1313         ret = down_interruptible(&arpt_mutex);
1314         if (ret != 0) {
1315                 free_table_info(newinfo);
1316                 return ret;
1317         }
1318
1319         /* Don't autoload: we'd eat our tail... */
1320         if (list_named_find(&arpt_tables, table->name)) {
1321                 ret = -EEXIST;
1322                 goto free_unlock;
1323         }
1324
1325         /* Simplifies replace_table code. */
1326         table->private = &bootstrap;
1327         if (!replace_table(table, 0, newinfo, &ret))
1328                 goto free_unlock;
1329
1330         duprintf("table->private->number = %u\n",
1331                  table->private->number);
1332         
1333         /* save number of initial entries */
1334         table->private->initial_entries = table->private->number;
1335
1336         rwlock_init(&table->lock);
1337         list_prepend(&arpt_tables, table);
1338
1339  unlock:
1340         up(&arpt_mutex);
1341         return ret;
1342
1343  free_unlock:
1344         free_table_info(newinfo);
1345         goto unlock;
1346 }
1347
1348 void arpt_unregister_table(struct arpt_table *table)
1349 {
1350         void *loc_cpu_entry;
1351
1352         down(&arpt_mutex);
1353         LIST_DELETE(&arpt_tables, table);
1354         up(&arpt_mutex);
1355
1356         /* Decrease module usage counts and free resources */
1357         loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
1358         ARPT_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
1359                            cleanup_entry, NULL);
1360         free_table_info(table->private);
1361 }
1362
1363 /* The built-in targets: standard (NULL) and error. */
1364 static struct arpt_target arpt_standard_target = {
1365         .name           = ARPT_STANDARD_TARGET,
1366 };
1367
1368 static struct arpt_target arpt_error_target = {
1369         .name           = ARPT_ERROR_TARGET,
1370         .target         = arpt_error,
1371 };
1372
1373 static struct nf_sockopt_ops arpt_sockopts = {
1374         .pf             = PF_INET,
1375         .set_optmin     = ARPT_BASE_CTL,
1376         .set_optmax     = ARPT_SO_SET_MAX+1,
1377         .set            = do_arpt_set_ctl,
1378         .get_optmin     = ARPT_BASE_CTL,
1379         .get_optmax     = ARPT_SO_GET_MAX+1,
1380         .get            = do_arpt_get_ctl,
1381 };
1382
1383 #ifdef CONFIG_PROC_FS
1384 static inline int print_name(const struct arpt_table *t,
1385                              off_t start_offset, char *buffer, int length,
1386                              off_t *pos, unsigned int *count)
1387 {
1388         if ((*count)++ >= start_offset) {
1389                 unsigned int namelen;
1390
1391                 namelen = sprintf(buffer + *pos, "%s\n", t->name);
1392                 if (*pos + namelen > length) {
1393                         /* Stop iterating */
1394                         return 1;
1395                 }
1396                 *pos += namelen;
1397         }
1398         return 0;
1399 }
1400
1401 static int arpt_get_tables(char *buffer, char **start, off_t offset, int length)
1402 {
1403         off_t pos = 0;
1404         unsigned int count = 0;
1405
1406         if (down_interruptible(&arpt_mutex) != 0)
1407                 return 0;
1408
1409         LIST_FIND(&arpt_tables, print_name, struct arpt_table *,
1410                   offset, buffer, length, &pos, &count);
1411
1412         up(&arpt_mutex);
1413
1414         /* `start' hack - see fs/proc/generic.c line ~105 */
1415         *start=(char *)((unsigned long)count-offset);
1416         return pos;
1417 }
1418 #endif /*CONFIG_PROC_FS*/
1419
1420 static int __init init(void)
1421 {
1422         int ret;
1423
1424         /* Noone else will be downing sem now, so we won't sleep */
1425         down(&arpt_mutex);
1426         list_append(&arpt_target, &arpt_standard_target);
1427         list_append(&arpt_target, &arpt_error_target);
1428         up(&arpt_mutex);
1429
1430         /* Register setsockopt */
1431         ret = nf_register_sockopt(&arpt_sockopts);
1432         if (ret < 0) {
1433                 duprintf("Unable to register sockopts.\n");
1434                 return ret;
1435         }
1436
1437 #ifdef CONFIG_PROC_FS
1438         {
1439                 struct proc_dir_entry *proc;
1440
1441                 proc = proc_net_create("arp_tables_names", 0, arpt_get_tables);
1442                 if (!proc) {
1443                         nf_unregister_sockopt(&arpt_sockopts);
1444                         return -ENOMEM;
1445                 }
1446                 proc->owner = THIS_MODULE;
1447         }
1448 #endif
1449
1450         printk("arp_tables: (C) 2002 David S. Miller\n");
1451         return 0;
1452 }
1453
1454 static void __exit fini(void)
1455 {
1456         nf_unregister_sockopt(&arpt_sockopts);
1457 #ifdef CONFIG_PROC_FS
1458         proc_net_remove("arp_tables_names");
1459 #endif
1460 }
1461
1462 EXPORT_SYMBOL(arpt_register_table);
1463 EXPORT_SYMBOL(arpt_unregister_table);
1464 EXPORT_SYMBOL(arpt_do_table);
1465 EXPORT_SYMBOL(arpt_register_target);
1466 EXPORT_SYMBOL(arpt_unregister_target);
1467
1468 module_init(init);
1469 module_exit(fini);