patch-1.3.87 linux/net/ipv4/tcp_timer.c

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

diff -u --recursive --new-file v1.3.86/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
@@ -22,21 +22,73 @@
 
 #include <net/tcp.h>
 
+void tcp_delack_timer(unsigned long data)
+{
+	tcp_send_ack((struct sock *) data);
+}
+
 /*
  *	Reset the retransmission timer
+ *
+ *	We currently ignore the why/when parameters, and decide on
+ *	our own how long we should wait on our own..
  */
  
 void tcp_reset_xmit_timer(struct sock *sk, int why, unsigned long when)
 {
-	del_timer(&sk->retransmit_timer);
-	sk->ip_xmit_timeout = why;
-	if((long)when < 0)
-	{
-		when=3;
-		printk("Error: Negative timer in xmit_timer\n");
+	unsigned long now = jiffies;
+
+	when = ~0UL;
+	why = -1;
+
+	/*
+	 * Was an old timer event active?
+	 */
+	if (del_timer(&sk->retransmit_timer)) {
+		why = sk->ip_xmit_timeout;
+		when = sk->retransmit_timer.expires;
+	}
+
+	/* 
+	 * Keepopen processing?
+	 */
+	if (sk->keepopen) {
+		unsigned long new_when = now + TCP_TIMEOUT_LEN;
+		if (new_when < when) {
+			when = new_when;
+			why = TIME_KEEPOPEN;
+		}
+	}
+
+	/*
+	 * Retransmission?
+	 */
+	if (sk->send_head) {
+		struct sk_buff * skb = sk->send_head;
+		unsigned long new_when = skb->when + sk->rto;
+		if (new_when < when) {
+			when = new_when;
+			why = TIME_WRITE;
+		}
+	} else if (!skb_queue_empty(&sk->write_queue)) {
+		/*
+		 * Zero window probe?
+		 */
+		struct sk_buff * skb = sk->write_queue.next;
+		if (before(sk->window_seq, skb->end_seq)) {
+			unsigned long new_when = now + TIME_PROBE0;
+			if (new_when < when) {
+				when = new_when;
+				why = TIME_PROBE0;
+			}
+		}
+	}
+
+	if (why >= 0) {
+		sk->ip_xmit_timeout = why;
+		sk->retransmit_timer.expires = when;
+		add_timer(&sk->retransmit_timer);
 	}
-	sk->retransmit_timer.expires=jiffies+when;
-	add_timer(&sk->retransmit_timer);
 }
 
 /*
@@ -170,46 +222,6 @@
 	return 1;
 }
 
-/*
- *	It could be we got here because we needed to send an ack,
- *	so we need to check for that and not just normal retransmit.
- */
-static void tcp_time_write_timeout(struct sock * sk)
-{
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	skb = sk->send_head;
-	if (!skb) {
-		if (sk->ack_backlog)
-			tcp_read_wakeup(sk);
-		restore_flags(flags);
-		return;
-	} 
-
-	/*
-	 *	Kicked by a delayed ack. Reset timer
-	 *	correctly now
-	 */
-	if (jiffies < skb->when + sk->rto) 
-	{
-		if (sk->ack_backlog)
-			tcp_read_wakeup(sk);
-		tcp_reset_xmit_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies);
-		restore_flags(flags);
-		return;
-	}
-
-	restore_flags(flags);
-	/*
-	 *	Retransmission
-	 */
-	sk->prot->retransmit (sk, 0);
-	tcp_write_timeout(sk);
-}
-
 
 /*
  *	The TCP retransmit timer. This lacks a few small details.
@@ -255,27 +267,25 @@
 	/* Window probing */
 	case TIME_PROBE0:
 		tcp_send_probe0(sk);
-		tcp_write_timeout(sk);
+		tcp_reset_xmit_timer(sk, 0, 0);		/* get us going again */
 		break;
 
 	/* Retransmitting */
 	case TIME_WRITE:
-		tcp_time_write_timeout(sk);
+		sk->prot->retransmit (sk, 0);
+		tcp_write_timeout(sk);
+		tcp_reset_xmit_timer(sk, 0, 0);		/* get us going again */		
 		break;
 
 	/* Sending Keepalives */
 	case TIME_KEEPOPEN:
-		/* 
-		 * this reset_timer() call is a hack, this is not
-		 * how KEEPOPEN is supposed to work.
-		 */
-		tcp_reset_xmit_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
 		/* Send something to keep the connection open. */
 		if (sk->prot->write_wakeup)
 			  sk->prot->write_wakeup (sk);
 		sk->retransmits++;
 		sk->prot->retransmits++;
 		tcp_write_timeout(sk);
+		tcp_reset_xmit_timer (sk, 0, 0);
 		break;
 
 	default:

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