]> bbs.cooldavid.org Git - net-next-2.6.git/blame - net/ipv4/inet_timewait_sock.c
[TIMEWAIT]: Introduce inet_timewait_death_row
[net-next-2.6.git] / net / ipv4 / inet_timewait_sock.c
CommitLineData
e48c414e
ACM
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Generic TIME_WAIT sockets functions
7 *
8 * From code orinally in TCP
9 */
10
11#include <linux/config.h>
12
13#include <net/inet_hashtables.h>
14#include <net/inet_timewait_sock.h>
15
16/* Must be called with locally disabled BHs. */
17void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
18{
19 struct inet_bind_hashbucket *bhead;
20 struct inet_bind_bucket *tb;
21 /* Unlink from established hashes. */
22 struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent];
23
24 write_lock(&ehead->lock);
25 if (hlist_unhashed(&tw->tw_node)) {
26 write_unlock(&ehead->lock);
27 return;
28 }
29 __hlist_del(&tw->tw_node);
30 sk_node_init(&tw->tw_node);
31 write_unlock(&ehead->lock);
32
33 /* Disassociate with bind bucket. */
34 bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)];
35 spin_lock(&bhead->lock);
36 tb = tw->tw_tb;
37 __hlist_del(&tw->tw_bind_node);
38 tw->tw_tb = NULL;
39 inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
40 spin_unlock(&bhead->lock);
41#ifdef SOCK_REFCNT_DEBUG
42 if (atomic_read(&tw->tw_refcnt) != 1) {
43 printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
44 tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
45 }
46#endif
47 inet_twsk_put(tw);
48}
49
d8c97a94
ACM
50EXPORT_SYMBOL_GPL(__inet_twsk_kill);
51
e48c414e
ACM
52/*
53 * Enter the time wait state. This is called with locally disabled BH.
54 * Essentially we whip up a timewait bucket, copy the relevant info into it
55 * from the SK, and mess with hash chains and list linkage.
56 */
57void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
58 struct inet_hashinfo *hashinfo)
59{
60 const struct inet_sock *inet = inet_sk(sk);
463c84b9 61 const struct inet_connection_sock *icsk = inet_csk(sk);
e48c414e
ACM
62 struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent];
63 struct inet_bind_hashbucket *bhead;
64 /* Step 1: Put TW into bind hash. Original socket stays there too.
65 Note, that any socket with inet->num != 0 MUST be bound in
66 binding cache, even if it is closed.
67 */
68 bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)];
69 spin_lock(&bhead->lock);
463c84b9
ACM
70 tw->tw_tb = icsk->icsk_bind_hash;
71 BUG_TRAP(icsk->icsk_bind_hash);
e48c414e
ACM
72 inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
73 spin_unlock(&bhead->lock);
74
75 write_lock(&ehead->lock);
76
77 /* Step 2: Remove SK from established hash. */
78 if (__sk_del_node_init(sk))
79 sock_prot_dec_use(sk->sk_prot);
80
81 /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
82 inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
83 atomic_inc(&tw->tw_refcnt);
84
85 write_unlock(&ehead->lock);
86}
c676270b
ACM
87
88struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state)
89{
90 struct inet_timewait_sock *tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_slab,
91 SLAB_ATOMIC);
92 if (tw != NULL) {
93 const struct inet_sock *inet = inet_sk(sk);
94
95 /* Give us an identity. */
96 tw->tw_daddr = inet->daddr;
97 tw->tw_rcv_saddr = inet->rcv_saddr;
98 tw->tw_bound_dev_if = sk->sk_bound_dev_if;
99 tw->tw_num = inet->num;
100 tw->tw_state = TCP_TIME_WAIT;
101 tw->tw_substate = state;
102 tw->tw_sport = inet->sport;
103 tw->tw_dport = inet->dport;
104 tw->tw_family = sk->sk_family;
105 tw->tw_reuse = sk->sk_reuse;
106 tw->tw_hashent = sk->sk_hashent;
107 tw->tw_ipv6only = 0;
108 tw->tw_prot = sk->sk_prot_creator;
109 atomic_set(&tw->tw_refcnt, 1);
110 inet_twsk_dead_node_init(tw);
111 }
112
113 return tw;
114}