X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=net%2Fnetfilter%2Fnf_conntrack_core.c;h=59bcab1d1084a0d8595e48c765c72f932fc87301;hb=a5ea6169f294bc33a762f7c1c240e3ac0f045f9e;hp=441a647b784779336121b4197cedf9a43a2ce3e9;hpb=605dcad6c85226e6d43387917b329d65b95cef39;p=powerpc.git diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 441a647b78..59bcab1d10 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -46,11 +46,7 @@ #include #include #include - -/* This rwlock protects the main hash table, protocol/helper/expected - registrations, conntrack timers*/ -#define ASSERT_READ_LOCK(x) -#define ASSERT_WRITE_LOCK(x) +#include #include #include @@ -68,15 +64,27 @@ #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; @@ -100,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; @@ -139,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); @@ -213,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; /* @@ -247,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, @@ -269,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, @@ -287,12 +298,12 @@ 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) { DEBUGP("clean_from_lists(%p)\n", ct); - ASSERT_WRITE_LOCK(&nf_conntrack_lock); list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); @@ -304,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; @@ -314,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 */ @@ -371,7 +386,6 @@ __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, struct nf_conntrack_tuple_hash *h; unsigned int hash = hash_conntrack(tuple); - ASSERT_READ_LOCK(&nf_conntrack_lock); list_for_each_entry(h, &nf_conntrack_hash[hash], list) { if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && nf_ct_tuple_equal(tuple, &h->tuple)) { @@ -383,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 * @@ -399,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, @@ -422,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 @@ -499,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). */ @@ -514,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. */ @@ -550,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)) { @@ -579,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); @@ -629,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) { @@ -641,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. */ @@ -654,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; @@ -681,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 @@ -836,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) @@ -845,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, @@ -871,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; } @@ -884,9 +943,10 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, ct->counters[CTINFO2DIR(ctinfo)].packets++; ct->counters[CTINFO2DIR(ctinfo)].bytes += skb->len - (unsigned int)(skb->nh.raw - skb->data); - if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000) - || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000)) - event |= IPCT_COUNTER_FILLING; + + if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000) + || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000)) + event |= IPCT_COUNTER_FILLING; } #endif @@ -896,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) @@ -920,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), @@ -935,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. */ @@ -962,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, @@ -1015,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) { @@ -1030,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. */ @@ -1041,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 @@ -1071,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]) { @@ -1196,14 +1262,18 @@ 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 < PF_MAX; i++) + for (i = 0; i < AF_MAX; i++) nf_ct_l3protos[i] = &nf_conntrack_l3proto_generic; 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 */ @@ -1213,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: