inet_timewait_sock.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. #include <linux/config.h>
  11. #include <net/inet_hashtables.h>
  12. #include <net/inet_timewait_sock.h>
  13. /* Must be called with locally disabled BHs. */
  14. void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
  15. {
  16. struct inet_bind_hashbucket *bhead;
  17. struct inet_bind_bucket *tb;
  18. /* Unlink from established hashes. */
  19. struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent];
  20. write_lock(&ehead->lock);
  21. if (hlist_unhashed(&tw->tw_node)) {
  22. write_unlock(&ehead->lock);
  23. return;
  24. }
  25. __hlist_del(&tw->tw_node);
  26. sk_node_init(&tw->tw_node);
  27. write_unlock(&ehead->lock);
  28. /* Disassociate with bind bucket. */
  29. bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)];
  30. spin_lock(&bhead->lock);
  31. tb = tw->tw_tb;
  32. __hlist_del(&tw->tw_bind_node);
  33. tw->tw_tb = NULL;
  34. inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
  35. spin_unlock(&bhead->lock);
  36. #ifdef SOCK_REFCNT_DEBUG
  37. if (atomic_read(&tw->tw_refcnt) != 1) {
  38. printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
  39. tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
  40. }
  41. #endif
  42. inet_twsk_put(tw);
  43. }
  44. /*
  45. * Enter the time wait state. This is called with locally disabled BH.
  46. * Essentially we whip up a timewait bucket, copy the relevant info into it
  47. * from the SK, and mess with hash chains and list linkage.
  48. */
  49. void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
  50. struct inet_hashinfo *hashinfo)
  51. {
  52. const struct inet_sock *inet = inet_sk(sk);
  53. const struct inet_connection_sock *icsk = inet_csk(sk);
  54. struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent];
  55. struct inet_bind_hashbucket *bhead;
  56. /* Step 1: Put TW into bind hash. Original socket stays there too.
  57. Note, that any socket with inet->num != 0 MUST be bound in
  58. binding cache, even if it is closed.
  59. */
  60. bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)];
  61. spin_lock(&bhead->lock);
  62. tw->tw_tb = icsk->icsk_bind_hash;
  63. BUG_TRAP(icsk->icsk_bind_hash);
  64. inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
  65. spin_unlock(&bhead->lock);
  66. write_lock(&ehead->lock);
  67. /* Step 2: Remove SK from established hash. */
  68. if (__sk_del_node_init(sk))
  69. sock_prot_dec_use(sk->sk_prot);
  70. /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
  71. inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
  72. atomic_inc(&tw->tw_refcnt);
  73. write_unlock(&ehead->lock);
  74. }
  75. struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state)
  76. {
  77. struct inet_timewait_sock *tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_slab,
  78. SLAB_ATOMIC);
  79. if (tw != NULL) {
  80. const struct inet_sock *inet = inet_sk(sk);
  81. /* Give us an identity. */
  82. tw->tw_daddr = inet->daddr;
  83. tw->tw_rcv_saddr = inet->rcv_saddr;
  84. tw->tw_bound_dev_if = sk->sk_bound_dev_if;
  85. tw->tw_num = inet->num;
  86. tw->tw_state = TCP_TIME_WAIT;
  87. tw->tw_substate = state;
  88. tw->tw_sport = inet->sport;
  89. tw->tw_dport = inet->dport;
  90. tw->tw_family = sk->sk_family;
  91. tw->tw_reuse = sk->sk_reuse;
  92. tw->tw_hashent = sk->sk_hashent;
  93. tw->tw_ipv6only = 0;
  94. tw->tw_prot = sk->sk_prot_creator;
  95. atomic_set(&tw->tw_refcnt, 1);
  96. inet_twsk_dead_node_init(tw);
  97. }
  98. return tw;
  99. }