]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/netfilter/arp_tables.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6
[linux-2.6-omap-h63xx.git] / net / ipv4 / netfilter / arp_tables.c
index b4a810c28ac85c3f79e6e350ea985b8a85ba380d..03e83a65aec5eca5dab1b1c99401c3ac40985ed2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <net/compat.h>
+#include <net/sock.h>
 #include <asm/uaccess.h>
 
 #include <linux/netfilter/x_tables.h>
@@ -51,14 +52,14 @@ MODULE_DESCRIPTION("arptables core");
 do {                                                           \
        if (!(x))                                               \
                printk("ARP_NF_ASSERT: %s:%s:%u\n",             \
-                      __FUNCTION__, __FILE__, __LINE__);       \
+                      __func__, __FILE__, __LINE__);   \
 } while(0)
 #else
 #define ARP_NF_ASSERT(x)
 #endif
 
 static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
-                                     char *hdr_addr, int len)
+                                     const char *hdr_addr, int len)
 {
        int i, ret;
 
@@ -79,8 +80,8 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
                                   const char *outdev,
                                   const struct arpt_arp *arpinfo)
 {
-       char *arpptr = (char *)(arphdr + 1);
-       char *src_devaddr, *tgt_devaddr;
+       const char *arpptr = (char *)(arphdr + 1);
+       const char *src_devaddr, *tgt_devaddr;
        __be32 src_ipaddr, tgt_ipaddr;
        int i, ret;
 
@@ -221,21 +222,18 @@ unsigned int arpt_do_table(struct sk_buff *skb,
                           unsigned int hook,
                           const struct net_device *in,
                           const struct net_device *out,
-                          struct arpt_table *table)
+                          struct xt_table *table)
 {
        static const char nulldevname[IFNAMSIZ];
        unsigned int verdict = NF_DROP;
-       struct arphdr *arp;
+       const struct arphdr *arp;
        bool hotdrop = false;
        struct arpt_entry *e, *back;
        const char *indev, *outdev;
        void *table_base;
-       struct xt_table_info *private;
+       const struct xt_table_info *private;
 
-       /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
-       if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
-                                (2 * skb->dev->addr_len) +
-                                (2 * sizeof(u32)))))
+       if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
                return NF_DROP;
 
        indev = in ? in->name : nulldevname;
