diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-13 20:55:15 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-13 20:55:15 +0000 |
commit | 1471f525455788c20b130690e0f104df451aeb43 (patch) | |
tree | 3778beba56558beb9a9548ea5b467e9c44ea966f /net/ipv4 | |
parent | e80d2c5456d30ebba5b0eb8a9d33e17d815d4d83 (diff) |
Merge with Linux 2.3.51.
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp.c | 39 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 21 |
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: |