patch-pre2.0.10 linux/net/ipv4/tcp_output.c

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

diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
@@ -18,6 +18,9 @@
  *		Matthew Dillon, <dillon@apollo.west.oic.com>
  *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
  *		Jorge Cwik, <jorge@laser.satlink.net>
+ *
+ * Fixes:	Eric Schenk	: avoid multiple retransmissions in one
+ *				: round trip timeout.
  */
 
 #include <linux/config.h>
@@ -175,7 +178,7 @@
 		if (before(sk->window_seq, sk->write_queue.next->end_seq) &&
 		    sk->send_head == NULL && sk->ack_backlog == 0)
 			tcp_reset_xmit_timer(sk, TIME_PROBE0, sk->rto);
-	} 
+	}
 	else 
 	{
 		/*
@@ -198,9 +201,9 @@
 		sk->prot->queue_xmit(sk, skb->dev, skb, 0);
 		
 		/*
-		 *	Set for next retransmit based on expected ACK time.
-		 *	FIXME: We set this every time which means our 
-		 *	retransmits are really about a window behind.
+		 *	Set for next retransmit based on expected ACK time
+		 *	of the first packet in the resend queue.
+		 *	This is no longer a window behind.
 		 */
 
 		tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
@@ -364,10 +367,6 @@
 
 			clear_delayed_acks(sk);
 
-			/*
-			 *	Again we slide the timer wrongly
-			 */
-			 
 			tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
 		}
 	}
@@ -384,10 +383,17 @@
 	struct sk_buff * skb;
 	struct proto *prot;
 	struct device *dev;
-	int ct=0;
 	struct rtable *rt;
 
 	prot = sk->prot;
+	if (!all) {
+		/*
+		 * If we are just retransmitting one packet reset
+		 * to the start of the queue.
+		 */
+		sk->send_next = sk->send_head;
+		sk->packets_out = 0;
+	}
 	skb = sk->send_head;
 
 	while (skb != NULL)
@@ -399,7 +405,7 @@
 		dev = skb->dev;
 		IS_SKB(skb);
 		skb->when = jiffies;
-		
+
 		/* dl1bke 960201 - @%$$! Hope this cures strange race conditions    */
 		/*		   with AX.25 mode VC. (esp. DAMA)		    */
 		/*		   if the buffer is locked we should not retransmit */
@@ -523,17 +529,15 @@
 					/* Now queue it */
 					ip_statistics.IpOutRequests++;
 					dev_queue_xmit(skb, dev, sk->priority);
+					sk->packets_out++;
 				}
 			}
 		}
-		
 
 		/*
 		 *	Count retransmissions
 		 */
 		 
-		ct++;
-		sk->retransmits++;
 		sk->prot->retransmits++;
 		tcp_statistics.TcpRetransSegs++;
 
@@ -544,6 +548,11 @@
 		if (sk->retransmits)
 			sk->high_seq = sk->sent_seq;
 		
+		/*
+	         * Advance the send_next pointer so we don't keep
+		 * retransmitting the same stuff every time we get an ACK.
+		 */
+		sk->send_next = skb->link3;
 
 		/*
 		 *	Only one retransmit requested.
@@ -556,8 +565,9 @@
 		 *	This should cut it off before we send too many packets.
 		 */
 
-		if (ct >= sk->cong_window)
+		if (sk->packets_out >= sk->cong_window)
 			break;
+
 		skb = skb->link3;
 	}
 }
@@ -888,10 +898,10 @@
 	    && skb_queue_empty(&sk->write_queue)
 	    && sk->ip_xmit_timeout == TIME_WRITE)
 	{
-		if(sk->keepopen)
+		if (sk->keepopen)
 			tcp_reset_xmit_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
 		else
-			delete_timer(sk);
+			del_timer(&sk->retransmit_timer);
 	}
 
 	/*
@@ -946,7 +956,7 @@
 
   	tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), buff);
   	if (sk->debug)
-  		 printk("\rtcp_ack: seq %x ack %x\n", sk->sent_seq, sk->acked_seq);
+  		 printk(KERN_ERR "\rtcp_ack: seq %x ack %x\n", sk->sent_seq, sk->acked_seq);
   	sk->prot->queue_xmit(sk, dev, buff, 1);
   	tcp_statistics.TcpOutSegs++;
 }

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