]> Pileus Git - ~andy/linux/blobdiff - net/ipv4/inet_connection_sock.c
tcp: bind() fix when many ports are bound
[~andy/linux] / net / ipv4 / inet_connection_sock.c
index 8da6429269dddd922f9c3fb4eda2b86a7bffe0d2..14825eb09770acfa5115cc2989f1403c830f348d 100644 (file)
@@ -70,13 +70,17 @@ int inet_csk_bind_conflict(const struct sock *sk,
                    (!sk->sk_bound_dev_if ||
                     !sk2->sk_bound_dev_if ||
                     sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
+                       const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+
                        if (!reuse || !sk2->sk_reuse ||
                            sk2->sk_state == TCP_LISTEN) {
-                               const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
                                if (!sk2_rcv_saddr || !sk_rcv_saddr ||
                                    sk2_rcv_saddr == sk_rcv_saddr)
                                        break;
-                       }
+                       } else if (reuse && sk2->sk_reuse &&
+                                  sk2_rcv_saddr &&
+                                  sk2_rcv_saddr == sk_rcv_saddr)
+                               break;
                }
        }
        return node != NULL;
@@ -120,9 +124,11 @@ again:
                                                smallest_size = tb->num_owners;
                                                smallest_rover = rover;
                                                if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) {
-                                                       spin_unlock(&head->lock);
-                                                       snum = smallest_rover;
-                                                       goto have_snum;
+                                                       if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
+                                                               spin_unlock(&head->lock);
+                                                               snum = smallest_rover;
+                                                               goto have_snum;
+                                                       }
                                                }
                                        }
                                        goto next;