177d8bf9cSArnaldo Carvalho de Melo /* 277d8bf9cSArnaldo Carvalho de Melo * INET An implementation of the TCP/IP protocol suite for the LINUX 377d8bf9cSArnaldo Carvalho de Melo * operating system. INET is implemented using the BSD Socket 477d8bf9cSArnaldo Carvalho de Melo * interface as the means of communication with the user level. 577d8bf9cSArnaldo Carvalho de Melo * 677d8bf9cSArnaldo Carvalho de Melo * Generic INET transport hashtables 777d8bf9cSArnaldo Carvalho de Melo * 877d8bf9cSArnaldo Carvalho de Melo * Authors: Lotsa people, from code originally in tcp 977d8bf9cSArnaldo Carvalho de Melo * 1077d8bf9cSArnaldo Carvalho de Melo * This program is free software; you can redistribute it and/or 1177d8bf9cSArnaldo Carvalho de Melo * modify it under the terms of the GNU General Public License 1277d8bf9cSArnaldo Carvalho de Melo * as published by the Free Software Foundation; either version 1377d8bf9cSArnaldo Carvalho de Melo * 2 of the License, or (at your option) any later version. 1477d8bf9cSArnaldo Carvalho de Melo */ 1577d8bf9cSArnaldo Carvalho de Melo 1677d8bf9cSArnaldo Carvalho de Melo #include <linux/config.h> 172d8c4ce5SArnaldo Carvalho de Melo #include <linux/module.h> 18a7f5e7f1SArnaldo Carvalho de Melo #include <linux/random.h> 19f3f05f70SArnaldo Carvalho de Melo #include <linux/sched.h> 2077d8bf9cSArnaldo Carvalho de Melo #include <linux/slab.h> 21f3f05f70SArnaldo Carvalho de Melo #include <linux/wait.h> 2277d8bf9cSArnaldo Carvalho de Melo 23463c84b9SArnaldo Carvalho de Melo #include <net/inet_connection_sock.h> 2477d8bf9cSArnaldo Carvalho de Melo #include <net/inet_hashtables.h> 25a7f5e7f1SArnaldo Carvalho de Melo #include <net/ip.h> 2677d8bf9cSArnaldo Carvalho de Melo 2777d8bf9cSArnaldo Carvalho de Melo /* 2877d8bf9cSArnaldo Carvalho de Melo * Allocate and initialize a new local port bind bucket. 2977d8bf9cSArnaldo Carvalho de Melo * The bindhash mutex for snum's hash chain must be held here. 3077d8bf9cSArnaldo Carvalho de Melo */ 3177d8bf9cSArnaldo Carvalho de Melo struct inet_bind_bucket *inet_bind_bucket_create(kmem_cache_t *cachep, 3277d8bf9cSArnaldo Carvalho de Melo struct inet_bind_hashbucket *head, 3377d8bf9cSArnaldo Carvalho de Melo const unsigned short snum) 3477d8bf9cSArnaldo Carvalho de Melo { 3577d8bf9cSArnaldo Carvalho de Melo struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, SLAB_ATOMIC); 3677d8bf9cSArnaldo Carvalho de Melo 3777d8bf9cSArnaldo Carvalho de Melo if (tb != NULL) { 3877d8bf9cSArnaldo Carvalho de Melo tb->port = snum; 3977d8bf9cSArnaldo Carvalho de Melo tb->fastreuse = 0; 4077d8bf9cSArnaldo Carvalho de Melo INIT_HLIST_HEAD(&tb->owners); 4177d8bf9cSArnaldo Carvalho de Melo hlist_add_head(&tb->node, &head->chain); 4277d8bf9cSArnaldo Carvalho de Melo } 4377d8bf9cSArnaldo Carvalho de Melo return tb; 4477d8bf9cSArnaldo Carvalho de Melo } 4577d8bf9cSArnaldo Carvalho de Melo 4677d8bf9cSArnaldo Carvalho de Melo EXPORT_SYMBOL(inet_bind_bucket_create); 4777d8bf9cSArnaldo Carvalho de Melo 4877d8bf9cSArnaldo Carvalho de Melo /* 4977d8bf9cSArnaldo Carvalho de Melo * Caller must hold hashbucket lock for this tb with local BH disabled 5077d8bf9cSArnaldo Carvalho de Melo */ 5177d8bf9cSArnaldo Carvalho de Melo void inet_bind_bucket_destroy(kmem_cache_t *cachep, struct inet_bind_bucket *tb) 5277d8bf9cSArnaldo Carvalho de Melo { 5377d8bf9cSArnaldo Carvalho de Melo if (hlist_empty(&tb->owners)) { 5477d8bf9cSArnaldo Carvalho de Melo __hlist_del(&tb->node); 5577d8bf9cSArnaldo Carvalho de Melo kmem_cache_free(cachep, tb); 5677d8bf9cSArnaldo Carvalho de Melo } 5777d8bf9cSArnaldo Carvalho de Melo } 582d8c4ce5SArnaldo Carvalho de Melo 592d8c4ce5SArnaldo Carvalho de Melo void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, 602d8c4ce5SArnaldo Carvalho de Melo const unsigned short snum) 612d8c4ce5SArnaldo Carvalho de Melo { 62463c84b9SArnaldo Carvalho de Melo inet_sk(sk)->num = snum; 632d8c4ce5SArnaldo Carvalho de Melo sk_add_bind_node(sk, &tb->owners); 64463c84b9SArnaldo Carvalho de Melo inet_csk(sk)->icsk_bind_hash = tb; 652d8c4ce5SArnaldo Carvalho de Melo } 662d8c4ce5SArnaldo Carvalho de Melo 672d8c4ce5SArnaldo Carvalho de Melo EXPORT_SYMBOL(inet_bind_hash); 682d8c4ce5SArnaldo Carvalho de Melo 692d8c4ce5SArnaldo Carvalho de Melo /* 702d8c4ce5SArnaldo Carvalho de Melo * Get rid of any references to a local port held by the given sock. 712d8c4ce5SArnaldo Carvalho de Melo */ 722d8c4ce5SArnaldo Carvalho de Melo static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk) 732d8c4ce5SArnaldo Carvalho de Melo { 74463c84b9SArnaldo Carvalho de Melo const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size); 752d8c4ce5SArnaldo Carvalho de Melo struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; 762d8c4ce5SArnaldo Carvalho de Melo struct inet_bind_bucket *tb; 772d8c4ce5SArnaldo Carvalho de Melo 782d8c4ce5SArnaldo Carvalho de Melo spin_lock(&head->lock); 79463c84b9SArnaldo Carvalho de Melo tb = inet_csk(sk)->icsk_bind_hash; 802d8c4ce5SArnaldo Carvalho de Melo __sk_del_bind_node(sk); 81463c84b9SArnaldo Carvalho de Melo inet_csk(sk)->icsk_bind_hash = NULL; 82463c84b9SArnaldo Carvalho de Melo inet_sk(sk)->num = 0; 832d8c4ce5SArnaldo Carvalho de Melo inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); 842d8c4ce5SArnaldo Carvalho de Melo spin_unlock(&head->lock); 852d8c4ce5SArnaldo Carvalho de Melo } 862d8c4ce5SArnaldo Carvalho de Melo 872d8c4ce5SArnaldo Carvalho de Melo void inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk) 882d8c4ce5SArnaldo Carvalho de Melo { 892d8c4ce5SArnaldo Carvalho de Melo local_bh_disable(); 902d8c4ce5SArnaldo Carvalho de Melo __inet_put_port(hashinfo, sk); 912d8c4ce5SArnaldo Carvalho de Melo local_bh_enable(); 922d8c4ce5SArnaldo Carvalho de Melo } 932d8c4ce5SArnaldo Carvalho de Melo 942d8c4ce5SArnaldo Carvalho de Melo EXPORT_SYMBOL(inet_put_port); 95f3f05f70SArnaldo Carvalho de Melo 96f3f05f70SArnaldo Carvalho de Melo /* 97f3f05f70SArnaldo Carvalho de Melo * This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP. 98f3f05f70SArnaldo Carvalho de Melo * Look, when several writers sleep and reader wakes them up, all but one 99f3f05f70SArnaldo Carvalho de Melo * immediately hit write lock and grab all the cpus. Exclusive sleep solves 100f3f05f70SArnaldo Carvalho de Melo * this, _but_ remember, it adds useless work on UP machines (wake up each 101f3f05f70SArnaldo Carvalho de Melo * exclusive lock release). It should be ifdefed really. 102f3f05f70SArnaldo Carvalho de Melo */ 103f3f05f70SArnaldo Carvalho de Melo void inet_listen_wlock(struct inet_hashinfo *hashinfo) 104f3f05f70SArnaldo Carvalho de Melo { 105f3f05f70SArnaldo Carvalho de Melo write_lock(&hashinfo->lhash_lock); 106f3f05f70SArnaldo Carvalho de Melo 107f3f05f70SArnaldo Carvalho de Melo if (atomic_read(&hashinfo->lhash_users)) { 108f3f05f70SArnaldo Carvalho de Melo DEFINE_WAIT(wait); 109f3f05f70SArnaldo Carvalho de Melo 110f3f05f70SArnaldo Carvalho de Melo for (;;) { 111f3f05f70SArnaldo Carvalho de Melo prepare_to_wait_exclusive(&hashinfo->lhash_wait, 112f3f05f70SArnaldo Carvalho de Melo &wait, TASK_UNINTERRUPTIBLE); 113f3f05f70SArnaldo Carvalho de Melo if (!atomic_read(&hashinfo->lhash_users)) 114f3f05f70SArnaldo Carvalho de Melo break; 115f3f05f70SArnaldo Carvalho de Melo write_unlock_bh(&hashinfo->lhash_lock); 116f3f05f70SArnaldo Carvalho de Melo schedule(); 117f3f05f70SArnaldo Carvalho de Melo write_lock_bh(&hashinfo->lhash_lock); 118f3f05f70SArnaldo Carvalho de Melo } 119f3f05f70SArnaldo Carvalho de Melo 120f3f05f70SArnaldo Carvalho de Melo finish_wait(&hashinfo->lhash_wait, &wait); 121f3f05f70SArnaldo Carvalho de Melo } 122f3f05f70SArnaldo Carvalho de Melo } 123f3f05f70SArnaldo Carvalho de Melo 124f3f05f70SArnaldo Carvalho de Melo EXPORT_SYMBOL(inet_listen_wlock); 12533b62231SArnaldo Carvalho de Melo 12633b62231SArnaldo Carvalho de Melo /* 12733b62231SArnaldo Carvalho de Melo * Don't inline this cruft. Here are some nice properties to exploit here. The 12833b62231SArnaldo Carvalho de Melo * BSD API does not allow a listening sock to specify the remote port nor the 12933b62231SArnaldo Carvalho de Melo * remote address for the connection. So always assume those are both 13033b62231SArnaldo Carvalho de Melo * wildcarded during the search since they can never be otherwise. 13133b62231SArnaldo Carvalho de Melo */ 13233b62231SArnaldo Carvalho de Melo struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 daddr, 13333b62231SArnaldo Carvalho de Melo const unsigned short hnum, const int dif) 13433b62231SArnaldo Carvalho de Melo { 13533b62231SArnaldo Carvalho de Melo struct sock *result = NULL, *sk; 13633b62231SArnaldo Carvalho de Melo const struct hlist_node *node; 13733b62231SArnaldo Carvalho de Melo int hiscore = -1; 13833b62231SArnaldo Carvalho de Melo 13933b62231SArnaldo Carvalho de Melo sk_for_each(sk, node, head) { 14033b62231SArnaldo Carvalho de Melo const struct inet_sock *inet = inet_sk(sk); 14133b62231SArnaldo Carvalho de Melo 14233b62231SArnaldo Carvalho de Melo if (inet->num == hnum && !ipv6_only_sock(sk)) { 14333b62231SArnaldo Carvalho de Melo const __u32 rcv_saddr = inet->rcv_saddr; 14433b62231SArnaldo Carvalho de Melo int score = sk->sk_family == PF_INET ? 1 : 0; 14533b62231SArnaldo Carvalho de Melo 14633b62231SArnaldo Carvalho de Melo if (rcv_saddr) { 14733b62231SArnaldo Carvalho de Melo if (rcv_saddr != daddr) 14833b62231SArnaldo Carvalho de Melo continue; 14933b62231SArnaldo Carvalho de Melo score += 2; 15033b62231SArnaldo Carvalho de Melo } 15133b62231SArnaldo Carvalho de Melo if (sk->sk_bound_dev_if) { 15233b62231SArnaldo Carvalho de Melo if (sk->sk_bound_dev_if != dif) 15333b62231SArnaldo Carvalho de Melo continue; 15433b62231SArnaldo Carvalho de Melo score += 2; 15533b62231SArnaldo Carvalho de Melo } 15633b62231SArnaldo Carvalho de Melo if (score == 5) 15733b62231SArnaldo Carvalho de Melo return sk; 15833b62231SArnaldo Carvalho de Melo if (score > hiscore) { 15933b62231SArnaldo Carvalho de Melo hiscore = score; 16033b62231SArnaldo Carvalho de Melo result = sk; 16133b62231SArnaldo Carvalho de Melo } 16233b62231SArnaldo Carvalho de Melo } 16333b62231SArnaldo Carvalho de Melo } 16433b62231SArnaldo Carvalho de Melo return result; 16533b62231SArnaldo Carvalho de Melo } 166e48c414eSArnaldo Carvalho de Melo 167e48c414eSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(__inet_lookup_listener); 168a7f5e7f1SArnaldo Carvalho de Melo 169a7f5e7f1SArnaldo Carvalho de Melo /* called with local bh disabled */ 170a7f5e7f1SArnaldo Carvalho de Melo static int __inet_check_established(struct inet_timewait_death_row *death_row, 171a7f5e7f1SArnaldo Carvalho de Melo struct sock *sk, __u16 lport, 172a7f5e7f1SArnaldo Carvalho de Melo struct inet_timewait_sock **twp) 173a7f5e7f1SArnaldo Carvalho de Melo { 174a7f5e7f1SArnaldo Carvalho de Melo struct inet_hashinfo *hinfo = death_row->hashinfo; 175a7f5e7f1SArnaldo Carvalho de Melo struct inet_sock *inet = inet_sk(sk); 176a7f5e7f1SArnaldo Carvalho de Melo u32 daddr = inet->rcv_saddr; 177a7f5e7f1SArnaldo Carvalho de Melo u32 saddr = inet->daddr; 178a7f5e7f1SArnaldo Carvalho de Melo int dif = sk->sk_bound_dev_if; 179a7f5e7f1SArnaldo Carvalho de Melo INET_ADDR_COOKIE(acookie, saddr, daddr) 180a7f5e7f1SArnaldo Carvalho de Melo const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); 181a7f5e7f1SArnaldo Carvalho de Melo unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); 182a7f5e7f1SArnaldo Carvalho de Melo struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); 183a7f5e7f1SArnaldo Carvalho de Melo struct sock *sk2; 184a7f5e7f1SArnaldo Carvalho de Melo const struct hlist_node *node; 185a7f5e7f1SArnaldo Carvalho de Melo struct inet_timewait_sock *tw; 186a7f5e7f1SArnaldo Carvalho de Melo 187a7f5e7f1SArnaldo Carvalho de Melo prefetch(head->chain.first); 188a7f5e7f1SArnaldo Carvalho de Melo write_lock(&head->lock); 189a7f5e7f1SArnaldo Carvalho de Melo 190a7f5e7f1SArnaldo Carvalho de Melo /* Check TIME-WAIT sockets first. */ 191a7f5e7f1SArnaldo Carvalho de Melo sk_for_each(sk2, node, &(head + hinfo->ehash_size)->chain) { 192a7f5e7f1SArnaldo Carvalho de Melo tw = inet_twsk(sk2); 193a7f5e7f1SArnaldo Carvalho de Melo 194a7f5e7f1SArnaldo Carvalho de Melo if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) { 195a7f5e7f1SArnaldo Carvalho de Melo if (twsk_unique(sk, sk2, twp)) 196a7f5e7f1SArnaldo Carvalho de Melo goto unique; 197a7f5e7f1SArnaldo Carvalho de Melo else 198a7f5e7f1SArnaldo Carvalho de Melo goto not_unique; 199a7f5e7f1SArnaldo Carvalho de Melo } 200a7f5e7f1SArnaldo Carvalho de Melo } 201a7f5e7f1SArnaldo Carvalho de Melo tw = NULL; 202a7f5e7f1SArnaldo Carvalho de Melo 203a7f5e7f1SArnaldo Carvalho de Melo /* And established part... */ 204a7f5e7f1SArnaldo Carvalho de Melo sk_for_each(sk2, node, &head->chain) { 205a7f5e7f1SArnaldo Carvalho de Melo if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) 206a7f5e7f1SArnaldo Carvalho de Melo goto not_unique; 207a7f5e7f1SArnaldo Carvalho de Melo } 208a7f5e7f1SArnaldo Carvalho de Melo 209a7f5e7f1SArnaldo Carvalho de Melo unique: 210a7f5e7f1SArnaldo Carvalho de Melo /* Must record num and sport now. Otherwise we will see 211a7f5e7f1SArnaldo Carvalho de Melo * in hash table socket with a funny identity. */ 212a7f5e7f1SArnaldo Carvalho de Melo inet->num = lport; 213a7f5e7f1SArnaldo Carvalho de Melo inet->sport = htons(lport); 214a7f5e7f1SArnaldo Carvalho de Melo sk->sk_hash = hash; 215a7f5e7f1SArnaldo Carvalho de Melo BUG_TRAP(sk_unhashed(sk)); 216a7f5e7f1SArnaldo Carvalho de Melo __sk_add_node(sk, &head->chain); 217a7f5e7f1SArnaldo Carvalho de Melo sock_prot_inc_use(sk->sk_prot); 218a7f5e7f1SArnaldo Carvalho de Melo write_unlock(&head->lock); 219a7f5e7f1SArnaldo Carvalho de Melo 220a7f5e7f1SArnaldo Carvalho de Melo if (twp) { 221a7f5e7f1SArnaldo Carvalho de Melo *twp = tw; 222a7f5e7f1SArnaldo Carvalho de Melo NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); 223a7f5e7f1SArnaldo Carvalho de Melo } else if (tw) { 224a7f5e7f1SArnaldo Carvalho de Melo /* Silly. Should hash-dance instead... */ 225a7f5e7f1SArnaldo Carvalho de Melo inet_twsk_deschedule(tw, death_row); 226a7f5e7f1SArnaldo Carvalho de Melo NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); 227a7f5e7f1SArnaldo Carvalho de Melo 228a7f5e7f1SArnaldo Carvalho de Melo inet_twsk_put(tw); 229a7f5e7f1SArnaldo Carvalho de Melo } 230a7f5e7f1SArnaldo Carvalho de Melo 231a7f5e7f1SArnaldo Carvalho de Melo return 0; 232a7f5e7f1SArnaldo Carvalho de Melo 233a7f5e7f1SArnaldo Carvalho de Melo not_unique: 234a7f5e7f1SArnaldo Carvalho de Melo write_unlock(&head->lock); 235a7f5e7f1SArnaldo Carvalho de Melo return -EADDRNOTAVAIL; 236a7f5e7f1SArnaldo Carvalho de Melo } 237a7f5e7f1SArnaldo Carvalho de Melo 238a7f5e7f1SArnaldo Carvalho de Melo static inline u32 inet_sk_port_offset(const struct sock *sk) 239a7f5e7f1SArnaldo Carvalho de Melo { 240a7f5e7f1SArnaldo Carvalho de Melo const struct inet_sock *inet = inet_sk(sk); 241a7f5e7f1SArnaldo Carvalho de Melo return secure_ipv4_port_ephemeral(inet->rcv_saddr, inet->daddr, 242a7f5e7f1SArnaldo Carvalho de Melo inet->dport); 243a7f5e7f1SArnaldo Carvalho de Melo } 244a7f5e7f1SArnaldo Carvalho de Melo 245a7f5e7f1SArnaldo Carvalho de Melo /* 246a7f5e7f1SArnaldo Carvalho de Melo * Bind a port for a connect operation and hash it. 247a7f5e7f1SArnaldo Carvalho de Melo */ 248a7f5e7f1SArnaldo Carvalho de Melo int inet_hash_connect(struct inet_timewait_death_row *death_row, 249a7f5e7f1SArnaldo Carvalho de Melo struct sock *sk) 250a7f5e7f1SArnaldo Carvalho de Melo { 251a7f5e7f1SArnaldo Carvalho de Melo struct inet_hashinfo *hinfo = death_row->hashinfo; 252a7f5e7f1SArnaldo Carvalho de Melo const unsigned short snum = inet_sk(sk)->num; 253a7f5e7f1SArnaldo Carvalho de Melo struct inet_bind_hashbucket *head; 254a7f5e7f1SArnaldo Carvalho de Melo struct inet_bind_bucket *tb; 255a7f5e7f1SArnaldo Carvalho de Melo int ret; 256a7f5e7f1SArnaldo Carvalho de Melo 257a7f5e7f1SArnaldo Carvalho de Melo if (!snum) { 258a7f5e7f1SArnaldo Carvalho de Melo int low = sysctl_local_port_range[0]; 259a7f5e7f1SArnaldo Carvalho de Melo int high = sysctl_local_port_range[1]; 260a7f5e7f1SArnaldo Carvalho de Melo int range = high - low; 261a7f5e7f1SArnaldo Carvalho de Melo int i; 262a7f5e7f1SArnaldo Carvalho de Melo int port; 263a7f5e7f1SArnaldo Carvalho de Melo static u32 hint; 264a7f5e7f1SArnaldo Carvalho de Melo u32 offset = hint + inet_sk_port_offset(sk); 265a7f5e7f1SArnaldo Carvalho de Melo struct hlist_node *node; 266a7f5e7f1SArnaldo Carvalho de Melo struct inet_timewait_sock *tw = NULL; 267a7f5e7f1SArnaldo Carvalho de Melo 268a7f5e7f1SArnaldo Carvalho de Melo local_bh_disable(); 269a7f5e7f1SArnaldo Carvalho de Melo for (i = 1; i <= range; i++) { 270a7f5e7f1SArnaldo Carvalho de Melo port = low + (i + offset) % range; 271a7f5e7f1SArnaldo Carvalho de Melo head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; 272a7f5e7f1SArnaldo Carvalho de Melo spin_lock(&head->lock); 273a7f5e7f1SArnaldo Carvalho de Melo 274a7f5e7f1SArnaldo Carvalho de Melo /* Does not bother with rcv_saddr checks, 275a7f5e7f1SArnaldo Carvalho de Melo * because the established check is already 276a7f5e7f1SArnaldo Carvalho de Melo * unique enough. 277a7f5e7f1SArnaldo Carvalho de Melo */ 278a7f5e7f1SArnaldo Carvalho de Melo inet_bind_bucket_for_each(tb, node, &head->chain) { 279a7f5e7f1SArnaldo Carvalho de Melo if (tb->port == port) { 280a7f5e7f1SArnaldo Carvalho de Melo BUG_TRAP(!hlist_empty(&tb->owners)); 281a7f5e7f1SArnaldo Carvalho de Melo if (tb->fastreuse >= 0) 282a7f5e7f1SArnaldo Carvalho de Melo goto next_port; 283a7f5e7f1SArnaldo Carvalho de Melo if (!__inet_check_established(death_row, 284a7f5e7f1SArnaldo Carvalho de Melo sk, port, 285a7f5e7f1SArnaldo Carvalho de Melo &tw)) 286a7f5e7f1SArnaldo Carvalho de Melo goto ok; 287a7f5e7f1SArnaldo Carvalho de Melo goto next_port; 288a7f5e7f1SArnaldo Carvalho de Melo } 289a7f5e7f1SArnaldo Carvalho de Melo } 290a7f5e7f1SArnaldo Carvalho de Melo 291a7f5e7f1SArnaldo Carvalho de Melo tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, head, port); 292a7f5e7f1SArnaldo Carvalho de Melo if (!tb) { 293a7f5e7f1SArnaldo Carvalho de Melo spin_unlock(&head->lock); 294a7f5e7f1SArnaldo Carvalho de Melo break; 295a7f5e7f1SArnaldo Carvalho de Melo } 296a7f5e7f1SArnaldo Carvalho de Melo tb->fastreuse = -1; 297a7f5e7f1SArnaldo Carvalho de Melo goto ok; 298a7f5e7f1SArnaldo Carvalho de Melo 299a7f5e7f1SArnaldo Carvalho de Melo next_port: 300a7f5e7f1SArnaldo Carvalho de Melo spin_unlock(&head->lock); 301a7f5e7f1SArnaldo Carvalho de Melo } 302a7f5e7f1SArnaldo Carvalho de Melo local_bh_enable(); 303a7f5e7f1SArnaldo Carvalho de Melo 304a7f5e7f1SArnaldo Carvalho de Melo return -EADDRNOTAVAIL; 305a7f5e7f1SArnaldo Carvalho de Melo 306a7f5e7f1SArnaldo Carvalho de Melo ok: 307a7f5e7f1SArnaldo Carvalho de Melo hint += i; 308a7f5e7f1SArnaldo Carvalho de Melo 309a7f5e7f1SArnaldo Carvalho de Melo /* Head lock still held and bh's disabled */ 310a7f5e7f1SArnaldo Carvalho de Melo inet_bind_hash(sk, tb, port); 311a7f5e7f1SArnaldo Carvalho de Melo if (sk_unhashed(sk)) { 312a7f5e7f1SArnaldo Carvalho de Melo inet_sk(sk)->sport = htons(port); 313a7f5e7f1SArnaldo Carvalho de Melo __inet_hash(hinfo, sk, 0); 314a7f5e7f1SArnaldo Carvalho de Melo } 315a7f5e7f1SArnaldo Carvalho de Melo spin_unlock(&head->lock); 316a7f5e7f1SArnaldo Carvalho de Melo 317a7f5e7f1SArnaldo Carvalho de Melo if (tw) { 318*53b3531bSAlexey Dobriyan inet_twsk_deschedule(tw, death_row); 319a7f5e7f1SArnaldo Carvalho de Melo inet_twsk_put(tw); 320a7f5e7f1SArnaldo Carvalho de Melo } 321a7f5e7f1SArnaldo Carvalho de Melo 322a7f5e7f1SArnaldo Carvalho de Melo ret = 0; 323a7f5e7f1SArnaldo Carvalho de Melo goto out; 324a7f5e7f1SArnaldo Carvalho de Melo } 325a7f5e7f1SArnaldo Carvalho de Melo 326a7f5e7f1SArnaldo Carvalho de Melo head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)]; 327a7f5e7f1SArnaldo Carvalho de Melo tb = inet_csk(sk)->icsk_bind_hash; 328a7f5e7f1SArnaldo Carvalho de Melo spin_lock_bh(&head->lock); 329a7f5e7f1SArnaldo Carvalho de Melo if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { 330a7f5e7f1SArnaldo Carvalho de Melo __inet_hash(hinfo, sk, 0); 331a7f5e7f1SArnaldo Carvalho de Melo spin_unlock_bh(&head->lock); 332a7f5e7f1SArnaldo Carvalho de Melo return 0; 333a7f5e7f1SArnaldo Carvalho de Melo } else { 334a7f5e7f1SArnaldo Carvalho de Melo spin_unlock(&head->lock); 335a7f5e7f1SArnaldo Carvalho de Melo /* No definite answer... Walk to established hash table */ 336a7f5e7f1SArnaldo Carvalho de Melo ret = __inet_check_established(death_row, sk, snum, NULL); 337a7f5e7f1SArnaldo Carvalho de Melo out: 338a7f5e7f1SArnaldo Carvalho de Melo local_bh_enable(); 339a7f5e7f1SArnaldo Carvalho de Melo return ret; 340a7f5e7f1SArnaldo Carvalho de Melo } 341a7f5e7f1SArnaldo Carvalho de Melo } 342a7f5e7f1SArnaldo Carvalho de Melo 343a7f5e7f1SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(inet_hash_connect); 344