patch-2.2.4 linux/net/ipv4/af_inet.c

Next file: linux/net/ipv4/arp.c
Previous file: linux/net/ipv4/Config.in
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.3/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.83 1999/02/22 13:54:18 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.85 1999/03/21 05:22:28 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -53,6 +53,7 @@
  *		David S. Miller	:	New socket lookup architecture.
  *					Some other random speedups.
  *		Cyrus Durgin	:	Cleaned up file for kmod hacks.
+ *		Andi Kleen	:	Fix inet_stream_connect TCP race.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -175,8 +176,6 @@
 	if(sk->opt)
 		kfree(sk->opt);
 	dst_release(sk->dst_cache);
-	if (atomic_read(&sk->omem_alloc))
-		printk(KERN_DEBUG "kill_sk_now: optmem leakage (%d bytes) detected.\n", atomic_read(&sk->omem_alloc));
 	sk_free(sk);
 }
 
@@ -613,15 +612,16 @@
 	}
 
 	if(sock->state == SS_CONNECTING) {
+		/* Note: tcp_connected contains SYN_RECV, which may cause
+		   bogus results here. -AK */ 
 		if(tcp_connected(sk->state)) {
 			sock->state = SS_CONNECTED;
 			return 0;
 		}
-		if(sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK)) {
-			if(sk->err)
-				return sock_error(sk);
+		if (sk->zapped || sk->err)
+			goto sock_error;
+		if (flags & O_NONBLOCK)
 			return -EALREADY;
-		}
 	} else {
 		/* We may need to bind the socket. */
 		if (inet_autobind(sk) != 0)
@@ -629,15 +629,17 @@
 		if (sk->prot->connect == NULL) 
 			return(-EOPNOTSUPP);
 		err = sk->prot->connect(sk, uaddr, addr_len);
+		/* Note: there is a theoretical race here when an wake up
+		   occurred before inet_wait_for_connect is entered. In 2.3
+		   the wait queue setup should be moved before the low level
+		   connect call. -AK*/
 		if (err < 0)
 			return(err);
   		sock->state = SS_CONNECTING;
 	}
 	
-	if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING) {
-		sock->state = SS_UNCONNECTED;
-		return sock_error(sk);
-	}
+	if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING)
+		goto sock_error;
 
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) 
 	  	return (-EINPROGRESS);
@@ -649,17 +651,19 @@
 	}
 
 	sock->state = SS_CONNECTED;
-	if ((sk->state != TCP_ESTABLISHED) && sk->err) {
-		/* This is ugly but needed to fix a race in the ICMP error handler */
-		if (sk->protocol == IPPROTO_TCP && sk->zapped) { 
-			lock_sock(sk);  
-			tcp_set_state(sk, TCP_CLOSE);
-			release_sock(sk); 
-		}
-		sock->state = SS_UNCONNECTED;
-		return sock_error(sk);
-	}
+	if ((sk->state != TCP_ESTABLISHED) && sk->err)
+		goto sock_error; 
 	return(0);
+
+sock_error:	
+	/* This is ugly but needed to fix a race in the ICMP error handler */
+	if (sk->zapped && sk->state != TCP_CLOSE) { 
+		lock_sock(sk);  
+		tcp_set_state(sk, TCP_CLOSE);
+		release_sock(sk); 
+	}
+	sock->state = SS_UNCONNECTED;
+	return sock_error(sk);
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)