patch-2.1.124 linux/net/ipv4/tcp.c

Next file: linux/net/ipv4/tcp_input.c
Previous file: linux/net/ipv4/sysctl_net_ipv4.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.123/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.121 1998/09/07 00:13:52 davem Exp $
+ * Version:	$Id: tcp.c,v 1.127 1998/10/04 07:04:32 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -301,7 +301,7 @@
  *   MUST use the RFC 793 clock selection mechanism.  (doesn't, but it's
  *     OK: RFC 793 specifies a 250KHz clock, while we use 1MHz, which is
  *     necessary for 10Mbps networks - and harder than BSD to spoof!
- *     With syncookies we doesn't)
+ *     With syncookies we don't)
  *
  * Simultaneous Open Attempts (4.2.2.10)
  *   MUST support simultaneous open attempts (does)
@@ -598,8 +598,13 @@
 		     sk->urginline || !tp->urg_data))
 			mask |= POLLIN | POLLRDNORM;
 
-		if (sock_wspace(sk) >= tcp_min_write_space(sk, tp))
-			mask |= POLLOUT | POLLWRNORM;
+		if (!(sk->shutdown & SEND_SHUTDOWN)) {
+			if (sock_wspace(sk) >= tcp_min_write_space(sk, tp)) {
+				mask |= POLLOUT | POLLWRNORM;
+			} else {  /* send SIGIO later */
+				sk->socket->flags |= SO_NOSPACE;
+			}
+		}
 
 		if (tp->urg_data & URG_VALID)
 			mask |= POLLPRI;
@@ -729,6 +734,9 @@
 	lock_sock(sk);
 }
 
+/* When all user supplied data has been queued set the PSH bit */
+#define PSH_NEEDED (seglen == 0 && iovlen == 0)
+
 /*
  *	This routine copies from a user buffer into a socket,
  *	and starts the transmit system.
@@ -742,16 +750,16 @@
 	int mss_now;
 	int err = 0;
 	int copied  = 0;
-
-	/* Verify that the socket is locked */
-	if (!atomic_read(&sk->sock_readers))
-		printk("tcp_do_sendmsg: socket not locked!\n");
+	struct sk_buff *skb;
 
 	/* Wait for a connection to finish. */
 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
 		if((err = wait_for_tcp_connect(sk, flags)) != 0)
 			return err;
 
+	/* This should be in poll */
+	sk->socket->flags &= ~SO_NOSPACE; /* clear SIGIO XXX */
+
 	mss_now = tcp_current_mss(sk);
 
 	/* Ok commence sending. */
@@ -763,10 +771,9 @@
 
 		while(seglen > 0) {
 			int copy, tmp, queue_it;
-			struct sk_buff *skb;
 
 			if (err)
-				return -EFAULT;
+				goto do_fault2;
 
 			/* Stop on errors. */
 			if (sk->err)
@@ -810,12 +817,24 @@
 							from, skb_put(skb, copy),
 							copy, skb->csum, &err);
 					}
+					/*
+					 * FIXME: the *_user functions should
+					 *	  return how much data was
+					 *	  copied before the fault
+					 *	  occured and then a partial
+					 *	  packet with this data should
+					 *	  be sent.  Unfortunately
+					 *	  csum_and_copy_from_user doesn't
+					 *	  return this information.
+					 *	  ATM it might send partly zeroed
+					 *	  data in this case.
+					 */
 					tp->write_seq += copy;
 					TCP_SKB_CB(skb)->end_seq += copy;
 					from += copy;
 					copied += copy;
 					seglen -= copy;
-					if(!seglen && !iovlen)
+					if (PSH_NEEDED)
 						TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
 					continue;
 				}
@@ -884,7 +903,7 @@
 
 			/* Prepare control bits for TCP header creation engine. */
 			TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK |
-						  ((!seglen && !iovlen) ?
+						  (PSH_NEEDED ?
 						   TCPCB_FLAG_PSH : 0));
 			TCP_SKB_CB(skb)->sacked = 0;
 			if (flags & MSG_OOB) {
@@ -901,6 +920,9 @@
 			skb->csum = csum_and_copy_from_user(from,
 					skb_put(skb, copy), copy, 0, &err);
 
+			if (err)
+				goto do_fault;
+
 			from += copy;
 			copied += copy;
 
@@ -912,8 +934,6 @@
 		}
 	}
 	sk->err = 0;
-	if (err)
-		return -EFAULT;
 	return copied;
 
 do_sock_err:
@@ -930,8 +950,14 @@
 	if(copied)
 		return copied;
 	return err;
+do_fault:
+	kfree_skb(skb);
+do_fault2:
+	return -EFAULT;
 }
 
+#undef PSH_NEEDED
+
 /*
  *	Send an ack if one is backlogged at this point. Ought to merge
  *	this with tcp_send_ack().
@@ -1046,8 +1072,6 @@
 		tcp_eat_skb(sk, skb);
 	}
 
-	SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
-
   	/* We send an ACK if we can now advertise a non-zero window
 	 * which has been raised "significantly".
   	 */
@@ -1084,6 +1108,9 @@
 	int err = 0; 
 	int target = 1;		/* Read at least this many bytes */
 
+	if (sk->err)
+		return sock_error(sk);
+
 	if (sk->state == TCP_LISTEN)
 		return -ENOTCONN;
 
@@ -1165,6 +1192,14 @@
 		if (copied >= target)
 			break;
 
+		/*
+		   These three lines and clause if (sk->state == TCP_CLOSE)
+		   are unlikely to be correct, if target > 1.
+		   I DO NOT FIX IT, because I have no idea, what
+		   POSIX prescribes to make here. Probably, it really
+		   wants to lose data 8), if not all target is received.
+		                                                 --ANK
+		 */
 		if (sk->err && !(flags&MSG_PEEK)) {
 			copied = sock_error(sk);
 			break;
@@ -1589,7 +1624,10 @@
 	 * This does not pass any already set errors on the new socket
 	 * to the user, but they will be returned on the first socket operation
 	 * after the accept.
-	 */ 
+	 *
+	 * Once linux gets a multithreaded net_bh or equivalent there will be a race
+	 * here - you'll have to check for sk->zapped as set by the ICMP handler then.
+	 */
 
 	error = 0;
 out:

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov