|
@@ -233,97 +233,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
|
|
|
int inet6_hash_connect(struct inet_timewait_death_row *death_row,
|
|
|
struct sock *sk)
|
|
|
{
|
|
|
- struct inet_hashinfo *hinfo = death_row->hashinfo;
|
|
|
- const unsigned short snum = inet_sk(sk)->num;
|
|
|
- struct inet_bind_hashbucket *head;
|
|
|
- struct inet_bind_bucket *tb;
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (snum == 0) {
|
|
|
- int i, port, low, high, remaining;
|
|
|
- static u32 hint;
|
|
|
- const u32 offset = hint + inet6_sk_port_offset(sk);
|
|
|
- struct hlist_node *node;
|
|
|
- struct inet_timewait_sock *tw = NULL;
|
|
|
-
|
|
|
- inet_get_local_port_range(&low, &high);
|
|
|
- remaining = (high - low) + 1;
|
|
|
-
|
|
|
- local_bh_disable();
|
|
|
- for (i = 1; i <= remaining; i++) {
|
|
|
- port = low + (i + offset) % remaining;
|
|
|
- head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
|
|
|
- spin_lock(&head->lock);
|
|
|
-
|
|
|
- /* Does not bother with rcv_saddr checks,
|
|
|
- * because the established check is already
|
|
|
- * unique enough.
|
|
|
- */
|
|
|
- inet_bind_bucket_for_each(tb, node, &head->chain) {
|
|
|
- if (tb->port == port) {
|
|
|
- BUG_TRAP(!hlist_empty(&tb->owners));
|
|
|
- if (tb->fastreuse >= 0)
|
|
|
- goto next_port;
|
|
|
- if (!__inet6_check_established(death_row,
|
|
|
- sk, port,
|
|
|
- &tw))
|
|
|
- goto ok;
|
|
|
- goto next_port;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
|
|
|
- head, port);
|
|
|
- if (!tb) {
|
|
|
- spin_unlock(&head->lock);
|
|
|
- break;
|
|
|
- }
|
|
|
- tb->fastreuse = -1;
|
|
|
- goto ok;
|
|
|
-
|
|
|
- next_port:
|
|
|
- spin_unlock(&head->lock);
|
|
|
- }
|
|
|
- local_bh_enable();
|
|
|
-
|
|
|
- return -EADDRNOTAVAIL;
|
|
|
-
|
|
|
-ok:
|
|
|
- hint += i;
|
|
|
-
|
|
|
- /* Head lock still held and bh's disabled */
|
|
|
- inet_bind_hash(sk, tb, port);
|
|
|
- if (sk_unhashed(sk)) {
|
|
|
- inet_sk(sk)->sport = htons(port);
|
|
|
- __inet6_hash(hinfo, sk);
|
|
|
- }
|
|
|
- spin_unlock(&head->lock);
|
|
|
-
|
|
|
- if (tw) {
|
|
|
- inet_twsk_deschedule(tw, death_row);
|
|
|
- inet_twsk_put(tw);
|
|
|
- }
|
|
|
-
|
|
|
- ret = 0;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)];
|
|
|
- tb = inet_csk(sk)->icsk_bind_hash;
|
|
|
- spin_lock_bh(&head->lock);
|
|
|
-
|
|
|
- if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
|
|
|
- __inet6_hash(hinfo, sk);
|
|
|
- spin_unlock_bh(&head->lock);
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- spin_unlock(&head->lock);
|
|
|
- /* No definite answer... Walk to established hash table */
|
|
|
- ret = __inet6_check_established(death_row, sk, snum, NULL);
|
|
|
-out:
|
|
|
- local_bh_enable();
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ return __inet_hash_connect(death_row, sk,
|
|
|
+ __inet6_check_established, __inet6_hash);
|
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(inet6_hash_connect);
|