patch-2.2.7 linux/net/ipv4/tcp_input.c

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

diff -u --recursive --new-file v2.2.6/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.159 1999/03/17 19:30:39 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.163 1999/04/28 16:08:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -97,7 +97,7 @@
 static void tcp_delack_estimator(struct tcp_opt *tp)
 {
 	if(tp->ato == 0) {
-		tp->lrcvtime = jiffies;
+		tp->lrcvtime = tcp_time_stamp;
 
 		/* Help sender leave slow start quickly,
 		 * and also makes sure we do not take this
@@ -106,9 +106,9 @@
 		tp->ato = 1;
 		tcp_enter_quickack_mode(tp);
 	} else {
-		int m = jiffies - tp->lrcvtime;
+		int m = tcp_time_stamp - tp->lrcvtime;
 
-		tp->lrcvtime = jiffies;
+		tp->lrcvtime = tcp_time_stamp;
 		if(m <= 0)
 			m = 1;
 		if(m > tp->rto)
@@ -231,7 +231,7 @@
 		 */
 		if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) {
 			tp->ts_recent = tp->rcv_tsval;
-			tp->ts_recent_stamp = jiffies;
+			tp->ts_recent_stamp = tcp_time_stamp;
 		}
 	}
 }
@@ -241,7 +241,7 @@
 extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct tcphdr *th, unsigned len)
 {
 	/* ts_recent must be younger than 24 days */
-	return (((s32)(jiffies - tp->ts_recent_stamp) >= PAWS_24DAYS) ||
+	return (((s32)(tcp_time_stamp - tp->ts_recent_stamp) >= PAWS_24DAYS) ||
 		(((s32)(tp->rcv_tsval - tp->ts_recent) < 0) &&
 		 /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM */
 		 (len != (th->doff * 4))));
@@ -609,7 +609,7 @@
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sk_buff *skb;
-	unsigned long now = jiffies;
+	__u32 now = tcp_time_stamp;
 	int acked = 0;
 
 	/* If we are retransmitting, and this ACK clears up to
@@ -725,7 +725,7 @@
 	if (!(flag & FLAG_DATA_ACKED))
 		return;
 
-	seq_rtt = jiffies-tp->rcv_tsecr;
+	seq_rtt = tcp_time_stamp - tp->rcv_tsecr;
 	tcp_rtt_estimator(tp, seq_rtt);
 	if (tp->retransmits) {
 		if (tp->packets_out == 0) {
@@ -749,7 +749,7 @@
 static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
 {
 	struct sk_buff *skb = skb_peek(&sk->write_queue);
-	long when = tp->rto - (jiffies - TCP_SKB_CB(skb)->when);
+	__u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
 
 	/* Some data was ACK'd, if still retransmitting (due to a
 	 * timeout), resend more of the retransmit queue.  The
@@ -778,7 +778,7 @@
 	if (tp->pending == TIME_KEEPOPEN)
 	  	tp->probes_out = 0;
 
-	tp->rcv_tstamp = jiffies;
+	tp->rcv_tstamp = tcp_time_stamp;
 
 	/* If the ack is newer than sent or older than previous acks
 	 * then we can probably ignore it.
@@ -2112,7 +2112,7 @@
 				tp->tcp_header_len = sizeof(struct tcphdr);
 			if (tp->saw_tstamp) {
 				tp->ts_recent = tp->rcv_tsval;
-				tp->ts_recent_stamp = jiffies;
+				tp->ts_recent_stamp = tcp_time_stamp;
 			}
 
 			/* Can't be earlier, doff would be wrong. */
@@ -2136,7 +2136,7 @@
 				tcp_parse_options(sk, th, tp, 0);
 				if (tp->saw_tstamp) {
 					tp->ts_recent = tp->rcv_tsval;
-					tp->ts_recent_stamp = jiffies;
+					tp->ts_recent_stamp = tcp_time_stamp;
 				}
 				
 				tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
@@ -2189,8 +2189,22 @@
 		}
 	}
 
+	/* The silly FIN test here is necessary to see an advancing ACK in
+	 * retransmitted FIN frames properly.  Consider the following sequence:
+	 *
+	 *	host1 --> host2		FIN XSEQ:XSEQ(0) ack YSEQ
+	 *	host2 --> host1		FIN YSEQ:YSEQ(0) ack XSEQ
+	 *	host1 --> host2		XSEQ:XSEQ(0) ack YSEQ+1
+	 *	host2 --> host1		FIN YSEQ:YSEQ(0) ack XSEQ+1	(fails tcp_sequence test)
+	 *
+	 * At this point the connection will deadlock with host1 believing
+	 * that his FIN is never ACK'd, and thus it will retransmit it's FIN
+	 * forever.  The following fix is from Taral (taral@taral.net).
+	 */
+
 	/* step 1: check sequence number */
-	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
+	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq) &&
+	    !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)) {
 		if (!th->rst) {
 			tcp_send_ack(sk);
 			goto discard;

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