summaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-13 20:55:15 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-13 20:55:15 +0000
commit1471f525455788c20b130690e0f104df451aeb43 (patch)
tree3778beba56558beb9a9548ea5b467e9c44ea966f /net/ipv4
parente80d2c5456d30ebba5b0eb8a9d33e17d815d4d83 (diff)
Merge with Linux 2.3.51.
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp.c39
-rw-r--r--net/ipv4/tcp_ipv4.c21
2 files changed, 33 insertions, 27 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 9f7ad441e..7d3e49bed 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.163 2000/02/08 21:27:13 davem Exp $
+ * Version: $Id: tcp.c,v 1.164 2000/03/08 19:36:40 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -624,28 +624,29 @@ int tcp_listen_start(struct sock *sk)
tp->listen_opt = lopt;
write_unlock_bh(&tp->syn_wait_lock);
+ /* There is race window here: we announce ourselves listening,
+ * but this transition is still not validated by get_port().
+ * It is OK, because this socket enters to hash table only
+ * after validation is complete.
+ */
sk->state = TCP_LISTEN;
- if (sk->num == 0) {
- if (sk->prot->get_port(sk, 0) != 0) {
- sk->state = TCP_CLOSE;
- write_lock_bh(&tp->syn_wait_lock);
- tp->listen_opt = NULL;
- write_unlock_bh(&tp->syn_wait_lock);
- kfree(lopt);
- return -EAGAIN;
- }
+ if (sk->prot->get_port(sk, sk->num) == 0) {
sk->sport = htons(sk->num);
- } else {
- if (sk->prev)
- ((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0;
- }
- sk_dst_reset(sk);
- sk->prot->hash(sk);
- sk->socket->flags |= SO_ACCEPTCON;
- sk->write_space = tcp_listen_write_space;
+ sk->write_space = tcp_listen_write_space;
+ sk_dst_reset(sk);
+ sk->prot->hash(sk);
+ sk->socket->flags |= SO_ACCEPTCON;
- return 0;
+ return 0;
+ }
+
+ sk->state = TCP_CLOSE;
+ write_lock_bh(&tp->syn_wait_lock);
+ tp->listen_opt = NULL;
+ write_unlock_bh(&tp->syn_wait_lock);
+ kfree(lopt);
+ return -EADDRINUSE;
}
/*
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 25a71d5f0..204f25574 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.200 2000/02/11 22:27:26 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.201 2000/03/08 19:36:42 davem Exp $
*
* IPv4 specific functions
*
@@ -231,14 +231,15 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
break;
}
if (tb != NULL && tb->owners != NULL) {
- if (tb->fastreuse != 0 && sk->reuse != 0) {
+ if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
goto success;
} else {
struct sock *sk2 = tb->owners;
int sk_reuse = sk->reuse;
for( ; sk2 != NULL; sk2 = sk2->bind_next) {
- if (sk->bound_dev_if == sk2->bound_dev_if) {
+ if (sk != sk2 &&
+ sk->bound_dev_if == sk2->bound_dev_if) {
if (!sk_reuse ||
!sk2->reuse ||
sk2->state == TCP_LISTEN) {
@@ -269,11 +270,15 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
tb->fastreuse = 0;
success:
sk->num = snum;
- if ((sk->bind_next = tb->owners) != NULL)
- tb->owners->bind_pprev = &sk->bind_next;
- tb->owners = sk;
- sk->bind_pprev = &tb->owners;
- sk->prev = (struct sock *) tb;
+ if (sk->prev == NULL) {
+ if ((sk->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &sk->bind_next;
+ tb->owners = sk;
+ sk->bind_pprev = &tb->owners;
+ sk->prev = (struct sock *) tb;
+ } else {
+ BUG_TRAP(sk->prev == (struct sock *) tb);
+ }
ret = 0;
fail_unlock: