Make tcp_sequence check more loose, so that
we respect control flags in packets which are not
out-of-window after truncating to the current window.
From Alexey.
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index f3a9092..08e4e3b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.207 2001-01-22 02:36:37 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.208 2001-01-30 01:38:22 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2164,43 +2164,23 @@
 		!tcp_disordered_ack(tp, skb));
 }
 
-static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
-{
-	u32 end_window = tp->rcv_wup + tp->rcv_wnd;
-#ifdef TCP_FORMAL_WINDOW
-	u32 rcv_wnd = tcp_receive_window(tp);
-#else
-	u32 rcv_wnd = tp->rcv_wnd;
-#endif
-
-	if (rcv_wnd &&
-	    after(end_seq, tp->rcv_nxt) &&
-	    before(seq, end_window))
-		return 1;
-	if (seq != end_window)
-		return 0;
-	return (seq == end_seq);
-}
-
-/* This functions checks to see if the tcp header is actually acceptable.
+/* Check segment sequence number for validity.
  *
- * Actually, our check is seriously broken, we must accept RST,ACK,URG
- * even on zero window effectively trimming data. It is RFC, guys.
- * But our check is so beautiful, that I do not want to repair it
- * now. However, taking into account those stupid plans to start to
- * send some texts with RST, we have to handle at least this case. --ANK
+ * Segment controls are considered valid, if the segment
+ * fits to the window after truncation to the window. Acceptability
+ * of data (and SYN, FIN, of course) is checked separately.
+ * See tcp_data_queue(), for example.
+ *
+ * Also, controls (RST is main one) are accepted using RCV.WUP instead
+ * of RCV.NXT. Peer still did not advance his SND.UNA when we
+ * delayed ACK, so that hisSND.UNA<=ourRCV.WUP.
+ * (borrowed from freebsd)
  */
-extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq, int rst)
-{
-#ifdef TCP_FORMAL_WINDOW
-	u32 rcv_wnd = tcp_receive_window(tp);
-#else
-	u32 rcv_wnd = tp->rcv_wnd;
-#endif
-	if (seq == tp->rcv_nxt)
-		return (rcv_wnd || (end_seq == seq) || rst);
 
-	return __tcp_sequence(tp, seq, end_seq);
+static inline int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
+{
+	return	!before(end_seq, tp->rcv_wup) &&
+		!after(seq, tp->rcv_nxt + tcp_receive_window(tp));
 }
 
 /* When we get a reset we do this. */
@@ -2541,7 +2521,10 @@
 	 *  Out of sequence packets to the out_of_order_queue.
 	 */
 	if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
-		/* Ok. In sequence. */
+		if (tcp_receive_window(tp) == 0)
+			goto out_of_window;
+
+		/* Ok. In sequence. In window. */
 		if (tp->ucopy.task == current &&
 		    tp->copied_seq == tp->rcv_nxt &&
 		    tp->ucopy.len &&
@@ -2601,20 +2584,27 @@
 		return;
 	}
 
-#ifdef TCP_DEBUG
-	/* An old packet, either a retransmit or some packet got lost. */
 	if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
-		/* A retransmit, 2nd most common case.  Force an imediate ack.
-		 * 
-		 * It is impossible, seq is checked by top level.
-		 */
-		printk("BUG: retransmit in tcp_data_queue: seq %X\n", TCP_SKB_CB(skb)->seq);
+		/* A retransmit, 2nd most common case.  Force an immediate ack. */
+		NET_INC_STATS_BH(DelayedACKLost);
 		tcp_enter_quickack_mode(tp);
+		tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
+
+out_of_window:
 		tcp_schedule_ack(tp);
 		__kfree_skb(skb);
 		return;
 	}
-#endif
+
+	/* Out of window. F.e. zero window probe.
+	 *
+	 * Note: it is highly possible that we may open window and enqueue
+	 * this segment now. However, this will be known only after we queue
+	 * it, which will result in queue full of successive 1 byte BSD
+	 * window probes, it is SWS in fact. So, always reject it and send ACK.
+	 */
+	if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt+tcp_receive_window(tp)))
+		goto out_of_window;
 
 	tcp_enter_quickack_mode(tp);
 
@@ -3336,7 +3326,7 @@
 	 *	Standard slow path.
 	 */
 
-	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, th->rst)) {
+	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
 		/* RFC793, page 37: "In all states except SYN-SENT, all reset
 		 * (RST) segments are validated by checking their SEQ-fields."
 		 * And page 69: "If an incoming segment is not acceptable,
@@ -3672,7 +3662,7 @@
 	}
 
 	/* step 1: check sequence number */
-	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, th->rst)) {
+	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
 		if (!th->rst)
 			tcp_send_dupack(sk, skb);
 		goto discard;