patch-2.1.129 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 v2.1.128/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.136 1998/11/07 14:36:18 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.141 1998/11/18 02:12:07 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -262,7 +262,7 @@
 }
 
 /* When we get a reset we do this. */
-static void tcp_reset(struct sock *sk, struct sk_buff *skb)
+static void tcp_reset(struct sock *sk)
 {
 	sk->zapped = 1;
 
@@ -277,7 +277,7 @@
 		default:
 			sk->err = ECONNRESET;
 	};
-	tcp_set_state(sk,TCP_CLOSE);
+	tcp_set_state(sk, TCP_CLOSE);
 	sk->shutdown = SHUTDOWN_MASK;
 	if (!sk->dead) 
 		sk->state_change(sk);
@@ -483,33 +483,36 @@
 		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
 			tp->dup_acks++;
 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-                                tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
+                                tp->snd_ssthresh =
+					max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3);
 				tp->high_seq = tp->snd_nxt;
 				if(!tp->fackets_out)
-					tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+					tcp_retransmit_skb(sk,
+							   skb_peek(&sk->write_queue));
 				else
 					tcp_fack_retransmit(sk);
                                 tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 			}
-		}
-
-                /* 2. Each time another duplicate ACK arrives, increment 
-                 * cwnd by the segment size. [...] Transmit a packet...
-                 *
-                 * Packet transmission will be done on normal flow processing
-                 * since we're not in "retransmit mode".  We do not use duplicate
-		 * ACKs to artificially inflate the congestion window when
-		 * doing FACK.
-                 */
-                if (tp->dup_acks > 3) {
+		} else if (++tp->dup_acks > 3) {
+			/* 2. Each time another duplicate ACK arrives, increment 
+			 * cwnd by the segment size. [...] Transmit a packet...
+			 *
+			 * Packet transmission will be done on normal flow processing
+			 * since we're not in "retransmit mode".  We do not use
+			 * duplicate ACKs to artificially inflate the congestion
+			 * window when doing FACK.
+			 */
 			if(!tp->fackets_out) {
 				tp->snd_cwnd++;
 			} else {
-				/* Fill any further holes which may have appeared.
-				 * We may want to change this to run every further
-				 * multiple-of-3 dup ack increments, to be more robust
-				 * against out-of-order packet delivery.  -DaveM
+				/* Fill any further holes which may have
+				 * appeared.
+				 *
+				 * We may want to change this to run every
+				 * further multiple-of-3 dup ack increments,
+				 * to be more robust against out-of-order
+				 * packet delivery.  -DaveM
 				 */
 				tcp_fack_retransmit(sk);
 			}
@@ -552,7 +555,8 @@
 				 * from snd_una is if this was a window update.
 				 */
 				if (ack != tp->snd_una && before(ack, tp->high_seq)) {
-                                	tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+                                	tcp_retransmit_skb(sk,
+							   skb_peek(&sk->write_queue));
                                 	tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 				}
 			} else {
@@ -568,7 +572,7 @@
 /* This is Jacobson's slow start and congestion avoidance. 
  * SIGCOMM '88, p. 328.
  */
-static void tcp_cong_avoid(struct tcp_opt *tp)
+static __inline__ void tcp_cong_avoid(struct tcp_opt *tp)
 {
         if (tp->snd_cwnd <= tp->snd_ssthresh) {
                 /* In "safe" area, increase. */
@@ -656,6 +660,33 @@
 	}
 }
  
+/* Should we open up the congestion window? */
+static __inline__ int should_advance_cwnd(struct tcp_opt *tp, int flag)
+{
+	/* Data must have been acked. */
+	if ((flag & FLAG_DATA_ACKED) == 0)
+		return 0;
+
+	/* Some of the data acked was retransmitted somehow? */
+	if ((flag & FLAG_RETRANS_DATA_ACKED) != 0) {
+		/* We advance in all cases except during
+		 * non-FACK fast retransmit/recovery.
+		 */
+		if (tp->fackets_out != 0 ||
+		    tp->retransmits != 0)
+			return 1;
+
+		/* Non-FACK fast retransmit does it's own
+		 * congestion window management, don't get
+		 * in the way.
+		 */
+		return 0;
+	}
+
+	/* New non-retransmitted data acked, always advance.  */
+	return 1;
+}
+
 /* Read draft-ietf-tcplw-high-performance before mucking
  * with this code. (Superceeds RFC1323)
  */
@@ -691,8 +722,10 @@
 		}
 	} else {
 		tcp_set_rto(tp);
-		tcp_cong_avoid(tp);
 	}
+	if (should_advance_cwnd(tp, flag))
+		tcp_cong_avoid(tp);
+
 	/* NOTE: safe here so long as cong_ctl doesn't use rto */
 	tcp_bound_rto(tp);
 }
@@ -810,9 +843,10 @@
 					tcp_set_rto(tp);
 					tcp_bound_rto(tp);
 				}
-				tcp_cong_avoid(tp);
 			}
 		}
+		if (should_advance_cwnd(tp, flag))
+			tcp_cong_avoid(tp);
 	}
 
 	if (tp->packets_out) {
@@ -1814,12 +1848,12 @@
 	if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
 		SOCK_DEBUG(sk, "syn in established state\n");
 		tcp_statistics.TcpInErrs++;
-		tcp_reset(sk, skb);
+		tcp_reset(sk);
 		return 1;
 	}
 	
 	if(th->rst) {
-		tcp_reset(sk,skb);
+		tcp_reset(sk);
 		goto discard;
 	}
 
@@ -1944,8 +1978,27 @@
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	int queued = 0;
 
-	/* state == CLOSED, hash lookup always fails, so no worries. -DaveM */
 	switch (sk->state) {
+	case TCP_CLOSE:
+		/* When state == CLOSED, hash lookup always fails.
+		 *
+		 * But, there is a back door, the backlog queue.
+		 * If we have a sequence of packets in the backlog
+		 * during __release_sock() which have a sequence such
+		 * that:
+		 *	packet X	causes entry to TCP_CLOSE state
+		 *	...
+		 *	packet X + N	has FIN bit set
+		 *
+		 * We report a (luckily) harmless error in this case.
+		 * The issue is that backlog queue processing bypasses
+		 * any hash lookups (we know which socket packets are for).
+		 * The correct behavior here is what 2.0.x did, since
+		 * a TCP_CLOSE socket does not exist.  Drop the frame
+		 * and send a RST back to the other end.
+		 */
+		return 1;
+
 	case TCP_LISTEN:
 		/* These use the socket TOS.. 
 		 * might want to be the received TOS 
@@ -1998,7 +2051,7 @@
 			}
 
 			if(th->rst) {
-				tcp_reset(sk,skb);
+				tcp_reset(sk);
 				goto discard;
 			}
 
@@ -2127,7 +2180,7 @@
 
 	/* step 2: check RST bit */
 	if(th->rst) {
-		tcp_reset(sk,skb);
+		tcp_reset(sk);
 		goto discard;
 	}
 
@@ -2150,7 +2203,7 @@
 	 */
 
 	if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
-		tcp_reset(sk, skb);
+		tcp_reset(sk);
 		return 1;
 	}
 
@@ -2230,7 +2283,7 @@
 		 */
 		if ((sk->shutdown & RCV_SHUTDOWN) && sk->dead) {
 			if (after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
-				tcp_reset(sk, skb);
+				tcp_reset(sk);
 				return 1;
 			}
 		}

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