[NETFILTER]: {ip,arp,ip6}_tables: fix sparse warnings in compat code
[safe/jmp/linux-2.6] / net / ipv6 / netfilter / ip6_tables.c
index 4ed16d2..b91738a 100644 (file)
@@ -90,6 +90,7 @@ ip6t_ext_hdr(u8 nexthdr)
 }
 
 /* Returns whether matches rule or not. */
+/* Performance critical - called for every packet */
 static inline bool
 ip6_packet_match(const struct sk_buff *skb,
                 const char *indev,
@@ -182,7 +183,7 @@ ip6_packet_match(const struct sk_buff *skb,
 }
 
 /* should be ip6 safe */
-static inline bool
+static bool
 ip6_checkentry(const struct ip6t_ip6 *ipv6)
 {
        if (ipv6->flags & ~IP6T_F_MASK) {
@@ -212,8 +213,9 @@ ip6t_error(struct sk_buff *skb,
        return NF_DROP;
 }
 
-static inline
-bool do_match(struct ip6t_entry_match *m,
+/* Performance critical - called for every packet */
+static inline bool
+do_match(struct ip6t_entry_match *m,
              const struct sk_buff *skb,
              const struct net_device *in,
              const struct net_device *out,
@@ -236,6 +238,7 @@ get_entry(void *base, unsigned int offset)
 }
 
 /* All zeroes == unconditional rule. */
+/* Mildly perf critical (only if packet tracing is on) */
 static inline int
 unconditional(const struct ip6t_ip6 *ipv6)
 {
@@ -251,7 +254,7 @@ unconditional(const struct ip6t_ip6 *ipv6)
 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
     defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
 /* This cries for unification! */
-static const char *hooknames[] = {
+static const char *const hooknames[] = {
        [NF_INET_PRE_ROUTING]           = "PREROUTING",
        [NF_INET_LOCAL_IN]              = "INPUT",
        [NF_INET_FORWARD]               = "FORWARD",
@@ -265,7 +268,7 @@ enum nf_ip_trace_comments {
        NF_IP6_TRACE_COMMENT_POLICY,
 };
 
-static const char *comments[] = {
+static const char *const comments[] = {
        [NF_IP6_TRACE_COMMENT_RULE]     = "rule",
        [NF_IP6_TRACE_COMMENT_RETURN]   = "return",
        [NF_IP6_TRACE_COMMENT_POLICY]   = "policy",
@@ -281,6 +284,7 @@ static struct nf_loginfo trace_loginfo = {
        },
 };
 
+/* Mildly perf critical (only if packet tracing is on) */
 static inline int
 get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
                      char *hookname, char **chainname,
@@ -316,7 +320,7 @@ static void trace_packet(struct sk_buff *skb,
                         unsigned int hook,
                         const struct net_device *in,
                         const struct net_device *out,
-                        char *tablename,
+                        const char *tablename,
                         struct xt_table_info *private,
                         struct ip6t_entry *e)
 {
@@ -595,7 +599,7 @@ mark_source_chains(struct xt_table_info *newinfo,
        return 1;
 }
 
-static inline int
+static int
 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
 {
        if (i && (*i)-- == 0)
@@ -607,7 +611,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
        return 0;
 }
 
-static inline int
+static int
 check_entry(struct ip6t_entry *e, const char *name)
 {
        struct ip6t_entry_target *t;
@@ -628,7 +632,7 @@ check_entry(struct ip6t_entry *e, const char *name)
        return 0;
 }
 
-static inline int check_match(struct ip6t_entry_match *m, const char *name,
+static int check_match(struct ip6t_entry_match *m, const char *name,
                              const struct ip6t_ip6 *ipv6,
                              unsigned int hookmask, unsigned int *i)
 {
@@ -651,7 +655,7 @@ static inline int check_match(struct ip6t_entry_match *m, const char *name,
        return ret;
 }
 
-static inline int
+static int
 find_check_match(struct ip6t_entry_match *m,
                 const char *name,
                 const struct ip6t_ip6 *ipv6,
@@ -680,7 +684,7 @@ err:
        return ret;
 }
 
-static inline int check_target(struct ip6t_entry *e, const char *name)
+static int check_target(struct ip6t_entry *e, const char *name)
 {
        struct ip6t_entry_target *t;
        struct xt_target *target;
@@ -701,7 +705,7 @@ static inline int check_target(struct ip6t_entry *e, const char *name)
        return ret;
 }
 
-static inline int
+static int
 find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
                 unsigned int *i)
 {
@@ -745,7 +749,7 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
        return ret;
 }
 
-static inline int
+static int
 check_entry_size_and_hooks(struct ip6t_entry *e,
                           struct xt_table_info *newinfo,
                           unsigned char *base,
@@ -788,7 +792,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
        return 0;
 }
 
-static inline int
+static int
 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
 {
        struct ip6t_entry_target *t;
@@ -944,7 +948,7 @@ get_counters(const struct xt_table_info *t,
        }
 }
 
-static inline struct xt_counters *alloc_counters(struct xt_table *table)
+static struct xt_counters *alloc_counters(struct xt_table *table)
 {
        unsigned int countersize;
        struct xt_counters *counters;
@@ -1114,7 +1118,7 @@ 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[IP6T_TABLE_MAXNAMELEN];
        struct xt_table *t;
@@ -1134,7 +1138,7 @@ static int get_info(void __user *user, int *len, int compat)
        if (compat)
                xt_compat_lock(AF_INET6);
 #endif
-       t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
+       t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
                                    "ip6table_%s", name);
        if (t && !IS_ERR(t)) {
                struct ip6t_getinfo info;
@@ -1174,7 +1178,7 @@ static int get_info(void __user *user, int *len, int compat)
 }
 
 static int
-get_entries(struct ip6t_get_entries __user *uptr, int *len)
+get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
 {
        int ret;
        struct ip6t_get_entries get;
@@ -1192,7 +1196,7 @@ get_entries(struct ip6t_get_entries __user *uptr, int *len)
                return -EINVAL;
        }
 
-       t = xt_find_table_lock(AF_INET6, get.name);
+       t = xt_find_table_lock(net, AF_INET6, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n", private->number);
@@ -1213,7 +1217,7 @@ get_entries(struct ip6t_get_entries __user *uptr, int *len)
 }
 
 static int
-__do_replace(const char *name, unsigned int valid_hooks,
+__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)
 {
@@ -1231,7 +1235,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
                goto out;
        }
 
-       t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
+       t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
                                    "ip6table_%s", name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1284,7 +1288,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
 }
 
 static int
-do_replace(void __user *user, unsigned int len)
+do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct ip6t_replace tmp;
@@ -1318,7 +1322,7 @@ do_replace(void __user *user, unsigned int len)
 
        duprintf("ip_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;
@@ -1354,7 +1358,8 @@ add_counter_to_entry(struct ip6t_entry *e,
 }
 
 static int
-do_add_counters(void __user *user, unsigned int len, int compat)
+do_add_counters(struct net *net, void __user *user, unsigned int len,
+               int compat)
 {
        unsigned int i;
        struct xt_counters_info tmp;
@@ -1406,7 +1411,7 @@ do_add_counters(void __user *user, unsigned int len, int compat)
                goto free;
        }
 
-       t = xt_find_table_lock(AF_INET6, name);
+       t = xt_find_table_lock(net, AF_INET6, name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
@@ -1452,7 +1457,7 @@ struct compat_ip6t_replace {
 
 static int
 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
-                         compat_uint_t *size, struct xt_counters *counters,
+                         unsigned int *size, struct xt_counters *counters,
                          unsigned int *i)
 {
        struct ip6t_entry_target *t;
@@ -1494,12 +1499,12 @@ out:
        return ret;
 }
 
-static inline int
+static int
 compat_find_calc_match(struct ip6t_entry_match *m,
                       const char *name,
                       const struct ip6t_ip6 *ipv6,
                       unsigned int hookmask,
-                      int *size, int *i)
+                      int *size, unsigned int *i)
 {
        struct xt_match *match;
 
@@ -1518,7 +1523,7 @@ compat_find_calc_match(struct ip6t_entry_match *m,
        return 0;
 }
 
-static inline int
+static int
 compat_release_match(struct ip6t_entry_match *m, unsigned int *i)
 {
        if (i && (*i)-- == 0)
@@ -1528,7 +1533,7 @@ compat_release_match(struct ip6t_entry_match *m, unsigned int *i)
        return 0;
 }
 
-static inline int
+static int
 compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i)
 {
        struct ip6t_entry_target *t;
@@ -1543,7 +1548,7 @@ compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i)
        return 0;
 }
 
-static inline int
+static int
 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
                                  struct xt_table_info *newinfo,
                                  unsigned int *size,
@@ -1557,7 +1562,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
        struct ip6t_entry_target *t;
        struct xt_target *target;
        unsigned int entry_offset;
-       int ret, off, h, j;
+       unsigned int j;
+       int ret, off, h;
 
        duprintf("check_compat_entry_size_and_hooks %p\n", e);
        if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0
@@ -1666,10 +1672,11 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
        return ret;
 }
 
-static inline int compat_check_entry(struct ip6t_entry *e, const char *name,
+static int compat_check_entry(struct ip6t_entry *e, const char *name,
                                     unsigned int *i)
 {
-       int j, ret;
+       unsigned int j;
+       int ret;
 
        j = 0;
        ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6,
@@ -1811,7 +1818,7 @@ out_unlock:
 }
 
 static int
-compat_do_replace(void __user *user, unsigned int len)
+compat_do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct compat_ip6t_replace tmp;
@@ -1848,7 +1855,7 @@ 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;
@@ -1872,11 +1879,11 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
 
        switch (cmd) {
        case IP6T_SO_SET_REPLACE:
-               ret = compat_do_replace(user, len);
+               ret = compat_do_replace(sk->sk_net, user, len);
                break;
 
        case IP6T_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 1);
+               ret = do_add_counters(sk->sk_net, user, len, 1);
                break;
 
        default:
@@ -1925,7 +1932,8 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
 }
 
 static int
-compat_get_entries(struct compat_ip6t_get_entries __user *uptr, int *len)
+compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
+                  int *len)
 {
        int ret;
        struct compat_ip6t_get_entries get;
@@ -1946,7 +1954,7 @@ compat_get_entries(struct compat_ip6t_get_entries __user *uptr, int *len)
        }
 
        xt_compat_lock(AF_INET6);
-       t = xt_find_table_lock(AF_INET6, get.name);
+       t = xt_find_table_lock(net, AF_INET6, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                struct xt_table_info info;
@@ -1982,10 +1990,10 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
        switch (cmd) {
        case IP6T_SO_GET_INFO:
-               ret = get_info(user, len, 1);
+               ret = get_info(sk->sk_net, user, len, 1);
                break;
        case IP6T_SO_GET_ENTRIES:
-               ret = compat_get_entries(user, len);
+               ret = compat_get_entries(sk->sk_net, user, len);
                break;
        default:
                ret = do_ip6t_get_ctl(sk, cmd, user, len);
@@ -2004,11 +2012,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 
        switch (cmd) {
        case IP6T_SO_SET_REPLACE:
-               ret = do_replace(user, len);
+               ret = do_replace(sk->sk_net, user, len);
                break;
 
        case IP6T_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 0);
+               ret = do_add_counters(sk->sk_net, user, len, 0);
                break;
 
        default:
@@ -2029,11 +2037,11 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
        switch (cmd) {
        case IP6T_SO_GET_INFO:
-               ret = get_info(user, len, 0);
+               ret = get_info(sk->sk_net, user, len, 0);
                break;
 
        case IP6T_SO_GET_ENTRIES:
-               ret = get_entries(user, len);
+               ret = get_entries(sk->sk_net, user, len);
                break;
 
        case IP6T_SO_GET_REVISION_MATCH:
@@ -2070,17 +2078,21 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl)
+struct xt_table *ip6t_register_table(struct net *net, struct xt_table *table,
+                                    const struct ip6t_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)
-               return -ENOMEM;
+       if (!newinfo) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* choose the copy on our node/cpu, but dont care about preemption */
        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
@@ -2091,30 +2103,35 @@ int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl)
                              repl->num_entries,
                              repl->hook_entry,
                              repl->underflow);
-       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 ip6t_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);
 
        /* Decrease module usage counts and free resources */
        loc_cpu_entry = private->entries[raw_smp_processor_id()];
        IP6T_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);
 }