]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - net/ipv4/inet_timewait_sock.c
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.
6 * Generic TIME_WAIT sockets functions
8 * From code orinally in TCP
11 #include <linux/config.h>
13 #include <net/inet_hashtables.h>
14 #include <net/inet_timewait_sock.h>
16 /* Must be called with locally disabled BHs. */
17 void __inet_twsk_kill(struct inet_timewait_sock
*tw
, struct inet_hashinfo
*hashinfo
)
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
];
24 write_lock(&ehead
->lock
);
25 if (hlist_unhashed(&tw
->tw_node
)) {
26 write_unlock(&ehead
->lock
);
29 __hlist_del(&tw
->tw_node
);
30 sk_node_init(&tw
->tw_node
);
31 write_unlock(&ehead
->lock
);
33 /* Disassociate with bind bucket. */
34 bhead
= &hashinfo
->bhash
[inet_bhashfn(tw
->tw_num
, hashinfo
->bhash_size
)];
35 spin_lock(&bhead
->lock
);
37 __hlist_del(&tw
->tw_bind_node
);
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
));
51 * Enter the time wait state. This is called with locally disabled BH.
52 * Essentially we whip up a timewait bucket, copy the relevant info into it
53 * from the SK, and mess with hash chains and list linkage.
55 void __inet_twsk_hashdance(struct inet_timewait_sock
*tw
, struct sock
*sk
,
56 struct inet_hashinfo
*hashinfo
)
58 const struct inet_sock
*inet
= inet_sk(sk
);
59 const struct inet_connection_sock
*icsk
= inet_csk(sk
);
60 struct inet_ehash_bucket
*ehead
= &hashinfo
->ehash
[sk
->sk_hashent
];
61 struct inet_bind_hashbucket
*bhead
;
62 /* Step 1: Put TW into bind hash. Original socket stays there too.
63 Note, that any socket with inet->num != 0 MUST be bound in
64 binding cache, even if it is closed.
66 bhead
= &hashinfo
->bhash
[inet_bhashfn(inet
->num
, hashinfo
->bhash_size
)];
67 spin_lock(&bhead
->lock
);
68 tw
->tw_tb
= icsk
->icsk_bind_hash
;
69 BUG_TRAP(icsk
->icsk_bind_hash
);
70 inet_twsk_add_bind_node(tw
, &tw
->tw_tb
->owners
);
71 spin_unlock(&bhead
->lock
);
73 write_lock(&ehead
->lock
);
75 /* Step 2: Remove SK from established hash. */
76 if (__sk_del_node_init(sk
))
77 sock_prot_dec_use(sk
->sk_prot
);
79 /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
80 inet_twsk_add_node(tw
, &(ehead
+ hashinfo
->ehash_size
)->chain
);
81 atomic_inc(&tw
->tw_refcnt
);
83 write_unlock(&ehead
->lock
);
86 struct inet_timewait_sock
*inet_twsk_alloc(const struct sock
*sk
, const int state
)
88 struct inet_timewait_sock
*tw
= kmem_cache_alloc(sk
->sk_prot_creator
->twsk_slab
,
91 const struct inet_sock
*inet
= inet_sk(sk
);
93 /* Give us an identity. */
94 tw
->tw_daddr
= inet
->daddr
;
95 tw
->tw_rcv_saddr
= inet
->rcv_saddr
;
96 tw
->tw_bound_dev_if
= sk
->sk_bound_dev_if
;
97 tw
->tw_num
= inet
->num
;
98 tw
->tw_state
= TCP_TIME_WAIT
;
99 tw
->tw_substate
= state
;
100 tw
->tw_sport
= inet
->sport
;
101 tw
->tw_dport
= inet
->dport
;
102 tw
->tw_family
= sk
->sk_family
;
103 tw
->tw_reuse
= sk
->sk_reuse
;
104 tw
->tw_hashent
= sk
->sk_hashent
;
106 tw
->tw_prot
= sk
->sk_prot_creator
;
107 atomic_set(&tw
->tw_refcnt
, 1);
108 inet_twsk_dead_node_init(tw
);