]> err.no Git - linux-2.6/blobdiff - net/netfilter/nf_conntrack_core.c
Pull sbs into release branch
[linux-2.6] / net / netfilter / nf_conntrack_core.c
index ed756c928bc4b669ae080e49304f8f03160c31fe..b3a70eb6d42ae8728a5d8803ea230e9d27ecbb10 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/socket.h>
+#include <linux/mm.h>
 
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_l3proto.h>
 #endif
 
 DEFINE_RWLOCK(nf_conntrack_lock);
+EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
 /* nf_conntrack_standalone needs this */
 atomic_t nf_conntrack_count = ATOMIC_INIT(0);
 EXPORT_SYMBOL_GPL(nf_conntrack_count);
 
-void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL;
+void (*nf_conntrack_destroyed)(struct nf_conn *conntrack);
+EXPORT_SYMBOL_GPL(nf_conntrack_destroyed);
+
 unsigned int nf_conntrack_htable_size __read_mostly;
+EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
+
 int nf_conntrack_max __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_max);
+
 struct list_head *nf_conntrack_hash __read_mostly;
+EXPORT_SYMBOL_GPL(nf_conntrack_hash);
+
 struct nf_conn nf_conntrack_untracked __read_mostly;
+EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
+
 unsigned int nf_ct_log_invalid __read_mostly;
 LIST_HEAD(unconfirmed);
 static int nf_conntrack_vmalloc __read_mostly;
@@ -97,7 +108,7 @@ static struct {
        size_t size;
 
        /* slab cache pointer */
-       kmem_cache_t *cachep;
+       struct kmem_cache *cachep;
 
        /* allocated slab cache + modules which uses this slab cache */
        int use;
@@ -136,7 +147,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
 {
        int ret = 0;
        char *cache_name;
-       kmem_cache_t *cachep;
+       struct kmem_cache *cachep;
 
        DEBUGP("nf_conntrack_register_cache: features=0x%x, name=%s, size=%d\n",
               features, name, size);
@@ -210,11 +221,12 @@ out_up_mutex:
        mutex_unlock(&nf_ct_cache_mutex);
        return ret;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_register_cache);
 
 /* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */
 void nf_conntrack_unregister_cache(u_int32_t features)
 {
-       kmem_cache_t *cachep;
+       struct kmem_cache *cachep;
        char *name;
 
        /*
@@ -244,6 +256,7 @@ void nf_conntrack_unregister_cache(u_int32_t features)
 
        mutex_unlock(&nf_ct_cache_mutex);
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_unregister_cache);
 
 int
 nf_ct_get_tuple(const struct sk_buff *skb,
@@ -266,6 +279,7 @@ nf_ct_get_tuple(const struct sk_buff *skb,
 
        return l4proto->pkt_to_tuple(skb, dataoff, tuple);
 }
+EXPORT_SYMBOL_GPL(nf_ct_get_tuple);
 
 int
 nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
@@ -284,6 +298,7 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
        inverse->dst.protonum = orig->dst.protonum;
        return l4proto->invert_tuple(inverse, orig);
 }
+EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
 
 static void
 clean_from_lists(struct nf_conn *ct)
@@ -303,6 +318,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
        struct nf_conn_help *help = nfct_help(ct);
        struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
+       typeof(nf_conntrack_destroyed) destroyed;
 
        DEBUGP("destroy_conntrack(%p)\n", ct);
        NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
@@ -317,16 +333,21 @@ destroy_conntrack(struct nf_conntrack *nfct)
        /* To make sure we don't get any weird locking issues here:
         * destroy_conntrack() MUST NOT be called with a write lock
         * to nf_conntrack_lock!!! -HW */
+       rcu_read_lock();
        l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
        if (l3proto && l3proto->destroy)
                l3proto->destroy(ct);
 
-       l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+       l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
+                                      ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
        if (l4proto && l4proto->destroy)
                l4proto->destroy(ct);
 
-       if (nf_conntrack_destroyed)
-               nf_conntrack_destroyed(ct);
+       destroyed = rcu_dereference(nf_conntrack_destroyed);
+       if (destroyed)
+               destroyed(ct);
+
+       rcu_read_unlock();
 
        write_lock_bh(&nf_conntrack_lock);
        /* Expectations will have been removed in clean_from_lists,
@@ -382,6 +403,7 @@ __nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(__nf_conntrack_find);
 
 /* Find a connection corresponding to a tuple. */
 struct nf_conntrack_tuple_hash *
@@ -398,10 +420,11 @@ nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
 
        return h;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
 
 static void __nf_conntrack_hash_insert(struct nf_conn *ct,
                                       unsigned int hash,
-                                      unsigned int repl_hash) 
+                                      unsigned int repl_hash)
 {
        ct->id = ++nf_conntrack_next_id;
        list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list,
@@ -421,6 +444,7 @@ void nf_conntrack_hash_insert(struct nf_conn *ct)
        __nf_conntrack_hash_insert(ct, hash, repl_hash);
        write_unlock_bh(&nf_conntrack_lock);
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_hash_insert);
 
 /* Confirm a connection given skb; places it in hash table */
 int
@@ -498,6 +522,7 @@ out:
        write_unlock_bh(&nf_conntrack_lock);
        return NF_DROP;
 }
+EXPORT_SYMBOL_GPL(__nf_conntrack_confirm);
 
 /* Returns true if a connection correspondings to the tuple (required
    for NAT). */
@@ -513,6 +538,7 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
 
        return h != NULL;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
 
 /* There's a small race here where we may free a just-assured
    connection.  Too bad: we're in trouble anyway. */
@@ -540,7 +566,7 @@ static int early_drop(struct list_head *chain)
        if (del_timer(&ct->timeout)) {
                death_by_timeout((unsigned long)ct);
                dropped = 1;
-               NF_CT_STAT_INC(early_drop);
+               NF_CT_STAT_INC_ATOMIC(early_drop);
        }
        nf_ct_put(ct);
        return dropped;
@@ -627,10 +653,16 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
                                   const struct nf_conntrack_tuple *repl)
 {
        struct nf_conntrack_l3proto *l3proto;
+       struct nf_conn *ct;
 
+       rcu_read_lock();
        l3proto = __nf_ct_l3proto_find(orig->src.l3num);
-       return __nf_conntrack_alloc(orig, repl, l3proto, 0);
+       ct = __nf_conntrack_alloc(orig, repl, l3proto, 0);
+       rcu_read_unlock();
+
+       return ct;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
 
 void nf_conntrack_free(struct nf_conn *conntrack)
 {
@@ -641,6 +673,7 @@ void nf_conntrack_free(struct nf_conn *conntrack)
        kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
        atomic_dec(&nf_conntrack_count);
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_free);
 
 /* Allocate a new conntrack: we return -ENOMEM if classification
    failed due to stress.  Otherwise it really is unclassifiable. */
@@ -791,11 +824,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
 
        /* Previously seen (loopback or untracked)?  Ignore. */
        if ((*pskb)->nfct) {
-               NF_CT_STAT_INC(ignore);
+               NF_CT_STAT_INC_ATOMIC(ignore);
                return NF_ACCEPT;
        }
 
+       /* rcu_read_lock()ed by nf_hook_slow */
        l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
+
        if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) {
                DEBUGP("not prepared to track yet or error occured\n");
                return -ret;
@@ -808,8 +843,8 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
         * core what to do with the packet. */
        if (l4proto->error != NULL &&
            (ret = l4proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) {
-               NF_CT_STAT_INC(error);
-               NF_CT_STAT_INC(invalid);
+               NF_CT_STAT_INC_ATOMIC(error);
+               NF_CT_STAT_INC_ATOMIC(invalid);
                return -ret;
        }
 
@@ -817,13 +852,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
                               &set_reply, &ctinfo);
        if (!ct) {
                /* Not valid part of a connection */
-               NF_CT_STAT_INC(invalid);
+               NF_CT_STAT_INC_ATOMIC(invalid);
                return NF_ACCEPT;
        }
 
        if (IS_ERR(ct)) {
                /* Too stressed to deal. */
-               NF_CT_STAT_INC(drop);
+               NF_CT_STAT_INC_ATOMIC(drop);
                return NF_DROP;
        }
 
@@ -836,7 +871,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
                DEBUGP("nf_conntrack_in: Can't track with proto module\n");
                nf_conntrack_put((*pskb)->nfct);
                (*pskb)->nfct = NULL;
-               NF_CT_STAT_INC(invalid);
+               NF_CT_STAT_INC_ATOMIC(invalid);
                return -ret;
        }
 
@@ -845,15 +880,22 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_in);
 
 int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
                         const struct nf_conntrack_tuple *orig)
 {
-       return nf_ct_invert_tuple(inverse, orig,
-                                 __nf_ct_l3proto_find(orig->src.l3num),
-                                 __nf_ct_l4proto_find(orig->src.l3num,
-                                                    orig->dst.protonum));
+       int ret;
+
+       rcu_read_lock();
+       ret = nf_ct_invert_tuple(inverse, orig,
+                                __nf_ct_l3proto_find(orig->src.l3num),
+                                __nf_ct_l4proto_find(orig->src.l3num,
+                                                     orig->dst.protonum));
+       rcu_read_unlock();
+       return ret;
 }
+EXPORT_SYMBOL_GPL(nf_ct_invert_tuplepr);
 
 /* Alter reply tuple (maybe alter helper).  This is for NAT, and is
    implicitly racy: see __nf_conntrack_confirm */
@@ -874,6 +916,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
                help->helper = __nf_ct_helper_find(newreply);
        write_unlock_bh(&nf_conntrack_lock);
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
 
 /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */
 void __nf_ct_refresh_acct(struct nf_conn *ct,
@@ -931,9 +974,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
        if (event)
                nf_conntrack_event_cache(event, skb);
 }
+EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
 
-#if defined(CONFIG_NF_CT_NETLINK) || \
-    defined(CONFIG_NF_CT_NETLINK_MODULE)
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
@@ -955,6 +998,7 @@ int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb,
 nfattr_failure:
        return -1;
 }
+EXPORT_SYMBOL_GPL(nf_ct_port_tuple_to_nfattr);
 
 static const size_t cta_min_proto[CTA_PROTO_MAX] = {
        [CTA_PROTO_SRC_PORT-1]  = sizeof(u_int16_t),
@@ -975,6 +1019,7 @@ int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[],
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nf_ct_port_nfattr_to_tuple);
 #endif
 
 /* Used by ipt_REJECT and ip6t_REJECT. */
@@ -995,6 +1040,7 @@ void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
        nskb->nfctinfo = ctinfo;
        nf_conntrack_get(nskb->nfct);
 }
+EXPORT_SYMBOL_GPL(__nf_conntrack_attach);
 
 static inline int
 do_iter(const struct nf_conntrack_tuple_hash *i,
@@ -1019,11 +1065,11 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
                        if (iter(ct, data))
                                goto found;
                }
-       }
+       }
        list_for_each_entry(h, &unconfirmed, list) {
                ct = nf_ct_tuplehash_to_ctrack(h);
                if (iter(ct, data))
-                       goto found;
+                       set_bit(IPS_DYING_BIT, &ct->status);
        }
        write_unlock_bh(&nf_conntrack_lock);
        return NULL;
@@ -1048,6 +1094,7 @@ nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data)
                nf_ct_put(ct);
        }
 }
+EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);
 
 static int kill_all(struct nf_conn *i, void *data)
 {
@@ -1059,14 +1106,15 @@ static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size)
        if (vmalloced)
                vfree(hash);
        else
-               free_pages((unsigned long)hash, 
+               free_pages((unsigned long)hash,
                           get_order(sizeof(struct list_head) * size));
 }
 
-void nf_conntrack_flush()
+void nf_conntrack_flush(void)
 {
        nf_ct_iterate_cleanup(kill_all, NULL);
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_flush);
 
 /* Mishearing the voices in his head, our hero wonders how he's
    supposed to kill the mall. */
@@ -1074,7 +1122,7 @@ void nf_conntrack_cleanup(void)
 {
        int i;
 
-       ip_ct_attach = NULL;
+       rcu_assign_pointer(ip_ct_attach, NULL);
 
        /* This makes sure all current packets have passed through
           netfilter framework.  Roll on, two-stage module
@@ -1119,18 +1167,18 @@ static struct list_head *alloc_hashtable(int size, int *vmalloced)
        struct list_head *hash;
        unsigned int i;
 
-       *vmalloced = 0; 
-       hash = (void*)__get_free_pages(GFP_KERNEL, 
+       *vmalloced = 0;
+       hash = (void*)__get_free_pages(GFP_KERNEL,
                                       get_order(sizeof(struct list_head)
                                                 * size));
-       if (!hash) { 
+       if (!hash) {
                *vmalloced = 1;
                printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
                hash = vmalloc(sizeof(struct list_head) * size);
        }
 
        if (hash)
-               for (i = 0; i < size; i++) 
+               for (i = 0; i < size; i++)
                        INIT_LIST_HEAD(&hash[i]);
 
        return hash;
@@ -1237,12 +1285,12 @@ int __init nf_conntrack_init(void)
 
        /* Don't NEED lock here, but good form anyway. */
        write_lock_bh(&nf_conntrack_lock);
-        for (i = 0; i < AF_MAX; i++)
+       for (i = 0; i < AF_MAX; i++)
                nf_ct_l3protos[i] = &nf_conntrack_l3proto_generic;
-        write_unlock_bh(&nf_conntrack_lock);
+       write_unlock_bh(&nf_conntrack_lock);
 
        /* For use by REJECT target */
-       ip_ct_attach = __nf_conntrack_attach;
+       rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach);
 
        /* Set up fake conntrack:
            - to never be deleted, not in any hashes */