@@ -354,7 +352,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
                e->counters.pcnt = pos;
 
                for (;;) {
-                       struct arpt_standard_target *t
+                       const struct arpt_standard_target *t
                                = (void *)arpt_get_target(e);
                        int visited = e->comefrom & (1 << hook);
 
@@ -439,7 +437,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
 
 static inline int check_entry(struct arpt_entry *e, const char *name)
 {
-       struct arpt_entry_target *t;
+       const struct arpt_entry_target *t;
 
        if (!arp_checkentry(&e->arp)) {
                duprintf("arp_tables: arp check failed %p %s.\n", e, name);
@@ -459,7 +457,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name)
 static inline int check_target(struct arpt_entry *e, const char *name)
 {
        struct arpt_entry_target *t;
-       struct arpt_target *target;
+       struct xt_target *target;
        int ret;
 
        t = arpt_get_target(e);
@@ -482,7 +480,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
                 unsigned int *i)
 {
        struct arpt_entry_target *t;
-       struct arpt_target *target;
+       struct xt_target *target;
        int ret;
 
        ret = check_entry(e, name);
@@ -708,11 +706,11 @@ static void get_counters(const struct xt_table_info *t,
        }
 }
 
-static inline struct xt_counters *alloc_counters(struct arpt_table *table)
+static inline struct xt_counters *alloc_counters(struct xt_table *table)
 {
        unsigned int countersize;
        struct xt_counters *counters;
-       struct xt_table_info *private = table->private;
+       const struct xt_table_info *private = table->private;
 
        /* We need atomic snapshot of counters: rest doesn't change
         * (other than comefrom, which userspace doesn't care
@@ -733,7 +731,7 @@ static inline struct xt_counters *alloc_counters(struct arpt_table *table)
 }
 
 static int copy_entries_to_user(unsigned int total_size,
-                               struct arpt_table *table,
+                               struct xt_table *table,
                                void __user *userptr)
 {
        unsigned int off, num;
@@ -850,10 +848,10 @@ static int compat_table_info(const struct xt_table_info *info,
 }
 #endif
 
-static int get_info(void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user, int *len, int compat)
 {
        char name[ARPT_TABLE_MAXNAMELEN];
-       struct arpt_table *t;
+       struct xt_table *t;
        int ret;
 
        if (*len != sizeof(struct arpt_getinfo)) {
@@ -870,11 +868,11 @@ static int get_info(void __user *user, int *len, int compat)
        if (compat)
                xt_compat_lock(NF_ARP);
 #endif
-       t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
+       t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
                                    "arptable_%s", name);
        if (t && !IS_ERR(t)) {
                struct arpt_getinfo info;
-               struct xt_table_info *private = t->private;
+               const struct xt_table_info *private = t->private;
 
 #ifdef CONFIG_COMPAT
                if (compat) {
@@ -908,11 +906,12 @@ static int get_info(void __user *user, int *len, int compat)
        return ret;
 }
 
-static int get_entries(struct arpt_get_entries __user *uptr, int *len)
+static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
+                      int *len)
 {
        int ret;
        struct arpt_get_entries get;
-       struct arpt_table *t;
+       struct xt_table *t;
 
        if (*len < sizeof(get)) {
                duprintf("get_entries: %u < %Zu\n", *len, sizeof(get));
@@ -926,9 +925,10 @@ static int get_entries(struct arpt_get_entries __user *uptr, int *len)
                return -EINVAL;
        }
 
-       t = xt_find_table_lock(NF_ARP, get.name);
+       t = xt_find_table_lock(net, NF_ARP, get.name);
        if (t && !IS_ERR(t)) {
-               struct xt_table_info *private = t->private;
+               const struct xt_table_info *private = t->private;
+
                duprintf("t->private->number = %u\n",
                         private->number);
                if (get.size == private->size)
@@ -937,7 +937,7 @@ static int get_entries(struct arpt_get_entries __user *uptr, int *len)
                else {
                        duprintf("get_entries: I've got %u not %u!\n",
                                 private->size, get.size);
-                       ret = -EINVAL;
+                       ret = -EAGAIN;
                }
                module_put(t->me);
                xt_table_unlock(t);
@@ -947,13 +947,14 @@ static int get_entries(struct arpt_get_entries __user *uptr, int *len)
        return ret;
 }
 
-static int __do_replace(const char *name, unsigned int valid_hooks,
+static int __do_replace(struct net *net, const char *name,
+                       unsigned int valid_hooks,
                        struct xt_table_info *newinfo,
                        unsigned int num_counters,
                        void __user *counters_ptr)
 {
        int ret;
-       struct arpt_table *t;
+       struct xt_table *t;
        struct xt_table_info *oldinfo;
        struct xt_counters *counters;
        void *loc_cpu_old_entry;
@@ -966,7 +967,7 @@ static int __do_replace(const char *name, unsigned int valid_hooks,
                goto out;
        }
 
-       t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
+       t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
                                    "arptable_%s", name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1019,7 +1020,7 @@ static int __do_replace(const char *name, unsigned int valid_hooks,
        return ret;
 }
 
-static int do_replace(void __user *user, unsigned int len)
+static int do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct arpt_replace tmp;
@@ -1053,7 +1054,7 @@ static int do_replace(void __user *user, unsigned int len)
 
        duprintf("arp_tables: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, tmp.counters);
        if (ret)
                goto free_newinfo_untrans;
@@ -1080,17 +1081,18 @@ static inline int add_counter_to_entry(struct arpt_entry *e,
        return 0;
 }
 
-static int do_add_counters(void __user *user, unsigned int len, int compat)
+static int do_add_counters(struct net *net, void __user *user, unsigned int len,
+                          int compat)
 {
        unsigned int i;
        struct xt_counters_info tmp;
        struct xt_counters *paddc;
        unsigned int num_counters;
-       char *name;
+       const char *name;
        int size;
        void *ptmp;
-       struct arpt_table *t;
-       struct xt_table_info *private;
+       struct xt_table *t;
+       const struct xt_table_info *private;
        int ret = 0;
        void *loc_cpu_entry;
 #ifdef CONFIG_COMPAT
@@ -1132,7 +1134,7 @@ static int do_add_counters(void __user *user, unsigned int len, int compat)
                goto free;
        }
 
-       t = xt_find_table_lock(NF_ARP, name);
+       t = xt_find_table_lock(net, NF_ARP, name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
@@ -1435,7 +1437,8 @@ struct compat_arpt_replace {
        struct compat_arpt_entry        entries[0];
 };
 
-static int compat_do_replace(void __user *user, unsigned int len)
+static int compat_do_replace(struct net *net, void __user *user,
+                            unsigned int len)
 {
        int ret;
        struct compat_arpt_replace tmp;
@@ -1471,7 +1474,7 @@ static int compat_do_replace(void __user *user, unsigned int len)
 
        duprintf("compat_do_replace: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, compat_ptr(tmp.counters));
        if (ret)
                goto free_newinfo_untrans;
@@ -1494,11 +1497,11 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
 
        switch (cmd) {
        case ARPT_SO_SET_REPLACE:
-               ret = compat_do_replace(user, len);
+               ret = compat_do_replace(sock_net(sk), user, len);
                break;
 
        case ARPT_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 1);
+               ret = do_add_counters(sock_net(sk), user, len, 1);
                break;
 
        default:
@@ -1552,11 +1555,11 @@ out:
 }
 
 static int compat_copy_entries_to_user(unsigned int total_size,
-                                      struct arpt_table *table,
+                                      struct xt_table *table,
                                       void __user *userptr)
 {
        struct xt_counters *counters;
-       struct xt_table_info *private = table->private;
+       const struct xt_table_info *private = table->private;
        void __user *pos;
        unsigned int size;
        int ret = 0;
@@ -1584,12 +1587,13 @@ struct compat_arpt_get_entries {
        struct compat_arpt_entry entrytable[0];
 };
 
-static int compat_get_entries(struct compat_arpt_get_entries __user *uptr,
+static int compat_get_entries(struct net *net,
+                             struct compat_arpt_get_entries __user *uptr,
                              int *len)
 {
        int ret;
        struct compat_arpt_get_entries get;
-       struct arpt_table *t;
+       struct xt_table *t;
 
        if (*len < sizeof(get)) {
                duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
@@ -1604,9 +1608,9 @@ static int compat_get_entries(struct compat_arpt_get_entries __user *uptr,
        }
 
        xt_compat_lock(NF_ARP);
-       t = xt_find_table_lock(NF_ARP, get.name);
+       t = xt_find_table_lock(net, NF_ARP, get.name);
        if (t && !IS_ERR(t)) {
-               struct xt_table_info *private = t->private;
+               const struct xt_table_info *private = t->private;
                struct xt_table_info info;
 
                duprintf("t->private->number = %u\n", private->number);
@@ -1617,7 +1621,7 @@ static int compat_get_entries(struct compat_arpt_get_entries __user *uptr,
                } else if (!ret) {
                        duprintf("compat_get_entries: I've got %u not %u!\n",
                                 private->size, get.size);
-                       ret = -EINVAL;
+                       ret = -EAGAIN;
                }
                xt_compat_flush_offsets(NF_ARP);
                module_put(t->me);
@@ -1641,10 +1645,10 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
 
        switch (cmd) {
        case ARPT_SO_GET_INFO:
-               ret = get_info(user, len, 1);
+               ret = get_info(sock_net(sk), user, len, 1);
                break;
        case ARPT_SO_GET_ENTRIES:
-               ret = compat_get_entries(user, len);
+               ret = compat_get_entries(sock_net(sk), user, len);
                break;
        default:
                ret = do_arpt_get_ctl(sk, cmd, user, len);
@@ -1662,11 +1666,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
 
        switch (cmd) {
        case ARPT_SO_SET_REPLACE:
-               ret = do_replace(user, len);
+               ret = do_replace(sock_net(sk), user, len);
                break;
 
        case ARPT_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 0);
+               ret = do_add_counters(sock_net(sk), user, len, 0);
                break;
 
        default:
@@ -1686,11 +1690,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
 
        switch (cmd) {
        case ARPT_SO_GET_INFO:
-               ret = get_info(user, len, 0);
+               ret = get_info(sock_net(sk), user, len, 0);
                break;
 
        case ARPT_SO_GET_ENTRIES:
-               ret = get_entries(user, len);
+               ret = get_entries(sock_net(sk), user, len);
                break;
 
        case ARPT_SO_GET_REVISION_TARGET: {
@@ -1719,19 +1723,20 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
        return ret;
 }
 
-int arpt_register_table(struct arpt_table *table,
-                       const struct arpt_replace *repl)
+struct xt_table *arpt_register_table(struct net *net, struct xt_table *table,
+                                    const struct arpt_replace *repl)
 {
        int ret;
        struct xt_table_info *newinfo;
        struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
+       struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
        if (!newinfo) {
                ret = -ENOMEM;
-               return ret;
+               goto out;
        }
 
        /* choose the copy on our node/cpu */
@@ -1745,24 +1750,27 @@ int arpt_register_table(struct arpt_table *table,
                              repl->underflow);
 
        duprintf("arpt_register_table: translate table gives %d\n", ret);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
-       }
+       if (ret != 0)
+               goto out_free;
 
-       ret = xt_register_table(table, &bootstrap, newinfo);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
+       new_table = xt_register_table(net, table, &bootstrap, newinfo);
+       if (IS_ERR(new_table)) {
+               ret = PTR_ERR(new_table);
+               goto out_free;
        }
+       return new_table;
 
-       return 0;
+out_free:
+       xt_free_table_info(newinfo);
+out:
+       return ERR_PTR(ret);
 }
 
-void arpt_unregister_table(struct arpt_table *table)
+void arpt_unregister_table(struct xt_table *table)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
+       struct module *table_owner = table->me;
 
        private = xt_unregister_table(table);
 
@@ -1770,11 +1778,13 @@ void arpt_unregister_table(struct arpt_table *table)
        loc_cpu_entry = private->entries[raw_smp_processor_id()];
        ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
                           cleanup_entry, NULL);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
        xt_free_table_info(private);
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct arpt_target arpt_standard_target __read_mostly = {
+static struct xt_target arpt_standard_target __read_mostly = {
        .name           = ARPT_STANDARD_TARGET,
        .targetsize     = sizeof(int),
        .family         = NF_ARP,
@@ -1785,7 +1795,7 @@ static struct arpt_target arpt_standard_target __read_mostly = {
 #endif
 };
 
-static struct arpt_target arpt_error_target __read_mostly = {
+static struct xt_target arpt_error_target __read_mostly = {
        .name           = ARPT_ERROR_TARGET,
        .target         = arpt_error,
        .targetsize     = ARPT_FUNCTION_MAXNAMELEN,
@@ -1809,11 +1819,26 @@ static struct nf_sockopt_ops arpt_sockopts = {
        .owner          = THIS_MODULE,
 };
 
+static int __net_init arp_tables_net_init(struct net *net)
+{
+       return xt_proto_init(net, NF_ARP);
+}
+
+static void __net_exit arp_tables_net_exit(struct net *net)
+{
+       xt_proto_fini(net, NF_ARP);
+}
+
+static struct pernet_operations arp_tables_net_ops = {
+       .init = arp_tables_net_init,
+       .exit = arp_tables_net_exit,
+};
+
 static int __init arp_tables_init(void)
 {
        int ret;
 
-       ret = xt_proto_init(NF_ARP);
+       ret = register_pernet_subsys(&arp_tables_net_ops);
        if (ret < 0)
                goto err1;
 
@@ -1838,7 +1863,7 @@ err4:
 err3:
        xt_unregister_target(&arpt_standard_target);
 err2:
-       xt_proto_fini(NF_ARP);
+       unregister_pernet_subsys(&arp_tables_net_ops);
 err1:
        return ret;
 }
@@ -1848,7 +1873,7 @@ static void __exit arp_tables_fini(void)
        nf_unregister_sockopt(&arpt_sockopts);
        xt_unregister_target(&arpt_error_target);
        xt_unregister_target(&arpt_standard_target);
-       xt_proto_fini(NF_ARP);
+       unregister_pernet_subsys(&arp_tables_net_ops);
 }
 
 EXPORT_SYMBOL(arpt_register_table);