patch-pre2.0.14-final2.0 linux/net/ipv4/tcp_input.c

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

diff -u --recursive --new-file pre2.0.14/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
@@ -64,9 +64,15 @@
 		if (m <= 0)
 			m = 1;
 
-		if (m > (sk->rtt >> 3))
+		/* This used to test against sk->rtt.
+		 * On a purely receiving link, there is no rtt measure.
+		 * The result is that we loose delayed ACKs on one way links.
+		 * Therefore we test against sk->rto, which will always
+		 * at least have a default value.
+		 */
+		if (m > sk->rto)
 		{
-			sk->ato = sk->rtt >> 3;
+			sk->ato = sk->rto;
 			/*
 			 * printk(KERN_DEBUG "ato: rtt %lu\n", sk->ato);
 			 */
@@ -124,7 +130,12 @@
 	 *	Now update timeout.  Note that this removes any backoff.
 	 */
 			 
+	/* Jacobson's algorithm calls for rto = R + 4V.
+	 * We diverge from Jacobson's algorithm here. See the commentary
+	 * in tcp_ack to understand why.
+	 */
 	sk->rto = (sk->rtt >> 3) + sk->mdev;
+	sk->rto += (sk->rto>>2) + (sk->rto >> (sk->cong_window-1));
 	if (sk->rto > 120*HZ)
 		sk->rto = 120*HZ;
 	if (sk->rto < HZ/5)	/* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */
@@ -195,7 +206,7 @@
 	/*
 	 * 	This packet is old news. Usually this is just a resend
 	 * 	from the far end, but sometimes it means the far end lost
-	 *	an ACK we send, so we better send an ACK.
+	 *	an ACK we sent, so we better send an ACK.
 	 */
 	tcp_send_ack(sk);
 }
@@ -842,8 +853,22 @@
 			 *  RTO = R*4V
 			 * In particular this gives better performance over
 			 * slow links, and should not effect fast links.
-			 */
+			 *
+			 * Note: Jacobson's algorithm is fine on BSD which
+			 * has a 1/2 second granularity clock, but with our
+			 * 1/100 second granularity clock we become too
+	 		 * sensitive to minor changes in the round trip time.
+			 * We add in two compensating factors.
+			 * First we multiply by 5/4. For large congestion
+			 * windows this allows us to tollerate burst traffic
+			 * delaying up to 1/4 of our packets.
+			 * We also add in a rtt / cong_window term.
+			 * For small congestion windows this allows
+			 * a single packet delay, but has neglibible effect
+			 * on the compensation for large windows.
+	 		 */
 			sk->rto = (sk->rtt >> 3) + sk->mdev;
+			sk->rto += (sk->rto>>2) + (sk->rto >> (sk->cong_window-1));
 			if (sk->rto > 120*HZ)
 				sk->rto = 120*HZ;
 			if (sk->rto < HZ/5)	/* Was 1*HZ, then 1 - turns out we must allow about
@@ -1247,8 +1272,18 @@
 			if (sk->ip_xmit_timeout != TIME_WRITE) {
 				if (sk->send_head)
 					tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
-				else
-					printk(KERN_ERR "send_head NULL in FIN_WAIT1\n");
+				else if (sk->ip_xmit_timeout != TIME_PROBE0
+				|| skb_queue_empty(&sk->write_queue)) {
+					/* BUG check case.
+					 * We have a problem here if there
+					 * is no timer running [leads to
+					 * frozen socket] or no data in the
+					 * write queue [means we sent a fin
+					 * and lost it from the queue before
+					 * changing the ack properly].
+					 */
+					printk(KERN_ERR "Lost timer or fin packet in tcp_fin.");
+				}
 			}
 			tcp_set_state(sk,TCP_CLOSING);
 			break;
@@ -1358,7 +1393,7 @@
 		} else {
 			if (sk->debug)
 				printk("Ack duplicate packet.\n");
-	    		tcp_send_ack(sk);
+			tcp_send_ack(sk);
 			return;
 		}
 
@@ -1865,8 +1900,14 @@
 			/* Crossed SYN or previous junk segment */
 			if(th->ack)
 			{
-				/* We got an ack, but it's not a good ack */
-				if(!tcp_ack(sk,th,skb->ack_seq,len))
+				/* We got an ack, but it's not a good ack.
+				 * We used to test this with a call to tcp_ack,
+				 * but this looses, because it takes the SYN
+				 * packet out of the send queue, even if
+				 * the ACK doesn't have the SYN bit sent, and
+				 * therefore isn't the one we are waiting for.
+				 */
+				if (after(skb->ack_seq, sk->sent_seq) || before(skb->ack_seq, sk->rcv_ack_seq))
 				{
 					/* Reset the ack - it's an ack from a 
 					   different connection  [ th->rst is checked in tcp_send_reset()] */
@@ -1888,6 +1929,15 @@
 					kfree_skb(skb, FREE_READ);
 					return 0;
 				}
+
+				/* process the ACK, get the SYN packet out
+				 * of the send queue, do other initial
+				 * processing stuff. [We know its good, and
+				 * we know it's the SYN,ACK we want.]
+				 */
+				tcp_ack(sk,th,skb->ack_seq,len);
+
+
 				/*
 				 *	Ok.. it's good. Set up sequence numbers and
 				 *	move to established.

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this