|
@@ -404,19 +404,49 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct,
|
|
|
&net->ct.hash[repl_hash]);
|
|
|
}
|
|
|
|
|
|
-void nf_conntrack_hash_insert(struct nf_conn *ct)
|
|
|
+int
|
|
|
+nf_conntrack_hash_check_insert(struct nf_conn *ct)
|
|
|
{
|
|
|
struct net *net = nf_ct_net(ct);
|
|
|
unsigned int hash, repl_hash;
|
|
|
+ struct nf_conntrack_tuple_hash *h;
|
|
|
+ struct hlist_nulls_node *n;
|
|
|
u16 zone;
|
|
|
|
|
|
zone = nf_ct_zone(ct);
|
|
|
- hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
|
|
|
- repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
|
|
+ hash = hash_conntrack(net, zone,
|
|
|
+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
|
|
|
+ repl_hash = hash_conntrack(net, zone,
|
|
|
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
|
|
+
|
|
|
+ spin_lock_bh(&nf_conntrack_lock);
|
|
|
|
|
|
+ /* See if there's one in the list already, including reverse */
|
|
|
+ hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode)
|
|
|
+ if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
|
|
|
+ &h->tuple) &&
|
|
|
+ zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
|
|
|
+ goto out;
|
|
|
+ hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
|
|
|
+ if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
|
|
|
+ &h->tuple) &&
|
|
|
+ zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ add_timer(&ct->timeout);
|
|
|
+ nf_conntrack_get(&ct->ct_general);
|
|
|
__nf_conntrack_hash_insert(ct, hash, repl_hash);
|
|
|
+ NF_CT_STAT_INC(net, insert);
|
|
|
+ spin_unlock_bh(&nf_conntrack_lock);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out:
|
|
|
+ NF_CT_STAT_INC(net, insert_failed);
|
|
|
+ spin_unlock_bh(&nf_conntrack_lock);
|
|
|
+ return -EEXIST;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(nf_conntrack_hash_insert);
|
|
|
+EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
|
|
|
|
|
|
/* Confirm a connection given skb; places it in hash table */
|
|
|
int
|