[NETFILTER]: nf_log: use rcu_assign_pointer for RCU protected pointer
[powerpc.git] / net / netfilter / nf_conntrack_core.c
index 355b330..59bcab1 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);
+EXPORT_SYMBOL_GPL(nf_conntrack_destroyed);
 
-void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL;
 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;
@@ -95,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;
@@ -134,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);
@@ -208,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;
 
        /*
@@ -242,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,
@@ -264,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,
@@ -282,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)
@@ -298,6 +315,7 @@ static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
        struct nf_conn *ct = (struct nf_conn *)nfct;
+       struct nf_conn_help *help = nfct_help(ct);
        struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
 
@@ -308,6 +326,9 @@ destroy_conntrack(struct nf_conntrack *nfct)
        nf_conntrack_event(IPCT_DESTROY, ct);
        set_bit(IPS_DYING_BIT, &ct->status);
 
+       if (help && help->helper && help->helper->destroy)
+               help->helper->destroy(ct);
+
        /* 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 */
@@ -376,6 +397,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 *
@@ -392,6 +414,7 @@ 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,
@@ -415,6 +438,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
@@ -492,6 +516,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). */
@@ -507,6 +532,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. */
@@ -543,10 +569,10 @@ static int early_drop(struct list_head *chain)
 static struct nf_conn *
 __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
                     const struct nf_conntrack_tuple *repl,
-                    const struct nf_conntrack_l3proto *l3proto)
+                    const struct nf_conntrack_l3proto *l3proto,
+                    u_int32_t features)
 {
        struct nf_conn *conntrack = NULL;
-       u_int32_t features = 0;
        struct nf_conntrack_helper *helper;
 
        if (unlikely(!nf_conntrack_hash_rnd_initted)) {
@@ -572,12 +598,13 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
        }
 
        /*  find features needed by this conntrack. */
-       features = l3proto->get_features(orig);
+       features |= l3proto->get_features(orig);
 
        /* FIXME: protect helper list per RCU */
        read_lock_bh(&nf_conntrack_lock);
        helper = __nf_ct_helper_find(repl);
-       if (helper)
+       /* NAT might want to assign a helper later */
+       if (helper || features & NF_CT_F_NAT)
                features |= NF_CT_F_HELP;
        read_unlock_bh(&nf_conntrack_lock);
 
@@ -622,8 +649,9 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
        struct nf_conntrack_l3proto *l3proto;
 
        l3proto = __nf_ct_l3proto_find(orig->src.l3num);
-       return __nf_conntrack_alloc(orig, repl, l3proto);
+       return __nf_conntrack_alloc(orig, repl, l3proto, 0);
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
 
 void nf_conntrack_free(struct nf_conn *conntrack)
 {
@@ -634,6 +662,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. */
@@ -647,13 +676,20 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
        struct nf_conn *conntrack;
        struct nf_conntrack_tuple repl_tuple;
        struct nf_conntrack_expect *exp;
+       u_int32_t features = 0;
 
        if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
                DEBUGP("Can't invert tuple.\n");
                return NULL;
        }
 
-       conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto);
+       read_lock_bh(&nf_conntrack_lock);
+       exp = __nf_conntrack_expect_find(tuple);
+       if (exp && exp->helper)
+               features = NF_CT_F_HELP;
+       read_unlock_bh(&nf_conntrack_lock);
+
+       conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto, features);
        if (conntrack == NULL || IS_ERR(conntrack)) {
                DEBUGP("Can't allocate conntrack.\n");
                return (struct nf_conntrack_tuple_hash *)conntrack;
@@ -674,6 +710,8 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
                /* Welcome, Mr. Bond.  We've been expecting you... */
                __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
                conntrack->master = exp->master;
+               if (exp->helper)
+                       nfct_help(conntrack)->helper = exp->helper;
 #ifdef CONFIG_NF_CONNTRACK_MARK
                conntrack->mark = exp->master->mark;
 #endif
@@ -829,6 +867,7 @@ 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)
@@ -838,6 +877,28 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
                                  __nf_ct_l4proto_find(orig->src.l3num,
                                                     orig->dst.protonum));
 }
+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 */
+void nf_conntrack_alter_reply(struct nf_conn *ct,
+                             const struct nf_conntrack_tuple *newreply)
+{
+       struct nf_conn_help *help = nfct_help(ct);
+
+       write_lock_bh(&nf_conntrack_lock);
+       /* Should be unconfirmed, so not in hash table yet */
+       NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
+
+       DEBUGP("Altering reply tuple of %p to ", ct);
+       NF_CT_DUMP_TUPLE(newreply);
+
+       ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
+       if (!ct->master && help && help->expecting == 0)
+               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,
@@ -864,9 +925,14 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
                ct->timeout.expires = extra_jiffies;
                event = IPCT_REFRESH;
        } else {
-               /* Need del_timer for race avoidance (may already be dying). */
-               if (del_timer(&ct->timeout)) {
-                       ct->timeout.expires = jiffies + extra_jiffies;
+               unsigned long newtime = jiffies + extra_jiffies;
+
+               /* Only update the timeout if the new timeout is at least
+                  HZ jiffies from the old timeout. Need del_timer for race
+                  avoidance (may already be dying). */
+               if (newtime - ct->timeout.expires >= HZ
+                   && del_timer(&ct->timeout)) {
+                       ct->timeout.expires = newtime;
                        add_timer(&ct->timeout);
                        event = IPCT_REFRESH;
                }
@@ -890,6 +956,7 @@ 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)
@@ -914,6 +981,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),
@@ -929,13 +997,12 @@ int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[],
        if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
                return -EINVAL;
 
-       t->src.u.tcp.port =
-               *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
-       t->dst.u.tcp.port =
-               *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
+       t->src.u.tcp.port = *(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
+       t->dst.u.tcp.port = *(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nf_ct_port_nfattr_to_tuple);
 #endif
 
 /* Used by ipt_REJECT and ip6t_REJECT. */
@@ -956,6 +1023,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,
@@ -1009,6 +1077,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)
 {
@@ -1024,10 +1093,11 @@ static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size)
                           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. */
@@ -1035,7 +1105,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
@@ -1065,6 +1135,8 @@ void nf_conntrack_cleanup(void)
        free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
                            nf_conntrack_htable_size);
 
+       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_generic);
+
        /* free l3proto protocol tables */
        for (i = 0; i < PF_MAX; i++)
                if (nf_ct_protos[i]) {
@@ -1190,6 +1262,10 @@ int __init nf_conntrack_init(void)
                goto err_free_conntrack_slab;
        }
 
+       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_generic);
+       if (ret < 0)
+               goto out_free_expect_slab;
+
        /* Don't NEED lock here, but good form anyway. */
        write_lock_bh(&nf_conntrack_lock);
         for (i = 0; i < AF_MAX; i++)
@@ -1197,7 +1273,7 @@ int __init nf_conntrack_init(void)
         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 */
@@ -1207,6 +1283,8 @@ int __init nf_conntrack_init(void)
 
        return ret;
 
+out_free_expect_slab:
+       kmem_cache_destroy(nf_conntrack_expect_cachep);
 err_free_conntrack_slab:
        nf_conntrack_unregister_cache(NF_CT_F_BASIC);
 err_free_hash: