patch-2.4.0-test7 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.4.0-test6/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.193 2000/04/20 14:41:16 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.198 2000/08/15 20:15:23 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -55,20 +55,15 @@
  *					work without delayed acks. 
  *		Andi Kleen:		Process packets with PSH set in the
  *					fast path.
+ *		J Hadi Salim:		ECN support
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <net/tcp.h>
 #include <net/inet_common.h>
 #include <linux/ipsec.h>
 
-#ifdef CONFIG_SYSCTL
-#define SYNC_INIT 0 /* let the user enable it */
-#else
-#define SYNC_INIT 1
-#endif
 
 /* These are on by default so the code paths get tested.
  * For the final 2.2 this may be undone at our discretion. -DaveM
@@ -76,33 +71,39 @@
 int sysctl_tcp_timestamps = 1;
 int sysctl_tcp_window_scaling = 1;
 int sysctl_tcp_sack = 1;
+int sysctl_tcp_fack = 1;
+int sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH;
+int sysctl_tcp_ecn = 1;
+int sysctl_tcp_dsack = 1;
+int sysctl_tcp_app_win = 31;
+int sysctl_tcp_adv_win_scale = 2;
 
-int sysctl_tcp_syncookies = SYNC_INIT; 
-int sysctl_tcp_stdurg;
-int sysctl_tcp_rfc1337;
-int sysctl_tcp_tw_recycle = 1;
-int sysctl_tcp_abort_on_overflow = 0;
+int sysctl_tcp_stdurg = 0;
+int sysctl_tcp_rfc1337 = 0;
 int sysctl_tcp_max_orphans = NR_FILE;
-int sysctl_tcp_max_tw_buckets = NR_FILE*2;
 
-static int prune_queue(struct sock *sk);
+#define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
+#define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
+#define FLAG_DATA_ACKED		0x04 /* This ACK acknowledged new data.		*/
+#define FLAG_RETRANS_DATA_ACKED	0x08 /* "" "" some of which was retransmitted.	*/
+#define FLAG_SYN_ACKED		0x10 /* This ACK acknowledged SYN.		*/
+#define FLAG_DATA_SACKED	0x20 /* New SACK.				*/
+#define FLAG_ECE		0x40 /* ECE in this ACK				*/
+#define FLAG_DATA_LOST		0x80 /* SACK detected data lossage.		*/
+#define FLAG_SLOWPATH		0x100 /* Do not skip RFC checks for window update.*/
+
+#define FLAG_ACKED		(FLAG_DATA_ACKED|FLAG_SYN_ACKED)
+#define FLAG_NOT_DUP		(FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
+#define FLAG_CA_ALERT		(FLAG_DATA_SACKED|FLAG_ECE)
+#define FLAG_FORWARD_PROGRESS	(FLAG_ACKED|FLAG_DATA_SACKED)
+
+#define IsReno(tp) ((tp)->sack_ok == 0)
+#define IsFack(tp) ((tp)->sack_ok & 2)
+
+#define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH)
 
-/* 
- * Adapt the MSS value used to make delayed ack decision to the 
+/* Adapt the MSS value used to make delayed ack decision to the 
  * real world.
- *
- * The constant 536 hasn't any good meaning.  In IPv4 world
- * MTU may be smaller, though it contradicts to RFC1122, which
- * states that MSS must be at least 536.
- * We use the constant to do not ACK each second
- * packet in a stream of tiny size packets.
- * It means that super-low mtu links will be aggressively delacked.
- * Seems, it is even good. If they have so low mtu, they are weirdly
- * slow.
- *
- * AK: BTW it may be useful to add an option to lock the rcv_mss.
- *     this way the beowulf people wouldn't need ugly patches to get the
- *     ack frequencies they want and it would be an elegant way to tune delack.
  */ 
 static __inline__ void tcp_measure_rcv_mss(struct tcp_opt *tp, struct sk_buff *skb)
 {
@@ -117,6 +118,9 @@
 	len = skb->len;
 	if (len >= tp->ack.rcv_mss) {
 		tp->ack.rcv_mss = len;
+		/* Dubious? Rather, it is final cut. 8) */
+		if (tcp_flag_word(skb->h.th)&TCP_REMNANT)
+			tp->ack.pending |= TCP_ACK_PUSHED;
 	} else {
 		/* Otherwise, we make more careful check taking into account,
 		 * that SACKs block is variable.
@@ -124,37 +128,47 @@
 		 * "len" is invariant segment length, including TCP header.
 		 */
 		len = skb->tail - skb->h.raw;
-		if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr)) {
+		if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) ||
+		    /* If PSH is not set, packet should be
+		     * full sized, provided peer TCP is not badly broken.
+		     * This observation (if it is correct 8)) allows
+		     * to handle super-low mtu links fairly.
+		     */
+		    (len >= TCP_MIN_MSS + sizeof(struct tcphdr) &&
+		     !(tcp_flag_word(skb->h.th)&TCP_REMNANT))) {
 			/* Subtract also invariant (if peer is RFC compliant),
 			 * tcp header plus fixed timestamp option length.
 			 * Resulting "len" is MSS free of SACK jitter.
 			 */
 			len -= tp->tcp_header_len;
-			if (len == lss)
-				tp->ack.rcv_mss = len;
 			tp->ack.last_seg_size = len;
+			if (len == lss) {
+				tp->ack.rcv_mss = len;
+				return;
+			}
 		}
+		tp->ack.pending |= TCP_ACK_PUSHED;
 	}
 }
 
-
-static __inline__ void tcp_enter_quickack_mode(struct tcp_opt *tp)
+static void tcp_incr_quickack(struct tcp_opt *tp)
 {
-	unsigned quickacks = tcp_receive_window(tp)/(2*tp->ack.rcv_mss);
+	unsigned quickacks = tp->rcv_wnd/(2*tp->ack.rcv_mss);
 
-	tp->ack.quick = max(min(quickacks, 127), 1);
+	if (quickacks==0)
+		quickacks=2;
+	if (quickacks > tp->ack.quick)
+		tp->ack.quick = min(quickacks, TCP_MAX_QUICKACKS);
+}
 
-	if (!tp->tstamp_ok && tp->ack.quick>2) {
-		/* Quick ACKs are _dangerous_, if RTTM is not used.
-		 * See comment in tcp_init_metrics(). We still help
-		 * them to overcome the most difficult, initial
-		 * phase of slow start.
-		 */
-		tp->ack.quick = 2;
-	}
+void tcp_enter_quickack_mode(struct tcp_opt *tp)
+{
+	tcp_incr_quickack(tp);
+	tp->ack.pingpong = 0;
+	tp->ack.ato = TCP_ATO_MIN;
 }
 
-/* Send ACKs quickly, if "quick" count is not ehausted
+/* Send ACKs quickly, if "quick" count is not exhausted
  * and the session is not interactive.
  */
 
@@ -163,6 +177,173 @@
 	return (tp->ack.quick && !tp->ack.pingpong);
 }
 
+/* Buffer size and advertised window tuning.
+ *
+ * 1. Tuning sk->sndbuf, when connection enters established state.
+ */
+
+static void tcp_fixup_sndbuf(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	int sndmem = tp->mss_clamp+MAX_TCP_HEADER+16+sizeof(struct sk_buff);
+
+	if (sk->sndbuf < 3*sndmem)
+		sk->sndbuf = min(3*sndmem, sysctl_tcp_wmem[2]);
+}
+
+/* 2. Tuning advertised window (window_clamp, rcv_ssthresh)
+ *
+ * All tcp_full_space() is split to two parts: "network" buffer, allocated
+ * forward and advertised in receiver window (tp->rcv_wnd) and
+ * "application buffer", required to isolate scheduling/application
+ * latencies from network.
+ * window_clamp is maximal advertised window. It can be less than
+ * tcp_full_space(), in this case tcp_full_space() - window_clamp
+ * is reserved for "application" buffer. The less window_clamp is
+ * the smoother our behaviour from viewpoint of network, but the lower
+ * throughput and the higher sensitivity of the connection to losses. 8)
+ *
+ * rcv_ssthresh is more strict window_clamp used at "slow start"
+ * phase to predict further behaviour of this connection.
+ * It is used for two goals:
+ * - to enforce header prediction at sender, even when application
+ *   requires some significant "application buffer". It is check #1.
+ * - to prevent pruning of receive queue because of misprediction
+ *   of receiver window. Check #2.
+ *
+ * The scheme does not work when sender sends good segments opening
+ * window and then starts to feed us spagetti. But it should work
+ * in common situations. Otherwise, we have to rely on queue collapsing.
+ */
+
+/* Slow part of check#2. */
+static int
+__tcp_grow_window(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb)
+{
+	/* Optimize this! */
+	int truesize = tcp_win_from_space(skb->truesize)/2;
+	int window = tcp_full_space(sk)/2;
+
+	while (tp->rcv_ssthresh <= window) {
+		if (truesize <= skb->len)
+			return 2*tp->ack.rcv_mss;
+
+		truesize >>= 1;
+		window >>= 1;
+	}
+	return 0;
+}
+
+static __inline__ void
+tcp_grow_window(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb)
+{
+	/* Check #1 */
+	if (tp->rcv_ssthresh < tp->window_clamp &&
+	    (int)tp->rcv_ssthresh < tcp_space(sk) &&
+	    !tcp_memory_pressure) {
+		int incr;
+
+		/* Check #2. Increase window, if skb with such overhead
+		 * will fit to rcvbuf in future.
+		 */
+		if (tcp_win_from_space(skb->truesize) <= skb->len)
+			incr = 2*tp->advmss;
+		else
+			incr = __tcp_grow_window(sk, tp, skb);
+
+		if (incr) {
+			tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, tp->window_clamp);
+			tp->ack.quick |= 1;
+		}
+	}
+}
+
+/* 3. Tuning rcvbuf, when connection enters established state. */
+
+static void tcp_fixup_rcvbuf(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	int rcvmem = tp->advmss+MAX_TCP_HEADER+16+sizeof(struct sk_buff);
+
+	/* Try to select rcvbuf so that 4 mss-sized segments
+	 * will fit to window and correspoding skbs will fit to our rcvbuf.
+	 * (was 3; 4 is minimum to allow fast retransmit to work.)
+	 */
+	while (tcp_win_from_space(rcvmem) < tp->advmss)
+		rcvmem += 128;
+	if (sk->rcvbuf < 4*rcvmem)
+		sk->rcvbuf = min(4*rcvmem, sysctl_tcp_rmem[2]);
+}
+
+/* 4. Try to fixup all. It is made iimediately after connection enters
+ *    established state.
+ */
+static void tcp_init_buffer_space(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	int maxwin;
+
+	if (!(sk->userlocks&SOCK_RCVBUF_LOCK))
+		tcp_fixup_rcvbuf(sk);
+	if (!(sk->userlocks&SOCK_SNDBUF_LOCK))
+		tcp_fixup_sndbuf(sk);
+
+	maxwin = tcp_full_space(sk);
+
+	if (tp->window_clamp >= maxwin) {
+		tp->window_clamp = maxwin;
+
+		if (sysctl_tcp_app_win && maxwin>4*tp->advmss)
+			tp->window_clamp = max(maxwin-(maxwin>>sysctl_tcp_app_win), 4*tp->advmss);
+	}
+
+	/* Force reservation of one segment. */
+	if (sysctl_tcp_app_win &&
+	    tp->window_clamp > 2*tp->advmss &&
+	    tp->window_clamp + tp->advmss > maxwin)
+		tp->window_clamp = max(2*tp->advmss, maxwin-tp->advmss);
+
+	tp->rcv_ssthresh = min(tp->rcv_ssthresh, tp->window_clamp);
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+}
+
+/* 5. Recalculate window clamp after socket hit its memory bounds. */
+static void tcp_clamp_window(struct sock *sk, struct tcp_opt *tp)
+{
+	struct sk_buff *skb;
+	int app_win = tp->rcv_nxt - tp->copied_seq;
+	int ofo_win = 0;
+
+	tp->ack.quick = 0;
+
+	skb_queue_walk(&tp->out_of_order_queue, skb) {
+		ofo_win += skb->len;
+	}
+
+	/* If overcommit is due to out of order segments,
+	 * do not clamp window. Try to expand rcvbuf instead.
+	 */
+	if (ofo_win) {
+		if (sk->rcvbuf < sysctl_tcp_rmem[2] &&
+		    !(sk->userlocks&SOCK_RCVBUF_LOCK) &&
+		    !tcp_memory_pressure &&
+		    atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0])
+			sk->rcvbuf = min(atomic_read(&sk->rmem_alloc), sysctl_tcp_rmem[2]);
+	}
+	if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
+		app_win += ofo_win;
+		if (atomic_read(&sk->rmem_alloc) >= 2*sk->rcvbuf)
+			app_win >>= 1;
+		if (app_win > tp->ack.rcv_mss)
+			app_win -= tp->ack.rcv_mss;
+		app_win = max(app_win, 2*tp->advmss);
+
+		if (!ofo_win)
+			tp->window_clamp = min(tp->window_clamp, app_win);
+		tp->rcv_ssthresh = min(tp->window_clamp, 2*tp->advmss);
+	}
+}
+
 /* There is something which you must keep in mind when you analyze the
  * behavior of the tp->ato delayed ack timeout interval.  When a
  * connection starts up, we want to ack as quickly as possible.  The
@@ -173,14 +354,13 @@
  * each ACK we send, he increments snd_cwnd and transmits more of his
  * queue.  -DaveM
  */
-static void tcp_event_data_recv(struct tcp_opt *tp, struct sk_buff *skb)
+static void tcp_event_data_recv(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb)
 {
 	u32 now;
 
-	tcp_measure_rcv_mss(tp, skb);
+	tcp_schedule_ack(tp);
 
-	tp->ack.pending = 1;
-	tp->ack.rcv_segs++;
+	tcp_measure_rcv_mss(tp, skb);
 
 	now = tcp_time_stamp;
 
@@ -188,37 +368,31 @@
 		/* The _first_ data packet received, initialize
 		 * delayed ACK engine.
 		 */
-
-		/* Help sender leave slow start quickly. */
 		tcp_enter_quickack_mode(tp);
-
-		/* Pingpong is off, session is not interactive by default */
-		tp->ack.pingpong = 0;
-
-		/* ATO is minimal */
-		tp->ack.ato = TCP_ATO_MIN;
 	} else {
 		int m = now - tp->ack.lrcvtime;
 
-		if (m > TCP_ATO_MAX/2) {
-			/* Do not touch ATO, if interval is out of bounds.
-			 * It will be deflated by delack timer, if our peer
-			 * really sends too rarely.
+		if (m <= TCP_ATO_MIN/2) {
+			/* The fastest case is the first. */
+			tp->ack.ato = (tp->ack.ato>>1) + TCP_ATO_MIN/2;
+		} else if (m < tp->ack.ato) {
+			tp->ack.ato = (tp->ack.ato>>1) + m;
+			if (tp->ack.ato > tp->rto)
+				tp->ack.ato = tp->rto;
+		} else if (m > tp->rto) {
+			/* Too long gap. Apparently sender falled to
+			 * restart window, so that we send ACKs quickly.
 			 */
-			if (m > tp->rto) {
-				/* Too long gap. Apparently sender falled to
-				 * restart window, so that we send ACKs quickly.
-				 */
-				tcp_enter_quickack_mode(tp);
-			}
-		} else {
-			if (m <= 0)
-				m = TCP_ATO_MIN/2;
-			if (m <= tp->ack.ato)
-				tp->ack.ato = (tp->ack.ato >> 1) + m;
+			tcp_incr_quickack(tp);
+			tcp_mem_reclaim(sk);
 		}
 	}
 	tp->ack.lrcvtime = now;
+
+	TCP_ECN_check_ce(tp, skb);
+
+	if (skb->len >= 128)
+		tcp_grow_window(sk, tp, skb);
 }
 
 /* Called to compute a smoothed rtt estimate. The data fed to this
@@ -230,7 +404,6 @@
  * To save cycles in the RFC 1323 implementation it was better to break
  * it up into three procedures. -- erics
  */
-
 static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
 {
 	long m = mrtt; /* RTT */
@@ -243,6 +416,13 @@
 	 *
 	 *	On a 1990 paper the rto value is changed to:
 	 *	RTO = rtt + 4 * mdev
+	 *
+	 * Funny. This algorithm seems to be very broken.
+	 * These formulae increase RTO, when it should be decreased, increase
+	 * too slowly, when it should be incresed fastly, decrease too fastly
+	 * etc. I guess in BSD RTO takes ONE value, so that it is absolutely
+	 * does not matter how to _calculate_ it. Seems, it was trap
+	 * that VJ failed to avoid. 8)
 	 */
 	if(m == 0)
 		m = 1;
@@ -263,16 +443,27 @@
 /* Calculate rto without backoff.  This is the second half of Van Jacobson's
  * routine referred to above.
  */
-
 static __inline__ void tcp_set_rto(struct tcp_opt *tp)
 {
 	tp->rto = (tp->srtt >> 3) + tp->mdev;
 	/* I am not enough educated to understand this magic.
 	 * However, it smells bad. snd_cwnd>31 is common case.
 	 */
+	/* OK, I found comment in 2.0 source tree, it deserves
+	 * to be reproduced:
+	 * ====
+	 * Note: Jacobson's algorithm is fine on BSD which has a 1/2 second
+	 * granularity clock, but with our 1/100 second granularity clock we
+	 * become too sensitive to minor changes in the round trip time.
+	 * We add in two compensating factors. First we multiply by 5/4.
+	 * For large congestion windows this allows us to tolerate burst
+	 * traffic delaying up to 1/4 of our packets. We also add in
+	 * a rtt / cong_window term. For small congestion windows this allows
+	 * a single packet delay, but has negligible effect
+	 * on the compensation for large windows.
+	 */
 	tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1));
 }
- 
 
 /* Keep the rto between HZ/5 and 120*HZ. 120*HZ is the upper bound
  * on packet lifetime in the internet. We need the HZ/5 lower
@@ -292,11 +483,12 @@
 		tp->rto = TCP_RTO_MAX;
 }
 
+
 /* Save metrics learned by this TCP session.
    This function is called only, when TCP finishes sucessfully
    i.e. when it enters TIME-WAIT or goes from LAST-ACK to CLOSE.
  */
-static void tcp_update_metrics(struct sock *sk)
+void tcp_update_metrics(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct dst_entry *dst = __sk_dst_get(sk);
@@ -344,19 +536,20 @@
 				dst->rttvar -= (dst->rttvar - m)>>2;
 		}
 
-		if (tp->snd_ssthresh == 0x7FFFFFFF) {
+		if (tp->snd_ssthresh >= 0xFFFF) {
 			/* Slow start still did not finish. */
 			if (dst->ssthresh &&
 			    !(dst->mxlock&(1<<RTAX_SSTHRESH)) &&
-			    tp->snd_cwnd > dst->ssthresh)
-				dst->ssthresh = tp->snd_cwnd;
+			    (tp->snd_cwnd>>1) > dst->ssthresh)
+				dst->ssthresh = (tp->snd_cwnd>>1);
 			if (!(dst->mxlock&(1<<RTAX_CWND)) &&
 			    tp->snd_cwnd > dst->cwnd)
 				dst->cwnd = tp->snd_cwnd;
-		} else if (tp->snd_cwnd >= tp->snd_ssthresh && !tp->high_seq) {
+		} else if (tp->snd_cwnd > tp->snd_ssthresh &&
+			   tp->ca_state == TCP_CA_Open) {
 			/* Cong. avoidance phase, cwnd is reliable. */
 			if (!(dst->mxlock&(1<<RTAX_SSTHRESH)))
-				dst->ssthresh = tp->snd_cwnd;
+				dst->ssthresh = max(tp->snd_cwnd>>1, tp->snd_ssthresh);
 			if (!(dst->mxlock&(1<<RTAX_CWND)))
 				dst->cwnd = (dst->cwnd + tp->snd_cwnd)>>1;
 		} else {
@@ -370,9 +563,37 @@
 			    tp->snd_ssthresh > dst->ssthresh)
 				dst->ssthresh = tp->snd_ssthresh;
 		}
+
+		if (!(dst->mxlock&(1<<RTAX_REORDERING))) {
+			if (dst->reordering < tp->reordering &&
+			    tp->reordering != sysctl_tcp_reordering)
+				dst->reordering = tp->reordering;
+		}
 	}
 }
 
+/* Increase initial CWND conservatively: if estimated
+ * RTT is low enough (<20msec) or if we have some preset ssthresh.
+ *
+ * Numbers are taken from RFC1414.
+ */
+__u32 tcp_init_cwnd(struct tcp_opt *tp)
+{
+	__u32 cwnd;
+
+	if (tp->mss_cache > 1460)
+		return 2;
+
+	cwnd = (tp->mss_cache > 1095) ? 3 : 4;
+
+	if (!tp->srtt || (tp->snd_ssthresh >= 0xFFFF && tp->srtt > ((HZ/50)<<3)))
+		cwnd = 2;
+	else if (cwnd > tp->snd_ssthresh)
+		cwnd = tp->snd_ssthresh;
+
+	return min(cwnd, tp->snd_cwnd_clamp);
+}
+
 /* Initialize metrics on socket. */
 
 static void tcp_init_metrics(struct sock *sk)
@@ -392,6 +613,10 @@
 		if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
 			tp->snd_ssthresh = tp->snd_cwnd_clamp;
 	}
+	if (dst->reordering && tp->reordering != dst->reordering) {
+		tp->sack_ok &= ~2;
+		tp->reordering = dst->reordering;
+	}
 
 	if (dst->rtt == 0)
 		goto reset;
@@ -422,9 +647,9 @@
 	if (tp->rto < TCP_TIMEOUT_INIT && !tp->saw_tstamp)
 		goto reset;
 	tp->snd_cwnd = tcp_init_cwnd(tp);
+	tp->snd_cwnd_stamp = tcp_time_stamp;
 	return;
 
-
 reset:
 	/* Play conservative. If timestamps are not
 	 * supported, TCP will fail to recalculate correct
@@ -437,402 +662,967 @@
 	}
 }
 
-/* WARNING: this must not be called if tp->saw_tstamp was false. */
-extern __inline__ void
-tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp, u32 seq)
+static void tcp_update_reordering(struct tcp_opt *tp, int metric, int ts)
 {
-	if (!after(seq, tp->rcv_wup)) {
-		/* PAWS bug workaround wrt. ACK frames, the PAWS discard
-		 * extra check below makes sure this can only happen
-		 * for pure ACK frames.  -DaveM
-		 *
-		 * Not only, also it occurs for expired timestamps
-		 * and RSTs with bad timestamp option. --ANK
-		 */
+	if (metric > tp->reordering) {
+		tp->reordering = min(TCP_MAX_REORDERING, metric);
 
-		if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0 ||
-		   xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS) {
-			tp->ts_recent = tp->rcv_tsval;
-			tp->ts_recent_stamp = xtime.tv_sec;
-		}
+		/* This exciting event is worth to be remembered. 8) */
+		if (ts)
+			NET_INC_STATS_BH(TCPTSReorder);
+		else if (IsReno(tp))
+			NET_INC_STATS_BH(TCPRenoReorder);
+		else if (IsFack(tp))
+			NET_INC_STATS_BH(TCPFACKReorder);
+		else
+			NET_INC_STATS_BH(TCPSACKReorder);
+#if FASTRETRANS_DEBUG > 1
+		printk(KERN_DEBUG "Disorder%d %d %u f%u s%u rr%d\n",
+		       tp->sack_ok, tp->ca_state,
+		       tp->reordering, tp->fackets_out, tp->sacked_out,
+		       tp->undo_marker ? tp->undo_retrans : 0);
+#endif
+		/* Disable FACK yet. */
+		tp->sack_ok &= ~2;
 	}
 }
 
-extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct sk_buff *skb)
-{
-	return ((s32)(tp->rcv_tsval - tp->ts_recent) < 0 &&
-		xtime.tv_sec < tp->ts_recent_stamp + TCP_PAWS_24DAYS
+/* This procedure tags the retransmission queue when SACKs arrive.
+ *
+ * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L).
+ * Packets in queue with these bits set are counted in variables
+ * sacked_out, retrans_out and lost_out, correspondingly.
+ *
+ * Valid combinations are:
+ * Tag  InFlight	Description
+ * 0	1		- orig segment is in flight.
+ * S	0		- nothing flies, orig reached receiver.
+ * L	0		- nothing flies, orig lost by net.
+ * R	2		- both orig and retransmit are in flight.
+ * L|R	1		- orig is lost, retransmit is in flight.
+ * S|R  1		- orig reached receiver, retrans is still in flight.
+ * (L|S|R is logically valid, it could occur when L|R is sacked,
+ *  but it is equivalent to plain S and code short-curcuits it to S.
+ *  L|S is logically invalid, it would mean -1 packet in flight 8))
+ *
+ * These 6 states form finite state machine, controlled by the following events:
+ * 1. New ACK (+SACK) arrives. (tcp_sacktag_write_queue())
+ * 2. Retransmission. (tcp_retransmit_skb(), tcp_xmit_retransmit_queue())
+ * 3. Loss detection event of one of three flavors:
+ *	A. Scoreboard estimator decided the packet is lost.
+ *	   A'. Reno "three dupacks" marks head of queue lost.
+ *	   A''. Its FACK modfication, head until snd.fack is lost.
+ *	B. SACK arrives sacking data transmitted after never retransmitted
+ *	   hole was sent out.
+ *	C. SACK arrives sacking SND.NXT at the moment, when the
+ *	   segment was retransmitted.
+ * 4. D-SACK added new rule: D-SACK changes any tag to S.
+ *
+ * It is pleasant to note, that state diagram turns out to be commutative,
+ * so that we are allowed not to be bothered by order of our actions,
+ * when multiple events arrive simultaneously. (see the function below).
+ *
+ * Reordering detection.
+ * --------------------
+ * Reordering metric is maximal distance, which a packet can be displaced
+ * in packet stream. With SACKs we can estimate it:
+ *
+ * 1. SACK fills old hole and the corresponding segment was not
+ *    ever retransmitted -> reordering. Alas, we cannot use it
+ *    when segment was retransmitted.
+ * 2. The last flaw is solved with D-SACK. D-SACK arrives
+ *    for retransmitted and already SACKed segment -> reordering..
+ * Both of these heuristics are not used in Loss state, when we cannot
+ * account for retransmits accurately.
+ */
+static int
+tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
+	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
+	int reord = tp->packets_out;
+	int prior_fackets;
+	u32 lost_retrans = 0;
+	int flag = 0;
+	int i;
 
-		 /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
+	if (!tp->sacked_out)
+		tp->fackets_out = 0;
+	prior_fackets = tp->fackets_out;
+
+	for (i=0; i<num_sacks; i++, sp++) {
+		struct sk_buff *skb;
+		__u32 start_seq = ntohl(sp->start_seq);
+		__u32 end_seq = ntohl(sp->end_seq);
+		int fack_count = 0;
+		int dup_sack = 0;
 
-		    I cannot see quitely as all the idea behind PAWS
-		    is destroyed 8)
+		/* Check for D-SACK. */
+		if (i == 0) {
+			u32 ack = TCP_SKB_CB(ack_skb)->ack_seq;
+
+			if (before(start_seq, ack)) {
+				dup_sack = 1;
+				NET_INC_STATS_BH(TCPDSACKRecv);
+			} else if (num_sacks > 1 &&
+				   !after(end_seq, ntohl(sp[1].end_seq)) &&
+				   !before(start_seq, ntohl(sp[1].start_seq))) {
+				dup_sack = 1;
+				NET_INC_STATS_BH(TCPDSACKOfoRecv);
+			}
+
+			/* D-SACK for already forgotten data...
+			 * Do dumb counting. */
+			if (dup_sack &&
+			    !after(end_seq, prior_snd_una) &&
+			    after(end_seq, tp->undo_marker))
+				tp->undo_retrans--;
+
+			/* Eliminate too old ACKs, but take into
+			 * account more or less fresh ones, they can
+			 * contain valid SACK info.
+			 */
+			if (before(ack, prior_snd_una-tp->max_window))
+				return 0;
+		}
 
-		    The problem is only in reordering duplicate ACKs.
-		    Hence, we can check this rare case more carefully.
-
-		    1. Check that it is really duplicate ACK (ack==snd_una)
-		    2. Give it some small "replay" window (~RTO)
-
-		    We do not know units of foreign ts values, but make conservative
-		    assumption that they are >=1ms. It solves problem
-		    noted in Dave's mail to tcpimpl and does not harm PAWS. --ANK
-		  */
-		 && (TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq ||
-		     TCP_SKB_CB(skb)->ack_seq != tp->snd_una ||
-		     !skb->h.th->ack ||
-		     (s32)(tp->ts_recent - tp->rcv_tsval) > (tp->rto*1024)/HZ));
-}
+		/* Event "B" in the comment above. */
+		if (after(end_seq, tp->high_seq))
+			flag |= FLAG_DATA_LOST;
+
+		for_retrans_queue(skb, sk, tp) {
+			u8 sacked = TCP_SKB_CB(skb)->sacked;
+			int in_sack;
 
+			/* The retransmission queue is always in order, so
+			 * we can short-circuit the walk early.
+			 */
+			if(!before(TCP_SKB_CB(skb)->seq, end_seq))
+				break;
 
-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
+			fack_count++;
 
-	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);
-}
+			in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
+				!before(end_seq, TCP_SKB_CB(skb)->end_seq);
 
-/* This functions checks to see if the tcp header is actually acceptable. */
-extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
-{
-#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));
+			/* Account D-SACK for retransmitted packet. */
+			if ((dup_sack && in_sack) &&
+			    (sacked & TCPCB_RETRANS) &&
+			    after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
+				tp->undo_retrans--;
+
+			/* The frame is ACKed. */
+			if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) {
+				if (sacked&TCPCB_RETRANS) {
+					if ((dup_sack && in_sack) &&
+					    (sacked&TCPCB_SACKED_ACKED))
+						reord = min(fack_count, reord);
+				} else {
+					/* If it was in a hole, we detected reordering. */
+					if (fack_count < prior_fackets &&
+					    !(sacked&TCPCB_SACKED_ACKED))
+						reord = min(fack_count, reord);
+				}
 
-	return __tcp_sequence(tp, seq, end_seq);
-}
+				/* Nothing to do; acked frame is about to be dropped. */
+				continue;
+			}
 
-/* When we get a reset we do this. */
-static void tcp_reset(struct sock *sk)
-{
-	/* We want the right error as BSD sees it (and indeed as we do). */
-	switch (sk->state) {
-		case TCP_SYN_SENT:
-			sk->err = ECONNREFUSED;
-			break;
-		case TCP_CLOSE_WAIT:
-			sk->err = EPIPE;
-			break;
-		case TCP_CLOSE:
-			return;
-		default:
-			sk->err = ECONNRESET;
-	}
+			if ((sacked&TCPCB_SACKED_RETRANS) &&
+			    after(end_seq, TCP_SKB_CB(skb)->ack_seq) &&
+			    (!lost_retrans || after(end_seq, lost_retrans)))
+				lost_retrans = end_seq;
 
-	if (!sk->dead)
-		sk->error_report(sk);
+			if (!in_sack)
+				continue;
 
-	tcp_done(sk);
-}
+			if (!(sacked&TCPCB_SACKED_ACKED)) {
+				if (sacked & TCPCB_SACKED_RETRANS) {
+					/* If the segment is not tagged as lost,
+					 * we do not clear RETRANS, believing
+					 * that retransmission is still in flight.
+					 */
+					if (sacked & TCPCB_LOST) {
+						TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
+						tp->lost_out--;
+						tp->retrans_out--;
+					}
+				} else {
+					/* New sack for not retransmitted frame,
+					 * which was in hole. It is reordering.
+					 */
+					if (!(sacked & TCPCB_RETRANS) &&
+					    fack_count < prior_fackets)
+						reord = min(fack_count, reord);
+
+					if (sacked & TCPCB_LOST) {
+						TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+						tp->lost_out--;
+					}
+				}
 
-/* This tags the retransmission queue when SACKs arrive. */
-static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp, int nsacks)
-{
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int i = nsacks;
+				TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
+				flag |= FLAG_DATA_SACKED;
+				tp->sacked_out++;
 
-	while(i--) {
-		struct sk_buff *skb = skb_peek(&sk->write_queue);
-		__u32 start_seq = ntohl(sp->start_seq);
-		__u32 end_seq = ntohl(sp->end_seq);
-		int fack_count = 0;
+				if (fack_count > tp->fackets_out)
+					tp->fackets_out = fack_count;
+			} else {
+				if (dup_sack && (sacked&TCPCB_RETRANS))
+					reord = min(fack_count, reord);
+			}
 
-		while((skb != NULL) &&
-		      (skb != tp->send_head) &&
-		      (skb != (struct sk_buff *)&sk->write_queue)) {
-			/* The retransmission queue is always in order, so
-			 * we can short-circuit the walk early.
+			/* D-SACK. We can detect redundant retransmission
+			 * in S|R and plain R frames and clear it.
+			 * undo_retrans is decreased above, L|R frames
+			 * are accounted above as well.
 			 */
-			if(after(TCP_SKB_CB(skb)->seq, end_seq))
-				break;
+			if (dup_sack &&
+			    (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) {
+				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
+				tp->retrans_out--;
+			}
+		}
+	}
 
-			/* We play conservative, we don't allow SACKS to partially
-			 * tag a sequence space.
-			 */
-			fack_count++;
-			if(!after(start_seq, TCP_SKB_CB(skb)->seq) &&
-			   !before(end_seq, TCP_SKB_CB(skb)->end_seq)) {
-				/* If this was a retransmitted frame, account for it. */
-				if((TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) &&
-				   tp->retrans_out)
-					tp->retrans_out--;
-				TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
+	/* Check for lost retransmit. This superb idea is
+	 * borrowed from "ratehalving". Event "C".
+	 * Later note: FACK people cheated me again 8),
+	 * we have to account for reordering! Ugly,
+	 * but should help.
+	 */
+	if (lost_retrans && tp->ca_state == TCP_CA_Recovery) {
+		struct sk_buff *skb;
 
-				/* RULE: All new SACKs will either decrease retrans_out
-				 *       or advance fackets_out.
-				 */
-				if(fack_count > tp->fackets_out)
-					tp->fackets_out = fack_count;
+		for_retrans_queue(skb, sk, tp) {
+			if (after(TCP_SKB_CB(skb)->seq, lost_retrans))
+				break;
+			if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
+				continue;
+			if ((TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) &&
+			    after(lost_retrans, TCP_SKB_CB(skb)->ack_seq) &&
+			    (IsFack(tp) ||
+			     !before(lost_retrans, TCP_SKB_CB(skb)->ack_seq+tp->reordering*tp->mss_cache))) {
+				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
+				tp->retrans_out--;
+
+				if (!(TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_SACKED_ACKED))) {
+					tp->lost_out++;
+					TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+					flag |= FLAG_DATA_SACKED;
+					NET_INC_STATS_BH(TCPLostRetransmit);
+				}
 			}
-			skb = skb->next;
 		}
-		sp++; /* Move on to the next SACK block. */
 	}
+
+	tp->left_out = tp->sacked_out + tp->lost_out;
+
+	if (reord < tp->fackets_out && tp->ca_state != TCP_CA_Loss)
+		tcp_update_reordering(tp, (tp->fackets_out+1)-reord, 0);
+
+#if FASTRETRANS_DEBUG > 0
+	BUG_TRAP((int)tp->sacked_out >= 0);
+	BUG_TRAP((int)tp->lost_out >= 0);
+	BUG_TRAP((int)tp->retrans_out >= 0);
+	BUG_TRAP((int)tcp_packets_in_flight(tp) >= 0);
+#endif
+	return flag;
 }
 
-/* Look for tcp options. Normally only called on SYN and SYNACK packets.
- * But, this can also be called on packets in the established flow when
- * the fast version below fails.
+void tcp_clear_retrans(struct tcp_opt *tp)
+{
+	tp->left_out = 0;
+	tp->retrans_out = 0;
+
+	tp->fackets_out = 0;
+	tp->sacked_out = 0;
+	tp->lost_out = 0;
+
+	tp->undo_marker = 0;
+	tp->undo_retrans = 0;
+}
+
+/* Enter Loss state. If "how" is not zero, forget all SACK information
+ * and reset tags completely, otherwise preserve SACKs. If receiver
+ * dropped its ofo queue, we will know this due to reneging detection.
  */
-void tcp_parse_options(struct sock *sk, struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
+void tcp_enter_loss(struct sock *sk, int how)
 {
-	unsigned char *ptr;
-	int length=(th->doff*4)-sizeof(struct tcphdr);
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct sk_buff *skb;
+	int cnt = 0;
 
-	ptr = (unsigned char *)(th + 1);
-	tp->saw_tstamp = 0;
+	/* Reduce ssthresh if it has not yet been made inside this window. */
+	if (tp->ca_state <= TCP_CA_Disorder ||
+	    tp->snd_una == tp->high_seq ||
+	    (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
+		tp->prior_ssthresh = tcp_current_ssthresh(tp);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+	}
+	tp->snd_cwnd = 1;
+	tp->snd_cwnd_cnt = 0;
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+
+	tcp_clear_retrans(tp);
+
+	/* Push undo marker, if it was plain RTO and nothing
+	 * was retransmitted. */
+	if (!how)
+		tp->undo_marker = tp->snd_una;
+
+	for_retrans_queue(skb, sk, tp) {
+		cnt++;
+		if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS)
+			tp->undo_marker = 0;
+		TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
+		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) {
+			TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
+			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+			tp->lost_out++;
+		} else {
+			tp->sacked_out++;
+			tp->fackets_out = cnt;
+		}
+	}
+	tp->left_out = tp->sacked_out + tp->lost_out;
 
-	while(length>0) {
-	  	int opcode=*ptr++;
-		int opsize;
+	tp->reordering = min(tp->reordering, sysctl_tcp_reordering);
+	tp->ca_state = TCP_CA_Loss;
+	tp->high_seq = tp->snd_nxt;
+	TCP_ECN_queue_cwr(tp);
+}
 
-		switch (opcode) {
-			case TCPOPT_EOL:
-				return;
-			case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
-				length--;
-				continue;
-			default:
-				opsize=*ptr++;
-				if (opsize < 2) /* "silly options" */
-					return;
-				if (opsize > length)
-					break;	/* don't parse partial options */
-	  			switch(opcode) {
-				case TCPOPT_MSS:
-					if(opsize==TCPOLEN_MSS && th->syn) {
-						u16 in_mss = ntohs(*(__u16 *)ptr);
-						if (in_mss) {
-							if (tp->user_mss && tp->user_mss < in_mss)
-								in_mss = tp->user_mss;
-							tp->mss_clamp = in_mss;
-						}
-					}
-					break;
-				case TCPOPT_WINDOW:
-					if(opsize==TCPOLEN_WINDOW && th->syn)
-						if (!no_fancy && sysctl_tcp_window_scaling) {
-							tp->wscale_ok = 1;
-							tp->snd_wscale = *(__u8 *)ptr;
-							if(tp->snd_wscale > 14) {
-								if(net_ratelimit())
-									printk("tcp_parse_options: Illegal window "
-									       "scaling value %d >14 received.",
-									       tp->snd_wscale);
-								tp->snd_wscale = 14;
-							}
-						}
-					break;
-				case TCPOPT_TIMESTAMP:
-					if(opsize==TCPOLEN_TIMESTAMP) {
-						if (sysctl_tcp_timestamps && !no_fancy) {
-							tp->tstamp_ok = 1;
-							tp->saw_tstamp = 1;
-							tp->rcv_tsval = ntohl(*(__u32 *)ptr);
-							tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4));
-						}
-					}
-					break;
-				case TCPOPT_SACK_PERM:
-					if(opsize==TCPOLEN_SACK_PERM && th->syn) {
-						if (sysctl_tcp_sack && !no_fancy) {
-							tp->sack_ok = 1;
-							tp->num_sacks = 0;
-						}
-					}
-					break;
+static int tcp_check_sack_reneging(struct sock *sk, struct tcp_opt *tp)
+{
+	struct sk_buff *skb;
 
-				case TCPOPT_SACK:
-					if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
-					   sysctl_tcp_sack && (sk != NULL) && !th->syn) {
-						int sack_bytes = opsize - TCPOLEN_SACK_BASE;
+	/* If ACK arrived pointing to a remembered SACK,
+	 * it means that our remembered SACKs do not reflect
+	 * real state of receiver i.e.
+	 * receiver _host_ is heavily congested (or buggy).
+	 * Do processing similar to RTO timeout.
+	 */
+	if ((skb = skb_peek(&sk->write_queue)) != NULL &&
+	    (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
+		NET_INC_STATS_BH(TCPSACKReneging);
+
+		tcp_enter_loss(sk, 1);
+		tp->retransmits++;
+		tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+		tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+		return 1;
+	}
+	return 0;
+}
+
+static inline int tcp_fackets_out(struct tcp_opt *tp)
+{
+	return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out;
+}
 
-						if(!(sack_bytes % TCPOLEN_SACK_PERBLOCK)) {
-							int num_sacks = sack_bytes >> 3;
-							struct tcp_sack_block *sackp;
 
-							sackp = (struct tcp_sack_block *)ptr;
-							tcp_sacktag_write_queue(sk, sackp, num_sacks);
-						}
-					}
-	  			};
-	  			ptr+=opsize-2;
-	  			length-=opsize;
-	  	};
+/* Linux NewReno/SACK/FACK/ECN state machine.
+ * --------------------------------------
+ *
+ * "Open"	Normal state, no dubious events, fast path.
+ * "Disorder"   In all the respects it is "Open",
+ *		but requires a bit more attention. It is entered when
+ *		we see some SACKs or dupacks. It is split of "Open"
+ *		mainly to move some processing from fast path to slow one.
+ * "CWR"	CWND was reduced due to some Congestion Notification event.
+ *		It can be ECN, ICMP source quench, local device congestion.
+ * "Recovery"	CWND was reduced, we are fast-retransmitting.
+ * "Loss"	CWND was reduced due to RTO timeout or SACK reneging.
+ *
+ * tcp_fastretrans_alert() is entered:
+ * - each incoming ACK, if state is not "Open"
+ * - when arrived ACK is unusual, namely:
+ *	* SACK
+ *	* Duplicate ACK.
+ *	* ECN ECE.
+ *
+ * Counting packets in flight is pretty simple.
+ *
+ *	in_flight = packets_out - left_out + retrans_out
+ *
+ *	packets_out is SND.NXT-SND.UNA counted in packets.
+ *
+ *	retrans_out is number of retransmitted segments.
+ *
+ *	left_out is number of segments left network, but not ACKed yet.
+ *
+ *		left_out = sacked_out + lost_out
+ *
+ *     sacked_out: Packets, which arrived to receiver out of order
+ *		   and hence not ACKed. With SACKs this number is simply
+ *		   amount of SACKed data. Even without SACKs
+ *		   it is easy to give pretty reliable estimate of this number,
+ *		   counting duplicate ACKs.
+ *
+ *       lost_out: Packets lost by network. TCP has no explicit
+ *		   "loss notification" feedback from network (for now).
+ *		   It means that this number can be only _guessed_.
+ *		   Actually, it is the heuristics to predict lossage that
+ *		   distinguishes different algorithms.
+ *
+ *	F.e. after RTO, when all the queue is considered as lost,
+ *	lost_out = packets_out and in_flight = retrans_out.
+ *
+ *		Essentially, we have now two algorithms counting
+ *		lost packets.
+ *
+ *		FACK: It is the simplest heuristics. As soon as we decided
+ *		that something is lost, we decide that _all_ not SACKed
+ *		packets until the most forward SACK are lost. I.e.
+ *		lost_out = fackets_out - sacked_out and left_out = fackets_out.
+ *		It is absolutely correct estimate, if network does not reorder
+ *		packets. And it loses any connection to reality when reordering
+ *		takes place. We use FACK by default until reordering
+ *		is suspected on the path to this destination.
+ *
+ *		NewReno: when Recovery is entered, we assume that one segment
+ *		is lost (classic Reno). While we are in Recovery and
+ *		a partial ACK arrives, we assume that one more packet
+ *		is lost (NewReno). This heuristics are the same in NewReno
+ *		and SACK.
+ *
+ *  Imagine, that's all! Forget about all this shamanism about CWND inflation
+ *  deflation etc. CWND is real congestion window, never inflated, changes
+ *  only according to classic VJ rules.
+ *
+ * Really tricky (and requiring careful tuning) part of algorithm
+ * is hidden in functions tcp_time_to_recover() and tcp_xmit_retransmit_queue().
+ * The first determines the moment _when_ we should reduce CWND and,
+ * hence, slow down forward transmission. In fact, it determines the moment
+ * when we decide that hole is caused by loss, rather than by a reorder.
+ *
+ * tcp_xmit_retransmit_queue() decides, _what_ we should retransmit to fill
+ * holes, caused by lost packets.
+ *
+ * And the most logically complicated part of algorithm is undo
+ * heuristics. We detect false retransmits due to both too early
+ * fast retransmit (reordering) and underestimated RTO, analyzing
+ * timestamps and D-SACKs. When we detect that some segments were
+ * retransmitted by mistake and CWND reduction was wrong, we undo
+ * window reduction and abort recovery phase. This logic is hidden
+ * inside several functions named tcp_try_undo_<something>.
+ */
+
+/* This function decides, when we should leave Disordered state
+ * and enter Recovery phase, reducing congestion window.
+ *
+ * Main question: may we further continue forward transmission
+ * with the same cwnd?
+ */
+static int
+tcp_time_to_recover(struct sock *sk, struct tcp_opt *tp)
+{
+	/* Trick#1: The loss is proven. */
+	if (tp->lost_out)
+		return 1;
+
+	/* Not-A-Trick#2 : Classic rule... */
+	if (tcp_fackets_out(tp) > tp->reordering)
+		return 1;
+
+	/* Trick#3: It is still not OK... But will it be useful to delay
+	 * recovery more?
+	 */
+	if (tp->packets_out <= tp->reordering &&
+	    tp->sacked_out >= max(tp->packets_out/2, sysctl_tcp_reordering) &&
+	    !tcp_may_send_now(sk, tp)) {
+		/* We have nothing to send. This connection is limited
+		 * either by receiver window or by application.
+		 */
+		return 1;
 	}
+
+	return 0;
 }
 
-/* Fast parse options. This hopes to only see timestamps.
- * If it is wrong it falls back on tcp_parse_options().
+/* If we receive more dupacks than we expected counting segments
+ * in assumption of absent reordering, interpret this as reordering.
+ * The only another reason could be bug in receiver TCP.
  */
-static __inline__ int tcp_fast_parse_options(struct sock *sk, struct tcphdr *th, struct tcp_opt *tp)
+static void tcp_check_reno_reordering(struct tcp_opt *tp, int addend)
 {
-	/* If we didn't send out any options ignore them all. */
-	if (tp->tcp_header_len == sizeof(struct tcphdr))
-		return 0;
-	if (th->doff == sizeof(struct tcphdr)>>2) {
-		tp->saw_tstamp = 0;
-		return 0;
-	} else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
-		__u32 *ptr = (__u32 *)(th + 1);
-		if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-					     | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
-			tp->saw_tstamp = 1;
-			++ptr;
-			tp->rcv_tsval = ntohl(*ptr);
-			++ptr;
-			tp->rcv_tsecr = ntohl(*ptr);
-			return 1;
+	if (tp->sacked_out + 1 > tp->packets_out) {
+		tp->sacked_out = tp->packets_out ? tp->packets_out - 1 : 0;
+		tcp_update_reordering(tp, tp->packets_out+addend, 0);
+	}
+}
+
+/* Emulate SACKs for SACKless connection: account for a new dupack. */
+
+static void tcp_add_reno_sack(struct tcp_opt *tp)
+{
+	++tp->sacked_out;
+	tcp_check_reno_reordering(tp, 0);
+	tp->left_out = tp->sacked_out + tp->lost_out;
+}
+
+/* Account for ACK, ACKing some data in Reno Recovery phase. */
+
+static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_opt *tp, int acked)
+{
+	if (acked > 0) {
+		/* One ACK eated lost packet. Must eat! */
+		BUG_TRAP(tp->lost_out == 0);
+
+		/* The rest eat duplicate ACKs. */
+		if (acked-1 >= tp->sacked_out)
+			tp->sacked_out = 0;
+		else
+			tp->sacked_out -= acked-1;
+	}
+	tcp_check_reno_reordering(tp, acked);
+	tp->left_out = tp->sacked_out + tp->lost_out;
+}
+
+static inline void tcp_reset_reno_sack(struct tcp_opt *tp)
+{
+	tp->sacked_out = 0;
+	tp->left_out = tp->lost_out;
+}
+
+/* Mark head of queue up as lost. */
+static void
+tcp_mark_head_lost(struct sock *sk, struct tcp_opt *tp, int packets, u32 high_seq)
+{
+	struct sk_buff *skb;
+	int cnt = packets;
+
+	BUG_TRAP(cnt <= tp->packets_out);
+
+	for_retrans_queue(skb, sk, tp) {
+		if (--cnt < 0 || after(TCP_SKB_CB(skb)->end_seq, high_seq))
+			break;
+		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
+			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+			tp->lost_out++;
 		}
 	}
-	tcp_parse_options(sk, th, tp, 0);
-	return 1;
+	tp->left_out = tp->sacked_out + tp->lost_out;
 }
 
-#define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
-#define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
-#define FLAG_DATA_ACKED		0x04 /* This ACK acknowledged new data.		*/
-#define FLAG_RETRANS_DATA_ACKED	0x08 /* "" "" some of which was retransmitted.	*/
-#define FLAG_SYN_ACKED		0x10 /* This ACK acknowledged new data.		*/
+/* Account newly detected lost packet(s) */
+
+static void tcp_update_scoreboard(struct sock *sk, struct tcp_opt *tp)
+{
+	if (IsFack(tp)) {
+		int lost = tp->fackets_out - tp->reordering;
+		if (lost <= 0)
+			lost = 1;
+		tcp_mark_head_lost(sk, tp, lost, tp->high_seq);
+	} else {
+		tcp_mark_head_lost(sk, tp, 1, tp->high_seq);
+	}
+}
+
+/* CWND moderation, preventing bursts due to too big ACKs
+ * in dubious situations.
+ */
+static __inline__ void tcp_moderate_cwnd(struct tcp_opt *tp)
+{
+	tp->snd_cwnd = min(tp->snd_cwnd,
+			   tcp_packets_in_flight(tp)+tcp_max_burst(tp));
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+}
+
+/* Decrease cwnd each second ack. */
+
+static void tcp_cwnd_down(struct tcp_opt *tp)
+{
+	int decr = tp->snd_cwnd_cnt + 1;
+
+	tp->snd_cwnd_cnt = decr&1;
+	decr >>= 1;
+
+	if (decr && tp->snd_cwnd > tp->snd_ssthresh/2)
+		tp->snd_cwnd -= decr;
+
+	tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1);
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+}
+
+/* Nothing was retransmitted or returned timestamp is less
+ * than timestamp of the first retransmission.
+ */
+static __inline__ int tcp_packet_delayed(struct tcp_opt *tp)
+{
+	return !tp->retrans_stamp ||
+		(tp->saw_tstamp &&
+		 (__s32)(tp->rcv_tsecr - tp->retrans_stamp) < 0);
+}
+
+/* Undo procedures. */
+
+#if FASTRETRANS_DEBUG > 1
+static void DBGUNDO(struct sock *sk, struct tcp_opt *tp, const char *msg)
+{
+	printk(KERN_DEBUG "Undo %s %u.%u.%u.%u/%u c%u l%u ss%u/%u p%u\n",
+	       msg,
+	       NIPQUAD(sk->daddr), ntohs(sk->dport),
+	       tp->snd_cwnd, tp->left_out,
+	       tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out);
+}
+#else
+#define DBGUNDO(x...) do { } while (0)
+#endif
+
+static void tcp_undo_cwr(struct tcp_opt *tp, int undo)
+{
+	if (tp->prior_ssthresh) {
+		tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh<<1);
+		if (undo && tp->prior_ssthresh > tp->snd_ssthresh)
+			tp->snd_ssthresh = tp->prior_ssthresh;
+	} else {
+		tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh);
+	}
+	tcp_moderate_cwnd(tp);
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+}
+
+static inline int tcp_may_undo(struct tcp_opt *tp)
+{
+	return tp->undo_marker &&
+		(!tp->undo_retrans || tcp_packet_delayed(tp));
+}
+
+/* People celebrate: "We love our President!" */
+static int tcp_try_undo_recovery(struct sock *sk, struct tcp_opt *tp)
+{
+	if (tcp_may_undo(tp)) {
+		/* Happy end! We did not retransmit anything
+		 * or our original transmission succeeded.
+		 */
+		DBGUNDO(sk, tp, tp->ca_state == TCP_CA_Loss ? "loss" : "retrans");
+		tcp_undo_cwr(tp, 1);
+		if (tp->ca_state == TCP_CA_Loss)
+			NET_INC_STATS_BH(TCPLossUndo);
+		else
+			NET_INC_STATS_BH(TCPFullUndo);
+		tp->undo_marker = 0;
+	}
+	if (tp->snd_una == tp->high_seq && IsReno(tp)) {
+		/* Hold old state until something *above* high_seq
+		 * is ACKed. For Reno it is MUST to prevent false
+		 * fast retransmits (RFC2582). SACK TCP is safe. */
+		tcp_moderate_cwnd(tp);
+		return 1;
+	}
+	tp->ca_state = TCP_CA_Open;
+	return 0;
+}
+
+/* Try to undo cwnd reduction, because D-SACKs acked all retransmitted data */
+static void tcp_try_undo_dsack(struct sock *sk, struct tcp_opt *tp)
+{
+	if (tp->undo_marker && !tp->undo_retrans) {
+		DBGUNDO(sk, tp, "D-SACK");
+		tcp_undo_cwr(tp, 1);
+		tp->undo_marker = 0;
+		NET_INC_STATS_BH(TCPDSACKUndo);
+	}
+}
+
+/* Undo during fast recovery after partial ACK. */
+
+static int tcp_try_undo_partial(struct sock *sk, struct tcp_opt *tp, int acked)
+{
+	/* Partial ACK arrived. Force Hoe's retransmit. */
+	int failed = IsReno(tp) || tp->fackets_out>tp->reordering;
+
+	if (tcp_may_undo(tp)) {
+		/* Plain luck! Hole if filled with delayed
+		 * packet, rather than with a retransmit.
+		 */
+		if (tp->retrans_out == 0)
+			tp->retrans_stamp = 0;
+
+		tcp_update_reordering(tp, tcp_fackets_out(tp)+acked, 1);
+
+		DBGUNDO(sk, tp, "Hoe");
+		tcp_undo_cwr(tp, 0);
+		NET_INC_STATS_BH(TCPPartialUndo);
+
+		/* So... Do not make Hoe's retransmit yet.
+		 * If the first packet was delayed, the rest
+		 * ones are most probably delayed as well.
+		 */
+		failed = 0;
+	}
+	return failed;
+}
+
+/* Undo during loss recovery after partial ACK. */
+static int tcp_try_undo_loss(struct sock *sk, struct tcp_opt *tp)
+{
+	if (tcp_may_undo(tp)) {
+		struct sk_buff *skb;
+		for_retrans_queue(skb, sk, tp) {
+			TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+		}
+		DBGUNDO(sk, tp, "partial loss");
+		tp->lost_out = 0;
+		tp->left_out = tp->sacked_out;
+		tcp_undo_cwr(tp, 1);
+		NET_INC_STATS_BH(TCPLossUndo);
+		tp->retransmits = 0;
+		tp->undo_marker = 0;
+		if (!IsReno(tp)) {
+			tp->ca_state = TCP_CA_Open;
+			tp->backoff = 0;
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static __inline__ void tcp_complete_cwr(struct tcp_opt *tp)
+{
+	tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+}
 
-static __inline__ void clear_fast_retransmit(struct tcp_opt *tp)
+static void tcp_try_to_open(struct sock *sk, struct tcp_opt *tp, int flag)
 {
-	if (tp->dup_acks > 3)
-		tp->snd_cwnd = (tp->snd_ssthresh);
+	tp->left_out = tp->sacked_out;
 
-	tp->dup_acks = 0;
+	if (tp->retrans_out == 0)
+		tp->retrans_stamp = 0;
+
+	if (flag&FLAG_ECE)
+		tcp_enter_cwr(tp);
+
+	if (tp->ca_state != TCP_CA_CWR) {
+		int state = TCP_CA_Open;
+
+		if (tp->left_out ||
+		    tp->retrans_out ||
+		    tp->undo_marker)
+			state = TCP_CA_Disorder;
+
+		if (tp->ca_state != state) {
+			tp->ca_state = state;
+			tp->high_seq = tp->snd_nxt;
+		}
+		tcp_moderate_cwnd(tp);
+	} else {
+		tcp_cwnd_down(tp);
+	}
+}
+
+/* Process an event, which can update packets-in-flight not trivially.
+ * Main goal of this function is to calculate new estimate for left_out,
+ * taking into account both packets sitting in receiver's buffer and
+ * packets lost by network.
+ *
+ * Besides that it does CWND reduction, when packet loss is detected
+ * and changes state of machine.
+ *
+ * It does _not_ decide what to send, it is made in function
+ * tcp_xmit_retransmit_queue().
+ */
+static void
+tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
+		      int prior_packets, int flag)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	int is_dupack = (tp->snd_una == prior_snd_una && !(flag&FLAG_NOT_DUP));
+
+	/* Some technical things:
+	 * 1. Reno does not count dupacks (sacked_out) automatically. */
+	if (!tp->packets_out)
+		tp->sacked_out = 0;
+        /* 2. SACK counts snd_fack in packets inaccurately. */
+	if (tp->sacked_out == 0)
+		tp->fackets_out = 0;
+
+        /* Now state machine starts.
+	 * A. ECE, hence prohibit cwnd undoing, the reduction is required. */
+	if (flag&FLAG_ECE)
+		tp->prior_ssthresh = 0;
+
+	/* B. In all the states check for reneging SACKs. */
+	if (tp->sacked_out && tcp_check_sack_reneging(sk, tp))
+		return;
+
+	/* C. Process data loss notification, provided it is valid. */
+	if ((flag&FLAG_DATA_LOST) &&
+	    before(tp->snd_una, tp->high_seq) &&
+	    tp->ca_state != TCP_CA_Open &&
+	    tp->fackets_out > tp->reordering) {
+		tcp_mark_head_lost(sk, tp, tp->fackets_out-tp->reordering, tp->high_seq);
+		NET_INC_STATS_BH(TCPLoss);
+	}
+
+	/* D. Synchronize left_out to current state. */
+	tp->left_out = tp->sacked_out + tp->lost_out;
+
+	/* E. Check state exit conditions. State can be terminated
+	 *    when high_seq is ACKed. */
+	if (tp->ca_state == TCP_CA_Open) {
+		BUG_TRAP(tp->retrans_out == 0);
+		tp->retrans_stamp = 0;
+	} else if (!before(tp->snd_una, tp->high_seq)) {
+		switch (tp->ca_state) {
+		case TCP_CA_Loss:
+			tp->retransmits = 0;
+			if (tcp_try_undo_recovery(sk, tp))
+				return;
+			tp->backoff = 0;
+			break;
+
+		case TCP_CA_CWR:
+			/* CWR is to be held something *above* high_seq
+			 * is ACKed for CWR bit to reach receiver. */
+			if (tp->snd_una != tp->high_seq) {
+				tcp_complete_cwr(tp);
+				tp->ca_state = TCP_CA_Open;
+			}
+			break;
+
+		case TCP_CA_Disorder:
+			tcp_try_undo_dsack(sk, tp);
+			if (IsReno(tp) || !tp->undo_marker) {
+				tp->undo_marker = 0;
+				tp->ca_state = TCP_CA_Open;
+			}
+			break;
+
+		case TCP_CA_Recovery:
+			if (IsReno(tp))
+				tcp_reset_reno_sack(tp);
+			if (tcp_try_undo_recovery(sk, tp))
+				return;
+			tcp_complete_cwr(tp);
+			break;
+		}
+	}
+
+	/* F. Process state. */
+	switch (tp->ca_state) {
+	case TCP_CA_Recovery:
+		if (prior_snd_una == tp->snd_una) {
+			if (IsReno(tp) && is_dupack)
+				tcp_add_reno_sack(tp);
+		} else {
+			int acked = prior_packets - tp->packets_out;
+			if (IsReno(tp))
+				tcp_remove_reno_sacks(sk, tp, acked);
+			is_dupack = tcp_try_undo_partial(sk, tp, acked);
+		}
+		break;
+	case TCP_CA_Loss:
+		if (flag & FLAG_ACKED)
+			tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+		if (!tcp_try_undo_loss(sk, tp)) {
+			tcp_moderate_cwnd(tp);
+			tcp_xmit_retransmit_queue(sk);
+			return;
+		}
+		if (tp->ca_state != TCP_CA_Open)
+			return;
+		/* Loss is undone; fall through to processing in Open state. */
+	default:
+		if (IsReno(tp)) {
+			if (tp->snd_una != prior_snd_una)
+				tcp_reset_reno_sack(tp);
+			if (is_dupack)
+				tcp_add_reno_sack(tp);
+		}
+
+		if (tp->ca_state == TCP_CA_Disorder)
+			tcp_try_undo_dsack(sk, tp);
+
+		if (!tcp_time_to_recover(sk, tp)) {
+			tcp_try_to_open(sk, tp, flag);
+			return;
+		}
+
+		/* Otherwise enter Recovery state */
+
+		if (IsReno(tp))
+			NET_INC_STATS_BH(TCPRenoRecovery);
+		else
+			NET_INC_STATS_BH(TCPSackRecovery);
+
+		tp->high_seq = tp->snd_nxt;
+		tp->prior_ssthresh = 0;
+		tp->undo_marker = tp->snd_una;
+		tp->undo_retrans = tp->retrans_out;
+
+		if (tp->ca_state < TCP_CA_CWR) {
+			if (!(flag&FLAG_ECE))
+				tp->prior_ssthresh = tcp_current_ssthresh(tp);
+			tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+			TCP_ECN_queue_cwr(tp);
+		}
+
+		tp->snd_cwnd_cnt = 0;
+		tp->ca_state = TCP_CA_Recovery;
+	}
+
+	if (is_dupack)
+		tcp_update_scoreboard(sk, tp);
+	tcp_cwnd_down(tp);
+	tcp_xmit_retransmit_queue(sk);
+}
+
+/* Read draft-ietf-tcplw-high-performance before mucking
+ * with this code. (Superceeds RFC1323)
+ */
+static void tcp_ack_saw_tstamp(struct tcp_opt *tp)
+{
+	__u32 seq_rtt;
+
+	/* RTTM Rule: A TSecr value received in a segment is used to
+	 * update the averaged RTT measurement only if the segment
+	 * acknowledges some new data, i.e., only if it advances the
+	 * left edge of the send window.
+	 *
+	 * See draft-ietf-tcplw-high-performance-00, section 3.3.
+	 * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
+	 */
+	seq_rtt = tcp_time_stamp - tp->rcv_tsecr;
+	tcp_rtt_estimator(tp, seq_rtt);
+	tcp_set_rto(tp);
+	tp->rto <<= tp->backoff;
+	tcp_bound_rto(tp);
 }
 
-/* NOTE: This code assumes that tp->dup_acks gets cleared when a
- * retransmit timer fires.
- */
-static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
+static void tcp_ack_no_tstamp(struct tcp_opt *tp, u32 seq_rtt, int flag)
 {
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-
-	/* Note: If not_dup is set this implies we got a
-	 * data carrying packet or a window update.
-	 * This carries no new information about possible
-	 * lost packets, so we have to ignore it for the purposes
-	 * of counting duplicate acks. Ideally this does not imply we
-	 * should stop our fast retransmit phase, more acks may come
-	 * later without data to help us. Unfortunately this would make
-	 * the code below much more complex. For now if I see such
-	 * a packet I clear the fast retransmit phase.
+	/* We don't have a timestamp. Can only use
+	 * packets that are not retransmitted to determine
+	 * rtt estimates. Also, we must not reset the
+	 * backoff for rto until we get a non-retransmitted
+	 * packet. This allows us to deal with a situation
+	 * where the network delay has increased suddenly.
+	 * I.e. Karn's algorithm. (SIGCOMM '87, p5.)
 	 */
-	if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) {
-		/* This is the standard reno style fast retransmit branch. */
-
-                /* 1. When the third duplicate ack is received, set ssthresh 
-                 * to one half the current congestion window, but no less 
-                 * than two segments. Retransmit the missing segment.
-                 */
-		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
-			tp->dup_acks++;
-			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-				__tcp_enter_cong_avoid(tp);
-				/* ... and account for 3 ACKs, which are
-				 * already received to this time.
-				 */
-                                tp->snd_cwnd += 3;
-
-				if(!tp->fackets_out)
-					tcp_retransmit_skb(sk,
-							   skb_peek(&sk->write_queue));
-				else
-					tcp_fack_retransmit(sk);
-                                tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
-			}
-		} 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
-				 */
-				tcp_fack_retransmit(sk);
-			}
-		}
-	} else if (tp->high_seq != 0) {
-		/* In this branch we deal with clearing the Floyd style
-		 * block on duplicate fast retransmits, and if requested
-		 * we do Hoe style secondary fast retransmits.
-		 */
-		if (!before(ack, tp->high_seq) || (not_dup & FLAG_DATA) != 0) {
-			/* Once we have acked all the packets up to high_seq
-			 * we are done this fast retransmit phase.
-			 * Alternatively data arrived. In this case we
-			 * Have to abort the fast retransmit attempt.
-			 * Note that we do want to accept a window
-			 * update since this is expected with Hoe's algorithm.
-			 */
-			clear_fast_retransmit(tp);
 
-			/* After we have cleared up to high_seq we can
-			 * clear the Floyd style block.
-			 */
-			if (!before(ack, tp->high_seq)) {
-				tp->high_seq = 0;
-				tp->fackets_out = 0;
-			}
-		} else if (tp->dup_acks >= 3) {
-			if (!tp->fackets_out) {
-				/* Hoe Style. We didn't ack the whole
-				 * window. Take this as a cue that
-				 * another packet was lost and retransmit it.
-				 * Don't muck with the congestion window here.
-				 * Note that we have to be careful not to
-				 * act if this was a window update and it
-				 * didn't ack new data, since this does
-				 * not indicate a packet left the system.
-				 * We can test this by just checking
-				 * if ack changed from snd_una, since
-				 * the only way to get here without advancing
-				 * 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_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
-				}
-			} else {
-				/* FACK style, fill any remaining holes in
-				 * receiver's queue.
-				 */
-				tcp_fack_retransmit(sk);
-			}
-		}
+	if (!tp->retransmits && !(flag & FLAG_RETRANS_DATA_ACKED)) {
+		tp->backoff = 0;
+		tcp_rtt_estimator(tp, seq_rtt);
+		tcp_set_rto(tp);
+		tcp_bound_rto(tp);
 	}
 }
 
+static __inline__ void
+tcp_ack_update_rtt(struct tcp_opt *tp, int flag, u32 seq_rtt)
+{
+	if (tp->saw_tstamp)
+		tcp_ack_saw_tstamp(tp);
+	else
+		tcp_ack_no_tstamp(tp, seq_rtt, flag);
+}
+
 /* This is Jacobson's slow start and congestion avoidance. 
  * SIGCOMM '88, p. 328.
  */
@@ -855,31 +1645,38 @@
         }
 }
 
+static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
+{
+	if (tp->packets_out==0) {
+		tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS);
+	} else {
+		struct sk_buff *skb = skb_peek(&sk->write_queue);
+		__u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
+
+		if ((__s32)when <= 0)
+			when = TCP_RTO_MIN;
+		tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, when);
+	}
+}
+
 /* Remove acknowledged frames from the retransmission queue. */
-static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
-			       __u32 *seq, __u32 *seq_rtt)
+static int tcp_clean_rtx_queue(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sk_buff *skb;
 	__u32 now = tcp_time_stamp;
 	int acked = 0;
-
-	/* If we are retransmitting, and this ACK clears up to
-	 * the retransmit head, or further, then clear our state.
-	 */
-	if (tp->retrans_head != NULL &&
-	    !before(ack, TCP_SKB_CB(tp->retrans_head)->end_seq))
-		tp->retrans_head = NULL;
+	__u32 seq_rtt = 0; /* F..g gcc... */
 
 	while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) {
 		struct tcp_skb_cb *scb = TCP_SKB_CB(skb); 
 		__u8 sacked = scb->sacked;
-		
+
 		/* If our packet is before the ack sequence we can
 		 * discard it as it's confirmed to have arrived at
 		 * the other end.
 		 */
-		if (after(scb->end_seq, ack))
+		if (after(scb->end_seq, tp->snd_una))
 			break;
 
 		/* Initial outgoing SYN's get put onto the write_queue
@@ -889,711 +1686,482 @@
 		 * connection startup slow start one packet too
 		 * quickly.  This is severely frowned upon behavior.
 		 */
-		if((sacked & TCPCB_SACKED_RETRANS) && tp->retrans_out)
-			tp->retrans_out--;
 		if(!(scb->flags & TCPCB_FLAG_SYN)) {
 			acked |= FLAG_DATA_ACKED;
-			if(sacked & TCPCB_SACKED_RETRANS)
-				acked |= FLAG_RETRANS_DATA_ACKED;
-			if(tp->fackets_out)
-				tp->fackets_out--;
 		} else {
 			acked |= FLAG_SYN_ACKED;
-			/* This is pure paranoia. */
-			tp->retrans_head = NULL;
 		}
+
+		if (sacked) {
+			if(sacked & TCPCB_RETRANS) {
+				if(sacked & TCPCB_SACKED_RETRANS)
+					tp->retrans_out--;
+				acked |= FLAG_RETRANS_DATA_ACKED;
+			}
+			if(sacked & TCPCB_SACKED_ACKED)
+				tp->sacked_out--;
+			if(sacked & TCPCB_LOST)
+				tp->lost_out--;
+		}
+		if(tp->fackets_out)
+			tp->fackets_out--;
 		tp->packets_out--;
-		*seq = scb->seq;
-		*seq_rtt = now - scb->when;
+		seq_rtt = now - scb->when;
 		__skb_unlink(skb, skb->list);
-		kfree_skb(skb);
+		tcp_free_skb(sk, skb);
+	}
+
+	if (acked&FLAG_ACKED) {
+		tcp_ack_update_rtt(tp, acked, seq_rtt);
+		tcp_ack_packets_out(sk, tp);
+	}
+
+#if FASTRETRANS_DEBUG > 0
+	BUG_TRAP((int)tp->sacked_out >= 0);
+	BUG_TRAP((int)tp->lost_out >= 0);
+	BUG_TRAP((int)tp->retrans_out >= 0);
+	if (tp->packets_out==0 && tp->sack_ok) {
+		if (tp->lost_out) {
+			printk(KERN_DEBUG "Leak l=%u %d\n", tp->lost_out, tp->ca_state);
+			tp->lost_out = 0;
+		}
+		if (tp->sacked_out) {
+			printk(KERN_DEBUG "Leak s=%u %d\n", tp->sacked_out, tp->ca_state);
+			tp->sacked_out = 0;
+		}
+		if (tp->retrans_out) {
+			printk(KERN_DEBUG "Leak r=%u %d\n", tp->retrans_out, tp->ca_state);
+			tp->retrans_out = 0;
+		}
 	}
+#endif
 	return acked;
 }
 
-static void tcp_ack_probe(struct sock *sk, __u32 ack)
+static void tcp_ack_probe(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	
+
 	/* Was it a usable window open? */
 
-	if (tp->send_head != NULL) {
-		if (!after(TCP_SKB_CB(tp->send_head)->end_seq, ack + tp->snd_wnd)) {
-			tp->backoff = 0;
-			tcp_clear_xmit_timer(sk, TCP_TIME_PROBE0);
-			/* If packets_out==0, socket must be waked up by
-			 * subsequent tcp_data_snd_check(). This function is
-			 * not for random using!
-			 */
-		} else if (!tp->packets_out) {
-			tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0,
-					     min(tp->rto << tp->backoff, TCP_RTO_MAX));
-		}
+	if (!after(TCP_SKB_CB(tp->send_head)->end_seq, tp->snd_una + tp->snd_wnd)) {
+		tp->backoff = 0;
+		tcp_clear_xmit_timer(sk, TCP_TIME_PROBE0);
+		/* Socket must be waked up by subsequent tcp_data_snd_check().
+		 * This function is not for random using!
+		 */
+	} else {
+		tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0,
+				     min(tp->rto << tp->backoff, TCP_RTO_MAX));
 	}
 }
 
-/* Should we open up the congestion window? */
-static __inline__ int should_advance_cwnd(struct tcp_opt *tp, int flag)
+static __inline__ int tcp_ack_is_dubious(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;
+	return (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) ||
+		tp->ca_state != TCP_CA_Open);
+}
 
-		/* Non-FACK fast retransmit does it's own
-		 * congestion window management, don't get
-		 * in the way.
-		 */
-		return 0;
-	}
+static __inline__ int tcp_may_raise_cwnd(struct tcp_opt *tp, int flag)
+{
+	return (!(flag & FLAG_ECE) || tp->snd_cwnd < tp->snd_ssthresh) &&
+		!((1<<tp->ca_state)&(TCPF_CA_Recovery|TCPF_CA_CWR));
+}
 
-	/* New non-retransmitted data acked, always advance.  */
-	return 1;
+/* Check that window update is acceptable.
+ * The function assumes that snd_una<=ack<=snd_next.
+ */
+static __inline__ int
+tcp_may_update_window(struct tcp_opt *tp, u32 ack, u32 ack_seq, u32 nwin)
+{
+	return (after(ack, tp->snd_una) ||
+		after(ack_seq, tp->snd_wl1) ||
+		(ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd));
 }
 
-/* Read draft-ietf-tcplw-high-performance before mucking
- * with this code. (Superceeds RFC1323)
+/* Update our send window.
+ *
+ * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
+ * and in FreeBSD. NetBSD's one is even worse.) is wrong.
  */
-static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
-			       u32 seq, u32 ack, int flag)
+static int tcp_ack_update_window(struct sock *sk, struct tcp_opt *tp,
+				 struct sk_buff *skb, u32 ack, u32 ack_seq)
 {
-	__u32 seq_rtt;
+	int flag = 0;
+	u32 nwin = ntohs(skb->h.th->window) << tp->snd_wscale;
 
-	/* RTTM Rule: A TSecr value received in a segment is used to
-	 * update the averaged RTT measurement only if the segment
-	 * acknowledges some new data, i.e., only if it advances the
-	 * left edge of the send window.
-	 *
-	 * See draft-ietf-tcplw-high-performance-00, section 3.3.
-	 * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
-	 */
-	if (!(flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED)))
-		return;
+	if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
+		flag |= FLAG_WIN_UPDATE;
+		tcp_update_wl(tp, ack, ack_seq);
 
-	seq_rtt = tcp_time_stamp - tp->rcv_tsecr;
-	tcp_rtt_estimator(tp, seq_rtt);
-	if (tp->retransmits) {
-		if (tp->packets_out == 0) {
-			tp->retransmits = 0;
-			tp->fackets_out = 0;
-			tp->retrans_out = 0;
-			tp->backoff = 0;
-			tcp_set_rto(tp);
-		} else {
-			/* Still retransmitting, use backoff */
-			tcp_set_rto(tp);
-			tp->rto = tp->rto << tp->backoff;
+		if (tp->snd_wnd != nwin) {
+			tp->snd_wnd = nwin;
+
+			/* Note, it is the only place, where
+			 * fast path is recovered for sending TCP.
+			 */
+			if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
+#ifdef TCP_FORMAL_WINDOW
+			    tcp_receive_window(tp) &&
+#endif
+			    !tp->urg_data)
+				tcp_fast_path_on(tp);
+
+			if (nwin > tp->max_window) {
+				tp->max_window = nwin;
+				tcp_sync_mss(sk, tp->pmtu_cookie);
+			}
 		}
-	} else {
-		tcp_set_rto(tp);
 	}
 
-	tcp_bound_rto(tp);
-}
-
-static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
-{
-	struct sk_buff *skb = skb_peek(&sk->write_queue);
+	tp->snd_una = ack;
 
 #ifdef TCP_DEBUG
-	/* It occured in 2.3, because of racy timers. Namely,
-	 * retransmit timer did not check packets_out and retransmitted
-	 * send_head sometimes and, hence, messed all the write_queue.
-	 * Now it is impossible, I bet. --ANK
-	 */
-	if (skb == NULL) {
-		printk("Sucks! packets_out=%d, sk=%p, %d\n", tp->packets_out, sk, sk->state);
-		return;
+	if (before(tp->snd_una + tp->snd_wnd, tp->snd_nxt)) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "TCP: peer shrinks window. Bad, what else can I say?\n");
 	}
 #endif
 
-	/* Some data was ACK'd, if still retransmitting (due to a
-	 * timeout), resend more of the retransmit queue.  The
-	 * congestion window is handled properly by that code.
-	 */
-	if (tp->retransmits) {
-		tcp_xmit_retransmit_queue(sk);
-		tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
-	} else {
-		__u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
-		if ((__s32)when < 0)
-			when = 1;
-		tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, when);
-	}
+	return flag;
 }
 
 /* This routine deals with incoming acks, but not outgoing ones. */
-static int tcp_ack(struct sock *sk, struct tcphdr *th, 
-		   u32 ack_seq, u32 ack, int len)
+static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int flag = 0;
-	u32 seq = 0;
-	u32 seq_rtt = 0;
-
-	if(sk->state == TCP_CLOSE)
-		return 1;	/* Dead, can't ack any more so why bother */
+	u32 prior_snd_una = tp->snd_una;
+	u32 ack_seq = TCP_SKB_CB(skb)->seq;
+	u32 ack = TCP_SKB_CB(skb)->ack_seq;
+	u32 prior_in_flight;
+	int prior_packets;
 
 	/* If the ack is newer than sent or older than previous acks
 	 * then we can probably ignore it.
 	 */
-	if (after(ack, tp->snd_nxt) || before(ack, tp->snd_una))
+	if (after(ack, tp->snd_nxt))
 		goto uninteresting_ack;
 
-	/* If there is data set flag 1 */
-	if (len != th->doff*4)
-		flag |= FLAG_DATA;
-
-	/* Update our send window. */
-
-	/* This is the window update code as per RFC 793
-	 * snd_wl{1,2} are used to prevent unordered
-	 * segments from shrinking the window 
-	 */
-	if (before(tp->snd_wl1, ack_seq) ||
-	    (tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) {
-		u32 nwin = ntohs(th->window) << tp->snd_wscale;
-
-		if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) {
-			flag |= FLAG_WIN_UPDATE;
-			if (tp->snd_wnd != nwin) {
-				tp->snd_wnd = nwin;
+	if (before(ack, prior_snd_una))
+		goto old_ack;
 
-				/* Note, it is the only place, where
-				 * fast path is recovered for sending TCP.
-				 */
-				if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
-#ifdef TCP_FORMAL_WINDOW
-				    tcp_receive_window(tp) &&
-#endif
-				    !tp->urg_data)
-					tcp_fast_path_on(tp);
+	if (!(flag&FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
+		/* Window is constant, pure forward advance.
+		 * No more checks are required.
+		 * Note, we use the fact that SND.UNA>=SND.WL2.
+		 */
+		tcp_update_wl(tp, ack, ack_seq);
+		tp->snd_una = ack;
+		flag |= FLAG_WIN_UPDATE;
 
-				if (nwin > tp->max_window) {
-					tp->max_window = nwin;
-					tcp_sync_mss(sk, tp->pmtu_cookie);
-				}
-			}
+		NET_INC_STATS_BH(TCPHPAcks);
+	} else {
+		if (ack_seq != TCP_SKB_CB(skb)->end_seq)
+			flag |= FLAG_DATA;
+		else
+			NET_INC_STATS_BH(TCPPureAcks);
 
-			tp->snd_wl1 = ack_seq;
-			tp->snd_wl2 = ack;
-		}
-	}
+		flag |= tcp_ack_update_window(sk, tp, skb, ack, ack_seq);
 
-	/* BEWARE! From this place and until return from this function
-	 * snd_nxt and snd_wnd are out of sync. All the routines, called
-	 * from here must get "ack" as argument or they should not depend
-	 * on right edge of window. It is _UGLY_. It cries to be fixed. --ANK
-	 */
+		if (TCP_SKB_CB(skb)->sacked)
+			flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
+
+		if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th))
+			flag |= FLAG_ECE;
+	}
 
 	/* We passed data and got it acked, remove any soft error
 	 * log. Something worked...
 	 */
 	sk->err_soft = 0;
-	tp->probes_out = 0;
 	tp->rcv_tstamp = tcp_time_stamp;
+	if ((prior_packets = tp->packets_out) == 0)
+		goto no_queue;
 
-	/* See if we can take anything off of the retransmit queue. */
-	flag |= tcp_clean_rtx_queue(sk, ack, &seq, &seq_rtt);
-
-	/* If this ack opens up a zero window, clear backoff.  It was
-	 * being used to time the probes, and is probably far higher than
-	 * it needs to be for normal retransmission.
-	 */
-	if (tcp_timer_is_set(sk, TCP_TIME_PROBE0))
-		tcp_ack_probe(sk, ack);
-
-	/* We must do this here, before code below clears out important
-	 * state contained in tp->fackets_out and tp->retransmits.  -DaveM
-	 */
-	if (should_advance_cwnd(tp, flag))
-		tcp_cong_avoid(tp);
+	prior_in_flight = tcp_packets_in_flight(tp);
 
-	/* If we have a timestamp, we always do rtt estimates. */
-	if (tp->saw_tstamp) {
-		tcp_ack_saw_tstamp(sk, tp, seq, ack, flag);
-	} else {
-		/* If we were retransmiting don't count rtt estimate. */
-		if (tp->retransmits) {
-			if (tp->packets_out == 0) {
-				tp->retransmits = 0;
-				tp->fackets_out = 0;
-				tp->retrans_out = 0;
-			}
-		} else {
-			/* We don't have a timestamp. Can only use
-			 * packets that are not retransmitted to determine
-			 * rtt estimates. Also, we must not reset the
-			 * backoff for rto until we get a non-retransmitted
-			 * packet. This allows us to deal with a situation
-			 * where the network delay has increased suddenly.
-			 * I.e. Karn's algorithm. (SIGCOMM '87, p5.)
-			 */
-			if (flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED)) {
-				if(!(flag & FLAG_RETRANS_DATA_ACKED)) {
-					tp->backoff = 0;
-					tcp_rtt_estimator(tp, seq_rtt);
-					tcp_set_rto(tp);
-					tcp_bound_rto(tp);
-				}
-			}
-		}
-	}
+	/* See if we can take anything off of the retransmit queue. */
+	flag |= tcp_clean_rtx_queue(sk);
 
-	if (tp->packets_out) {
-		if (flag & FLAG_DATA_ACKED)
-			tcp_ack_packets_out(sk, tp);
+	if (tcp_ack_is_dubious(tp, flag)) {
+		/* Advanve CWND, if state allows this. */
+		if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd &&
+		    tcp_may_raise_cwnd(tp, flag))
+			tcp_cong_avoid(tp);
+		tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
 	} else {
-		tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS);
+		if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd)
+			tcp_cong_avoid(tp);
 	}
 
-	flag &= (FLAG_DATA | FLAG_WIN_UPDATE);
-	if ((ack == tp->snd_una	&& tp->packets_out && flag == 0) ||
-	    (tp->high_seq != 0)) {
-		tcp_fast_retrans(sk, ack, flag);
-	} else {
-		/* Clear any aborted fast retransmit starts. */
-		tp->dup_acks = 0;
-	}
-	/* It is not a brain fart, I thought a bit now. 8)
-	 *
-	 * Forward progress is indicated, if:
-	 *   1. the ack acknowledges new data.
-	 *   2. or the ack is duplicate, but it is caused by new segment
-	 *      arrival. This case is filtered by:
-	 *      - it contains no data, syn or fin.
-	 *      - it does not update window.
-	 *   3. or new SACK. It is difficult to check, so that we ignore it.
-	 *
-	 * Forward progress is also indicated by arrival new data,
-	 * which was caused by window open from our side. This case is more
-	 * difficult and it is made (alas, incorrectly) in tcp_data_queue().
-	 *                                              --ANK (990513)
-	 */
-	if (ack != tp->snd_una || (flag == 0 && !th->fin))
+	if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
 		dst_confirm(sk->dst_cache);
 
-	if (ack != tp->snd_una)
-		tp->sorry = 1;
+	return 1;
+
+no_queue:
+	tp->probes_out = 0;
 
-	/* Remember the highest ack received. */
-	tp->snd_una = ack;
+	/* If this ack opens up a zero window, clear backoff.  It was
+	 * being used to time the probes, and is probably far higher than
+	 * it needs to be for normal retransmission.
+	 */
+	if (tp->send_head)
+		tcp_ack_probe(sk);
 	return 1;
 
+old_ack:
+	if (TCP_SKB_CB(skb)->sacked)
+		tcp_sacktag_write_queue(sk, skb, prior_snd_una);
+
 uninteresting_ack:
-	SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
+	SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
 	return 0;
 }
 
-int tcp_paws_check(struct tcp_opt *tp, int rst)
-{
-	if ((s32)(tp->rcv_tsval - tp->ts_recent) >= 0)
-		return 0;
-	if (xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS)
-		return 0;
-
-	/* RST segments are not recommended to carry timestamp,
-	   and, if they do, it is recommended to ignore PAWS because
-	   "their cleanup function should take precedence over timestamps."
-	   Certainly, it is mistake. It is necessary to understand the reasons
-	   of this constraint to relax it: if peer reboots, clock may go
-	   out-of-sync and half-open connections will not be reset.
-	   Actually, the problem would be not existing if all
-	   the implementations followed draft about maintaining clock
-	   via reboots. Linux-2.2 DOES NOT!
 
-	   However, we can relax time bounds for RST segments to MSL.
-	 */
-	if (rst && xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_MSL)
-		return 0;
-	return 1;
-}
-
-static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
+/* Look for tcp options. Normally only called on SYN and SYNACK packets.
+ * But, this can also be called on packets in the established flow when
+ * the fast version below fails.
+ */
+void tcp_parse_options(struct sk_buff *skb, struct tcp_opt *tp)
 {
-	if (seq == s_win)
-		return 1;
-	if (after(end_seq, s_win) && before(seq, e_win))
-		return 1;
-	return (seq == e_win && seq == end_seq);
-}
+	unsigned char *ptr;
+	struct tcphdr *th = skb->h.th;
+	int length=(th->doff*4)-sizeof(struct tcphdr);
+
+	ptr = (unsigned char *)(th + 1);
+	tp->saw_tstamp = 0;
 
-/* New-style handling of TIME_WAIT sockets. */
+	while(length>0) {
+	  	int opcode=*ptr++;
+		int opsize;
 
-/* Must be called with locally disabled BHs. */
-void tcp_timewait_kill(struct tcp_tw_bucket *tw)
-{
-	struct tcp_ehash_bucket *ehead;
-	struct tcp_bind_hashbucket *bhead;
-	struct tcp_bind_bucket *tb;
+		switch (opcode) {
+			case TCPOPT_EOL:
+				return;
+			case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
+				length--;
+				continue;
+			default:
+				opsize=*ptr++;
+				if (opsize < 2) /* "silly options" */
+					return;
+				if (opsize > length)
+					break;	/* don't parse partial options */
+	  			switch(opcode) {
+				case TCPOPT_MSS:
+					if(opsize==TCPOLEN_MSS && th->syn) {
+						u16 in_mss = ntohs(*(__u16 *)ptr);
+						if (in_mss) {
+							if (tp->user_mss && tp->user_mss < in_mss)
+								in_mss = tp->user_mss;
+							tp->mss_clamp = in_mss;
+						}
+					}
+					break;
+				case TCPOPT_WINDOW:
+					if(opsize==TCPOLEN_WINDOW && th->syn)
+						if (sysctl_tcp_window_scaling) {
+							tp->wscale_ok = 1;
+							tp->snd_wscale = *(__u8 *)ptr;
+							if(tp->snd_wscale > 14) {
+								if(net_ratelimit())
+									printk("tcp_parse_options: Illegal window "
+									       "scaling value %d >14 received.",
+									       tp->snd_wscale);
+								tp->snd_wscale = 14;
+							}
+						}
+					break;
+				case TCPOPT_TIMESTAMP:
+					if(opsize==TCPOLEN_TIMESTAMP) {
+						if (sysctl_tcp_timestamps) {
+							tp->tstamp_ok = 1;
+							tp->saw_tstamp = 1;
+							tp->rcv_tsval = ntohl(*(__u32 *)ptr);
+							tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4));
+						}
+					}
+					break;
+				case TCPOPT_SACK_PERM:
+					if(opsize==TCPOLEN_SACK_PERM && th->syn) {
+						if (sysctl_tcp_sack) {
+							tp->sack_ok = 1;
+							tcp_sack_reset(tp);
+						}
+					}
+					break;
 
-	/* Unlink from established hashes. */
-	ehead = &tcp_ehash[tw->hashent];
-	write_lock(&ehead->lock);
-	if (!tw->pprev) {
-		write_unlock(&ehead->lock);
-		return;
-	}
-	if(tw->next)
-		tw->next->pprev = tw->pprev;
-	*(tw->pprev) = tw->next;
-	tw->pprev = NULL;
-	write_unlock(&ehead->lock);
-
-	/* Disassociate with bind bucket. */
-	bhead = &tcp_bhash[tcp_bhashfn(tw->num)];
-	spin_lock(&bhead->lock);
-	if ((tb = tw->tb) != NULL) {
-		if(tw->bind_next)
-			tw->bind_next->bind_pprev = tw->bind_pprev;
-		*(tw->bind_pprev) = tw->bind_next;
-		tw->tb = NULL;
-		if (tb->owners == NULL) {
-			if (tb->next)
-				tb->next->pprev = tb->pprev;
-			*(tb->pprev) = tb->next;
-			kmem_cache_free(tcp_bucket_cachep, tb);
-		}
-	}
-	spin_unlock(&bhead->lock);
-
-#ifdef INET_REFCNT_DEBUG
-	if (atomic_read(&tw->refcnt) != 1) {
-		printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, atomic_read(&tw->refcnt));
+				case TCPOPT_SACK:
+					if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
+					   !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) &&
+					   tp->sack_ok) {
+						TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th;
+					}
+	  			};
+	  			ptr+=opsize-2;
+	  			length-=opsize;
+	  	};
 	}
-#endif
-	tcp_tw_put(tw);
 }
 
-/* 
- * * Main purpose of TIME-WAIT state is to close connection gracefully,
- *   when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
- *   (and, probably, tail of data) and one or more our ACKs are lost.
- * * What is TIME-WAIT timeout? It is associated with maximal packet
- *   lifetime in the internet, which results in wrong conclusion, that
- *   it is set to catch "old duplicate segments" wandering out of their path.
- *   It is not quite correct. This timeout is calculated so that it exceeds
- *   maximal retransmision timeout enough to allow to lose one (or more)
- *   segments sent by peer and our ACKs. This time may be calculated from RTO.
- * * When TIME-WAIT socket receives RST, it means that another end
- *   finally closed and we are allowed to kill TIME-WAIT too.
- * * Second purpose of TIME-WAIT is catching old duplicate segments.
- *   Well, certainly it is pure paranoia, but if we load TIME-WAIT
- *   with this semantics, we MUST NOT kill TIME-WAIT state with RSTs.
- * * If we invented some more clever way to catch duplicates
- *   (f.e. based on PAWS), we could truncate TIME-WAIT to several RTOs.
- *
- * The algorithm below is based on FORMAL INTERPRETATION of RFCs.
- * When you compare it to RFCs, please, read section SEGMENT ARRIVES
- * from the very beginning.
- *
- * NOTE. With recycling (and later with fin-wait-2) TW bucket
- * is _not_ stateless. It means, that strictly speaking we must
- * spinlock it. I do not want! Well, probability of misbehaviour
- * is ridiculously low and, seems, we could use some mb() tricks
- * to avoid misread sequence numbers, states etc.  --ANK
- */
-enum tcp_tw_status
-tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
-			   struct tcphdr *th, unsigned len)
-{
-	struct tcp_opt tp;
-	int paws_reject = 0;
-
-	tp.saw_tstamp = 0;
-	if (th->doff > (sizeof(struct tcphdr)>>2) && tw->ts_recent_stamp) {
-		tcp_parse_options(NULL, th, &tp, 0);
-
-		if (tp.saw_tstamp) {
-			tp.ts_recent = tw->ts_recent;
-			tp.ts_recent_stamp = tw->ts_recent_stamp;
-			paws_reject = tcp_paws_check(&tp, th->rst);
-		}
-	}
-
-	if (tw->substate == TCP_FIN_WAIT2) {
-		/* Just repeat all the checks of tcp_rcv_state_process() */
-
-		/* Out of window, send ACK */
-		if (paws_reject ||
-		    !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-				   tw->rcv_nxt, tw->rcv_nxt + tw->rcv_wnd))
-			return TCP_TW_ACK;
-
-		if (th->rst)
-			goto kill;
-
-		if (th->syn && TCP_SKB_CB(skb)->seq != tw->syn_seq)
-			goto kill_with_rst;
-
-		/* Dup ACK? */
-		if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) ||
-		    TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) {
-			tcp_tw_put(tw);
-			return TCP_TW_SUCCESS;
-		}
-
-		/* New data or FIN. If new data arrive after half-duplex close,
-		 * reset.
-		 */
-		if (!th->fin || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) {
-kill_with_rst:
-			tcp_tw_deschedule(tw);
-			tcp_timewait_kill(tw);
-			tcp_tw_put(tw);
-			return TCP_TW_RST;
-		}
-
-		/* FIN arrived, enter true time-wait state. */
-		tw->substate = TCP_TIME_WAIT;
-		tw->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
-		if (tp.saw_tstamp) {
-			tw->ts_recent_stamp = xtime.tv_sec;
-			tw->ts_recent = tp.rcv_tsval;
-		}
-
-		/* I am shamed, but failed to make it more elegant.
-		 * Yes, it is direct reference to IP, which is impossible
-		 * to generalize to IPv6. Taking into account that IPv6
-		 * do not undertsnad recycling in any case, it not
-		 * a big problem in practice. --ANK */
-		if (tw->family == AF_INET &&
-		    sysctl_tcp_tw_recycle && tw->ts_recent_stamp &&
-		    tcp_v4_tw_remember_stamp(tw))
-			tcp_tw_schedule(tw, tw->timeout);
-		else
-			tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
-		return TCP_TW_ACK;
-	}
-
-	/*
-	 *	Now real TIME-WAIT state.
-	 *
-	 *	RFC 1122:
-	 *	"When a connection is [...] on TIME-WAIT state [...]
-	 *	[a TCP] MAY accept a new SYN from the remote TCP to
-	 *	reopen the connection directly, if it:
-	 *	
-	 *	(1)  assigns its initial sequence number for the new
-	 *	connection to be larger than the largest sequence
-	 *	number it used on the previous connection incarnation,
-	 *	and
-	 *
-	 *	(2)  returns to TIME-WAIT state if the SYN turns out 
-	 *	to be an old duplicate".
-	 */
-
-	if (!paws_reject &&
-	    (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq &&
-	     TCP_SKB_CB(skb)->seq == tw->rcv_nxt)) {
-		/* In window segment, it may be only reset or bare ack. */
-
-		if (th->rst) {
-			/* This is TIME_WAIT assasination, in two flavors.
-			 * Oh well... nobody has a sufficient solution to this
-			 * protocol bug yet.
-			 */
-			if (sysctl_tcp_rfc1337 == 0) {
-kill:
-				tcp_tw_deschedule(tw);
-				tcp_timewait_kill(tw);
-				tcp_tw_put(tw);
-				return TCP_TW_SUCCESS;
-			}
-		}
-		tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
-
-		if (tp.saw_tstamp) {
-			tw->ts_recent = tp.rcv_tsval;
-			tw->ts_recent_stamp = xtime.tv_sec;
+/* Fast parse options. This hopes to only see timestamps.
+ * If it is wrong it falls back on tcp_parse_options().
+ */
+static __inline__ int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, struct tcp_opt *tp)
+{
+	if (th->doff == sizeof(struct tcphdr)>>2) {
+		tp->saw_tstamp = 0;
+		return 0;
+	} else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
+		__u32 *ptr = (__u32 *)(th + 1);
+		if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+					     | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+			tp->saw_tstamp = 1;
+			++ptr;
+			tp->rcv_tsval = ntohl(*ptr);
+			++ptr;
+			tp->rcv_tsecr = ntohl(*ptr);
+			return 1;
 		}
-
-		tcp_tw_put(tw);
-		return TCP_TW_SUCCESS;
-	}
-
-	/* Out of window segment.
-
-	   All the segments are ACKed immediately.
-
-	   The only exception is new SYN. We accept it, if it is
-	   not old duplicate and we are not in danger to be killed
-	   by delayed old duplicates. RFC check is that it has
-	   newer sequence number works at rates <40Mbit/sec.
-	   However, if paws works, it is reliable AND even more,
-	   we even may relax silly seq space cutoff.
-
-	   RED-PEN: we violate main RFC requirement, if this SYN will appear
-	   old duplicate (i.e. we receive RST in reply to SYN-ACK),
-	   we must return socket to time-wait state. It is not good,
-	   but not fatal yet.
-	 */
-
-	if (th->syn && !th->rst && !th->ack && !paws_reject &&
-	    (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) ||
-	     (tp.saw_tstamp && (s32)(tw->ts_recent - tp.rcv_tsval) < 0))) {
-		u32 isn = tw->snd_nxt + 2;
-		if (isn == 0)
-			isn++;
-		TCP_SKB_CB(skb)->when = isn;
-		return TCP_TW_SYN;
 	}
+	tcp_parse_options(skb, tp);
+	return 1;
+}
 
-	if (paws_reject)
-		NET_INC_STATS_BH(PAWSEstabRejected);
+extern __inline__ void
+tcp_store_ts_recent(struct tcp_opt *tp)
+{
+	tp->ts_recent = tp->rcv_tsval;
+	tp->ts_recent_stamp = xtime.tv_sec;
+}
 
-	if(!th->rst) {
-		/* In this case we must reset the TIMEWAIT timer.
+extern __inline__ void
+tcp_replace_ts_recent(struct tcp_opt *tp, u32 seq)
+{
+	if (tp->saw_tstamp && !after(seq, tp->rcv_wup)) {
+		/* PAWS bug workaround wrt. ACK frames, the PAWS discard
+		 * extra check below makes sure this can only happen
+		 * for pure ACK frames.  -DaveM
 		 *
-		 * If it is ACKless SYN it may be both old duplicate
-		 * and new good SYN with random sequence number <rcv_nxt.
-		 * Do not reschedule in the last case.
+		 * Not only, also it occurs for expired timestamps.
 		 */
-		if (paws_reject || th->ack)
-			tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
 
-		/* Send ACK. Note, we do not put the bucket,
-		 * it will be released by caller.
-		 */
-		return TCP_TW_ACK;
+		if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0 ||
+		   xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS)
+			tcp_store_ts_recent(tp);
 	}
-	tcp_tw_put(tw);
-	return TCP_TW_SUCCESS;
 }
 
-/* Enter the time wait state.  This is called with locally disabled BH.
- * Essentially we whip up a timewait bucket, copy the
- * relevant info into it from the SK, and mess with hash chains
- * and list linkage.
+/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
+ *
+ * It is not fatal. If this ACK does _not_ change critical state (seqs, window)
+ * it can pass through stack. So, the following predicate verifies that
+ * this segment is not used for anything but congestion avoidance or
+ * fast retransmit. Moreover, we even are able to eliminate most of such
+ * second order effects, if we apply some small "replay" window (~RTO)
+ * to timestamp space.
+ *
+ * All these measures still do not guarantee that we reject wrapped ACKs
+ * on networks with high bandwidth, when sequence space is recycled fastly,
+ * but it guarantees that such events will be very rare and do not affect
+ * connection seriously. This doesn't look nice, but alas, PAWS is really
+ * buggy extension.
+ *
+ * [ Later note. Even worse! It is buggy for segments _with_ data. RFC
+ * states that events when retransmit arrives after original data are rare.
+ * It is a blatant lie. VJ forgot about fast retransmit! 8)8) It is
+ * the biggest problem on large power networks even with minor reordering.
+ * OK, let's give it small replay window. If peer clock is even 1hz, it is safe
+ * up to bandwidth of 18Gigabit/sec. 8) ]
  */
-static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
+
+static int tcp_disordered_ack(struct tcp_opt *tp, struct sk_buff *skb)
 {
-	struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->hashent];
-	struct tcp_bind_hashbucket *bhead;
-	struct sock **head, *sktw;
+	struct tcphdr *th = skb->h.th;
+	u32 seq = TCP_SKB_CB(skb)->seq;
+	u32 ack = TCP_SKB_CB(skb)->ack_seq;
 
-	write_lock(&ehead->lock);
+	return (/* 1. Pure ACK with correct sequence number. */
+		(th->ack && seq == TCP_SKB_CB(skb)->end_seq && seq == tp->rcv_nxt) &&
 
-	/* Step 1: Remove SK from established hash. */
-	if (sk->pprev) {
-		if(sk->next)
-			sk->next->pprev = sk->pprev;
-		*sk->pprev = sk->next;
-		sk->pprev = NULL;
-		sock_prot_dec_use(sk->prot);
-	}
+		/* 2. ... and duplicate ACK. */
+		ack == tp->snd_una &&
 
-	/* Step 2: Hash TW into TIMEWAIT half of established hash table. */
-	head = &(ehead + tcp_ehash_size)->chain;
-	sktw = (struct sock *)tw;
-	if((sktw->next = *head) != NULL)
-		(*head)->pprev = &sktw->next;
-	*head = sktw;
-	sktw->pprev = head;
-	atomic_inc(&tw->refcnt);
+		/* 3. ... and does not update window. */
+		!tcp_may_update_window(tp, ack, seq, ntohs(th->window)<<tp->snd_wscale) &&
 
-	write_unlock(&ehead->lock);
+		/* 4. ... and sits in replay window. */
+		(s32)(tp->ts_recent - tp->rcv_tsval) <= (tp->rto*1024)/HZ);
+}
 
-	/* Step 3: Put TW into bind hash. Original socket stays there too.
-	   Note, that any socket with sk->num!=0 MUST be bound in binding
-	   cache, even if it is closed.
-	 */
-	bhead = &tcp_bhash[tcp_bhashfn(sk->num)];
-	spin_lock(&bhead->lock);
-	tw->tb = (struct tcp_bind_bucket *)sk->prev;
-	BUG_TRAP(sk->prev!=NULL);
-	if ((tw->bind_next = tw->tb->owners) != NULL)
-		tw->tb->owners->bind_pprev = &tw->bind_next;
-	tw->tb->owners = (struct sock*)tw;
-	tw->bind_pprev = &tw->tb->owners;
-	spin_unlock(&bhead->lock);
+extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct sk_buff *skb)
+{
+	return ((s32)(tp->ts_recent - tp->rcv_tsval) > TCP_PAWS_WINDOW &&
+		xtime.tv_sec < tp->ts_recent_stamp + TCP_PAWS_24DAYS &&
+		!tcp_disordered_ack(tp, skb));
 }
 
-/* 
- * Move a socket to time-wait or dead fin-wait-2 state.
- */ 
-void tcp_time_wait(struct sock *sk, int state, int timeo)
+static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
 {
-	struct tcp_tw_bucket *tw = NULL;
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int recycle_ok = 0;
+	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 (sysctl_tcp_tw_recycle && tp->ts_recent_stamp)
-		recycle_ok = tp->af_specific->remember_stamp(sk);
+	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);
+}
 
-	if (tcp_tw_count < sysctl_tcp_max_tw_buckets)
-		tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC);
-
-	if(tw != NULL) {
-		int rto = (tp->rto<<2) - (tp->rto>>1);
-
-		/* Give us an identity. */
-		tw->daddr	= sk->daddr;
-		tw->rcv_saddr	= sk->rcv_saddr;
-		tw->bound_dev_if= sk->bound_dev_if;
-		tw->num		= sk->num;
-		tw->state	= TCP_TIME_WAIT;
-		tw->substate	= state;
-		tw->sport	= sk->sport;
-		tw->dport	= sk->dport;
-		tw->family	= sk->family;
-		tw->reuse	= sk->reuse;
-		tw->rcv_wscale	= tp->rcv_wscale;
-		atomic_set(&tw->refcnt, 0);
-
-		tw->hashent	= sk->hashent;
-		tw->rcv_nxt	= tp->rcv_nxt;
-		tw->snd_nxt	= tp->snd_nxt;
-		tw->rcv_wnd	= tcp_receive_window(tp);
-		tw->syn_seq	= tp->syn_seq;
-		tw->ts_recent	= tp->ts_recent;
-		tw->ts_recent_stamp= tp->ts_recent_stamp;
-		tw->pprev_death = NULL;
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-		if(tw->family == PF_INET6) {
-			memcpy(&tw->v6_daddr,
-			       &sk->net_pinfo.af_inet6.daddr,
-			       sizeof(struct in6_addr));
-			memcpy(&tw->v6_rcv_saddr,
-			       &sk->net_pinfo.af_inet6.rcv_saddr,
-			       sizeof(struct in6_addr));
-		}
+/* This functions checks to see if the tcp header is actually acceptable.
+ *
+ * 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
+ */
+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
-		/* Linkage updates. */
-		__tcp_tw_hashdance(sk, tw);
-
-		/* Get the TIME_WAIT timeout firing. */
-		if (timeo < rto)
-			timeo = rto;
+	if (seq == tp->rcv_nxt)
+		return (rcv_wnd || (end_seq == seq) || rst);
 
-		if (recycle_ok) {
-			tw->timeout = rto;
-		} else {
-			tw->timeout = TCP_TIMEWAIT_LEN;
-			if (state == TCP_TIME_WAIT)
-				timeo = TCP_TIMEWAIT_LEN;
-		}
+	return __tcp_sequence(tp, seq, end_seq);
+}
 
-		tcp_tw_schedule(tw, timeo);
-	} else {
-		/* Sorry, if we're out of memory, just CLOSE this
-		 * socket up.  We've got bigger problems than
-		 * non-graceful socket closings.
-		 */
-		if (net_ratelimit())
-			printk(KERN_INFO "TCP: time wait bucket table overflow\n");
+/* When we get a reset we do this. */
+static void tcp_reset(struct sock *sk)
+{
+	/* We want the right error as BSD sees it (and indeed as we do). */
+	switch (sk->state) {
+		case TCP_SYN_SENT:
+			sk->err = ECONNREFUSED;
+			break;
+		case TCP_CLOSE_WAIT:
+			sk->err = EPIPE;
+			break;
+		case TCP_CLOSE:
+			return;
+		default:
+			sk->err = ECONNRESET;
 	}
 
-	tcp_update_metrics(sk);
+	if (!sk->dead)
+		sk->error_report(sk);
+
 	tcp_done(sk);
 }
 
@@ -1611,22 +2179,22 @@
  *
  *	If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
  */
- 
 static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	tp->fin_seq = TCP_SKB_CB(skb)->end_seq;
-	tp->ack.pending = 1;
-	tp->ack.quick = 0;
+	tcp_schedule_ack(tp);
 
 	sk->shutdown |= RCV_SHUTDOWN;
+	sk->done = 1;
 
 	switch(sk->state) {
 		case TCP_SYN_RECV:
 		case TCP_ESTABLISHED:
 			/* Move to CLOSE_WAIT */
 			tcp_set_state(sk, TCP_CLOSE_WAIT);
+			tp->ack.pingpong = 1;
 			break;
 
 		case TCP_CLOSE_WAIT:
@@ -1644,6 +2212,7 @@
 			 * happens, we must ack the received FIN and
 			 * enter the CLOSING state.
 			 */
+			tcp_send_ack(sk);
 			tcp_set_state(sk, TCP_CLOSING);
 			break;
 		case TCP_FIN_WAIT2:
@@ -1664,7 +2233,8 @@
 	 */
 	__skb_queue_purge(&tp->out_of_order_queue);
 	if (tp->sack_ok)
-		tp->num_sacks = 0;
+		tcp_sack_reset(tp);
+	tcp_mem_reclaim(sk);
 
 	if (!sk->dead) {
 		sk->state_change(sk);
@@ -1677,51 +2247,90 @@
 	}
 }
 
+static __inline__ int
+tcp_sack_extend(struct tcp_sack_block *sp, u32 seq, u32 end_seq)
+{
+	if (!after(seq, sp->end_seq) && !after(sp->start_seq, end_seq)) {
+		if (before(seq, sp->start_seq))
+			sp->start_seq = seq;
+		if (after(end_seq, sp->end_seq))
+			sp->end_seq = end_seq;
+		return 1;
+	}
+	return 0;
+}
+
+static __inline__ void tcp_dsack_set(struct tcp_opt *tp, u32 seq, u32 end_seq)
+{
+	if (tp->sack_ok && sysctl_tcp_dsack) {
+		if (before(seq, tp->rcv_nxt))
+			NET_INC_STATS_BH(TCPDSACKOldSent);
+		else
+			NET_INC_STATS_BH(TCPDSACKOfoSent);
+
+		tp->dsack = 1;
+		tp->duplicate_sack[0].start_seq = seq;
+		tp->duplicate_sack[0].end_seq = end_seq;
+		tp->eff_sacks = min(tp->num_sacks+1, 4-tp->tstamp_ok);
+	}
+}
+
+static __inline__ void tcp_dsack_extend(struct tcp_opt *tp, u32 seq, u32 end_seq)
+{
+	if (!tp->dsack)
+		tcp_dsack_set(tp, seq, end_seq);
+	else
+		tcp_sack_extend(tp->duplicate_sack, seq, end_seq);
+}
+
+static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+	if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
+	    before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+		NET_INC_STATS_BH(DelayedACKLost);
+		tcp_enter_quickack_mode(tp);
+
+		if (tp->sack_ok && sysctl_tcp_dsack) {
+			u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+
+			if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))
+				end_seq = tp->rcv_nxt;
+			tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, end_seq);
+		}
+	}
+
+	tcp_send_ack(sk);
+}
+
 /* These routines update the SACK block as out-of-order packets arrive or
  * in-order packets close up the sequence space.
  */
-static void tcp_sack_maybe_coalesce(struct tcp_opt *tp, struct tcp_sack_block *sp)
+static void tcp_sack_maybe_coalesce(struct tcp_opt *tp)
 {
-	int this_sack, num_sacks = tp->num_sacks;
-	struct tcp_sack_block *swalk = &tp->selective_acks[0];
+	int this_sack;
+	struct tcp_sack_block *sp = &tp->selective_acks[0];
+	struct tcp_sack_block *swalk = sp+1;
 
-	/* If more than one SACK block, see if the recent change to SP eats into
+	/* See if the recent change to the first SACK eats into
 	 * or hits the sequence space of other SACK blocks, if so coalesce.
 	 */
-	if(num_sacks != 1) {
-		for(this_sack = 0; this_sack < num_sacks; this_sack++, swalk++) {
-			if(swalk == sp)
-				continue;
+	for (this_sack = 1; this_sack < tp->num_sacks; ) {
+		if (tcp_sack_extend(sp, swalk->start_seq, swalk->end_seq)) {
+			int i;
 
-			/* First case, bottom of SP moves into top of the
-			 * sequence space of SWALK.
-			 */
-			if(between(sp->start_seq, swalk->start_seq, swalk->end_seq)) {
-				sp->start_seq = swalk->start_seq;
-				goto coalesce;
-			}
-			/* Second case, top of SP moves into bottom of the
-			 * sequence space of SWALK.
+			/* Zap SWALK, by moving every further SACK up by one slot.
+			 * Decrease num_sacks.
 			 */
-			if(between(sp->end_seq, swalk->start_seq, swalk->end_seq)) {
-				sp->end_seq = swalk->end_seq;
-				goto coalesce;
-			}
+			tp->num_sacks--;
+			tp->eff_sacks = min(tp->num_sacks+tp->dsack, 4-tp->tstamp_ok);
+			for(i=this_sack; i < tp->num_sacks; i++)
+				sp[i] = sp[i+1];
+			continue;
 		}
+		this_sack++, swalk++;
 	}
-	/* SP is the only SACK, or no coalescing cases found. */
-	return;
-
-coalesce:
-	/* Zap SWALK, by moving every further SACK up by one slot.
-	 * Decrease num_sacks.
-	 */
-	for(; this_sack < num_sacks-1; this_sack++, swalk++) {
-		struct tcp_sack_block *next = (swalk + 1);
-		swalk->start_seq = next->start_seq;
-		swalk->end_seq = next->end_seq;
-	}
-	tp->num_sacks--;
 }
 
 static __inline__ void tcp_sack_swap(struct tcp_sack_block *sack1, struct tcp_sack_block *sack2)
@@ -1737,151 +2346,117 @@
 	sack2->end_seq = tmp;
 }
 
-static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
+static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct tcp_sack_block *sp = &tp->selective_acks[0];
 	int cur_sacks = tp->num_sacks;
+	int this_sack;
 
 	if (!cur_sacks)
 		goto new_sack;
 
-	/* Optimize for the common case, new ofo frames arrive
-	 * "in order". ;-)  This also satisfies the requirements
-	 * of RFC2018 about ordering of SACKs.
-	 */
-	if(sp->end_seq == TCP_SKB_CB(skb)->seq) {
-		sp->end_seq = TCP_SKB_CB(skb)->end_seq;
-		tcp_sack_maybe_coalesce(tp, sp);
-	} else if(sp->start_seq == TCP_SKB_CB(skb)->end_seq) {
-		/* Re-ordered arrival, in this case, can be optimized
-		 * as well.
-		 */
-		sp->start_seq = TCP_SKB_CB(skb)->seq;
-		tcp_sack_maybe_coalesce(tp, sp);
-	} else {
-		struct tcp_sack_block *swap = sp + 1;
-		int this_sack, max_sacks = (tp->tstamp_ok ? 3 : 4);
-
-		/* Oh well, we have to move things around.
-		 * Try to find a SACK we can tack this onto.
-		 */
-
-		for(this_sack = 1; this_sack < cur_sacks; this_sack++, swap++) {
-			if((swap->end_seq == TCP_SKB_CB(skb)->seq) ||
-			   (swap->start_seq == TCP_SKB_CB(skb)->end_seq)) {
-				if(swap->end_seq == TCP_SKB_CB(skb)->seq)
-					swap->end_seq = TCP_SKB_CB(skb)->end_seq;
-				else
-					swap->start_seq = TCP_SKB_CB(skb)->seq;
-				tcp_sack_swap(sp, swap);
-				tcp_sack_maybe_coalesce(tp, sp);
-				return;
-			}
-		}
-
-		/* Could not find an adjacent existing SACK, build a new one,
-		 * put it at the front, and shift everyone else down.  We
-		 * always know there is at least one SACK present already here.
-		 *
-		 * If the sack array is full, forget about the last one.
-		 */
-		if (cur_sacks >= max_sacks) {
-			cur_sacks--;
-			tp->num_sacks--;
-		}
-		while(cur_sacks >= 1) {
-			struct tcp_sack_block *this = &tp->selective_acks[cur_sacks];
-			struct tcp_sack_block *prev = (this - 1);
-			this->start_seq = prev->start_seq;
-			this->end_seq = prev->end_seq;
-			cur_sacks--;
+	for (this_sack=0; this_sack<cur_sacks; this_sack++, sp++) {
+		if (tcp_sack_extend(sp, seq, end_seq)) {
+			/* Rotate this_sack to the first one. */
+			for (; this_sack>0; this_sack--, sp--)
+				tcp_sack_swap(sp, sp-1);
+			if (cur_sacks > 1)
+				tcp_sack_maybe_coalesce(tp);
+			return;
 		}
+	}
 
-	new_sack:
-		/* Build the new head SACK, and we're done. */
-		sp->start_seq = TCP_SKB_CB(skb)->seq;
-		sp->end_seq = TCP_SKB_CB(skb)->end_seq;
-		tp->num_sacks++;
+	/* Could not find an adjacent existing SACK, build a new one,
+	 * put it at the front, and shift everyone else down.  We
+	 * always know there is at least one SACK present already here.
+	 *
+	 * If the sack array is full, forget about the last one.
+	 */
+	if (this_sack >= 4) {
+		this_sack--;
+		tp->num_sacks--;
+		sp--;
 	}
+	for(; this_sack > 0; this_sack--, sp--)
+		*sp = *(sp-1);
+
+new_sack:
+	/* Build the new head SACK, and we're done. */
+	sp->start_seq = seq;
+	sp->end_seq = end_seq;
+	tp->num_sacks++;
+	tp->eff_sacks = min(tp->num_sacks+tp->dsack, 4-tp->tstamp_ok);
 }
 
-static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb)
+/* RCV.NXT advances, some SACKs should be eaten. */
+
+static void tcp_sack_remove(struct tcp_opt *tp)
 {
 	struct tcp_sack_block *sp = &tp->selective_acks[0];
 	int num_sacks = tp->num_sacks;
 	int this_sack;
 
-	/* This is an in order data segment _or_ an out-of-order SKB being
-	 * moved to the receive queue, so we know this removed SKB will eat
-	 * from the front of a SACK.
-	 */
-	for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
-		/* Check if the start of the sack is covered by skb. */
-		if(!before(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
-		   before(sp->start_seq, TCP_SKB_CB(skb)->end_seq))
-			break;
-	}
-
-	/* This should only happen if so many SACKs get built that some get
-	 * pushed out before we get here, or we eat some in sequence packets
-	 * which are before the first SACK block.
-	 */
-	if(this_sack >= num_sacks)
+	/* Empty ofo queue, hence, all the SACKs are eaten. Clear. */
+	if (skb_queue_len(&tp->out_of_order_queue) == 0) {
+		tp->num_sacks = 0;
+		tp->eff_sacks = tp->dsack;
 		return;
+	}
 
-	sp->start_seq = TCP_SKB_CB(skb)->end_seq;
-	if(!before(sp->start_seq, sp->end_seq)) {
-		/* Zap this SACK, by moving forward any other SACKS. */
-		for(this_sack += 1; this_sack < num_sacks; this_sack++, sp++) {
-			struct tcp_sack_block *next = (sp + 1);
-			sp->start_seq = next->start_seq;
-			sp->end_seq = next->end_seq;
+	for(this_sack = 0; this_sack < num_sacks; ) {
+		/* Check if the start of the sack is covered by RCV.NXT. */
+		if (!before(tp->rcv_nxt, sp->start_seq)) {
+			int i;
+
+			/* RCV.NXT must cover all the block! */
+			BUG_TRAP(!before(tp->rcv_nxt, sp->end_seq));
+
+			/* Zap this SACK, by moving forward any other SACKS. */
+			for (i=this_sack+1; i < num_sacks; i++)
+				sp[i-1] = sp[i];
+			num_sacks--;
+			continue;
 		}
-		tp->num_sacks--;
+		this_sack++;
+		sp++;
 	}
-}
-
-static void tcp_sack_extend(struct tcp_opt *tp, struct sk_buff *old_skb, struct sk_buff *new_skb)
-{
-	struct tcp_sack_block *sp = &tp->selective_acks[0];
-	int num_sacks = tp->num_sacks;
-	int this_sack;
-
-	for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
-		if(sp->end_seq == TCP_SKB_CB(old_skb)->end_seq)
-			break;
+	if (num_sacks != tp->num_sacks) {
+		tp->num_sacks = num_sacks;
+		tp->eff_sacks = min(tp->num_sacks+tp->dsack, 4-tp->tstamp_ok);
 	}
-	if(this_sack >= num_sacks)
-		return;
-	sp->end_seq = TCP_SKB_CB(new_skb)->end_seq;
 }
 
-
 /* This one checks to see if we can put data from the
  * out_of_order queue into the receive_queue.
  */
 static void tcp_ofo_queue(struct sock *sk)
 {
-	struct sk_buff *skb;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	__u32 dsack_high = tp->rcv_nxt;
+	struct sk_buff *skb;
 
-	while ((skb = skb_peek(&tp->out_of_order_queue))) {
+	while ((skb = skb_peek(&tp->out_of_order_queue)) != NULL) {
 		if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
 			break;
 
+		if (before(TCP_SKB_CB(skb)->seq, dsack_high)) {
+			__u32 dsack = dsack_high;
+			if (before(TCP_SKB_CB(skb)->end_seq, dsack_high))
+				dsack_high = TCP_SKB_CB(skb)->end_seq;
+			tcp_dsack_extend(tp, TCP_SKB_CB(skb)->seq, dsack);
+		}
+
 		if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
 			SOCK_DEBUG(sk, "ofo packet was already received \n");
 			__skb_unlink(skb, skb->list);
-			kfree_skb(skb);
+			__kfree_skb(skb);
 			continue;
 		}
 		SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
 			   tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
 			   TCP_SKB_CB(skb)->end_seq);
 
-		if(tp->sack_ok)
-			tcp_sack_remove_skb(tp, skb);
 		__skb_unlink(skb, skb->list);
 		__skb_queue_tail(&sk->receive_queue, skb);
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
@@ -1892,10 +2467,14 @@
 
 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 {
-	struct sk_buff *skb1;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	int eaten = 0;
 
+	if (tp->dsack) {
+		tp->dsack = 0;
+		tp->eff_sacks = min(tp->num_sacks, 4-tp->tstamp_ok);
+	}
+
 	/*  Queue data for delivery to the user.
 	 *  Packets in sequence go to the receive queue.
 	 *  Out of sequence packets to the out_of_order_queue.
@@ -1924,20 +2503,27 @@
 
 		if (!eaten) {
 queue_and_out:
-			skb_set_owner_r(skb, sk);
+			tcp_set_owner_r(skb, sk);
 			__skb_queue_tail(&sk->receive_queue, skb);
 		}
-		dst_confirm(sk->dst_cache);
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 		if(skb->len)
-			tcp_event_data_recv(tp, skb); 
+			tcp_event_data_recv(sk, tp, skb);
 		if(skb->h.th->fin)
 			tcp_fin(skb, sk, skb->h.th);
 
-		/* This may have eaten into a SACK block. */
-		if(tp->sack_ok && tp->num_sacks)
-			tcp_sack_remove_skb(tp, skb);
-		tcp_ofo_queue(sk);
+		if (skb_queue_len(&tp->out_of_order_queue)) {
+			tcp_ofo_queue(sk);
+
+			/* RFC2581. 4.2. SHOULD send immediate ACK, when
+			 * gap in queue is filled.
+			 */
+			if (skb_queue_len(&tp->out_of_order_queue) == 0)
+				tp->ack.pingpong = 0;
+		}
+
+		if(tp->num_sacks)
+			tcp_sack_remove(tp);
 
 		/* Turn on fast path. */ 
 		if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
@@ -1948,24 +2534,28 @@
 			tcp_fast_path_on(tp);
 
 		if (eaten) {
-			kfree_skb(skb);
+			__kfree_skb(skb);
 		} else if (!sk->dead)
 			sk->data_ready(sk, 0);
 		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.
 		 */
-		NETDEBUG(printk("retransmit in tcp_data_queue: seq %X\n", TCP_SKB_CB(skb)->seq));
+		printk("BUG: retransmit in tcp_data_queue: seq %X\n", TCP_SKB_CB(skb)->seq);
 		tcp_enter_quickack_mode(tp);
-		tp->ack.pending = 1;
-		kfree_skb(skb);
+		tcp_schedule_ack(tp);
+		__kfree_skb(skb);
 		return;
 	}
+#endif
+
+	tcp_enter_quickack_mode(tp);
 
 	if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
 		/* Partial packet, seq < rcv_next < end_seq */
@@ -1973,67 +2563,198 @@
 			   tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
 			   TCP_SKB_CB(skb)->end_seq);
 
+		tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, tp->rcv_nxt);
 		goto queue_and_out;
 	}
 
-	/* Ok. This is an out_of_order segment, force an ack. */
-	tp->ack.pending = 1;
+	TCP_ECN_check_ce(tp, skb);
 
 	/* Disable header prediction. */
 	tp->pred_flags = 0;
-
+	tcp_schedule_ack(tp);
 
 	SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
 		   tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
 
-	skb_set_owner_r(skb, sk);
+	tcp_set_owner_r(skb, sk);
 
 	if (skb_peek(&tp->out_of_order_queue) == NULL) {
 		/* Initial out of order segment, build 1 SACK. */
 		if(tp->sack_ok) {
 			tp->num_sacks = 1;
+			tp->dsack = 0;
+			tp->eff_sacks = 1;
 			tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
 			tp->selective_acks[0].end_seq = TCP_SKB_CB(skb)->end_seq;
 		}
 		__skb_queue_head(&tp->out_of_order_queue,skb);
 	} else {
-		for(skb1=tp->out_of_order_queue.prev; ; skb1 = skb1->prev) {
-			/* Already there. */
-			if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb1)->seq) {
-				if (skb->len >= skb1->len) {
-					if(tp->sack_ok)
-						tcp_sack_extend(tp, skb1, skb);
-					__skb_append(skb1, skb);
-					__skb_unlink(skb1, skb1->list);
-					kfree_skb(skb1);
-				} else {
-					/* A duplicate, smaller than what is in the
-					 * out-of-order queue right now, toss it.
-					 */
-					kfree_skb(skb);
-				}
+		struct sk_buff *skb1=tp->out_of_order_queue.prev;
+		u32 seq = TCP_SKB_CB(skb)->seq;
+		u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+
+		if (seq == TCP_SKB_CB(skb1)->end_seq) {
+			__skb_append(skb1, skb);
+
+			if (tp->num_sacks == 0 ||
+			    tp->selective_acks[0].end_seq != seq)
+				goto add_sack;
+
+			/* Common case: data arrive in order after hole. */
+			tp->selective_acks[0].end_seq = end_seq;
+			return;
+		}
+
+		/* Find place to insert this segment. */
+		do {
+			if (!after(TCP_SKB_CB(skb1)->seq, seq))
 				break;
+		} while ((skb1=skb1->prev) != (struct sk_buff*)&tp->out_of_order_queue);
+
+		/* Do skb overlap to previous one? */
+		if (skb1 != (struct sk_buff*)&tp->out_of_order_queue &&
+		    before(seq, TCP_SKB_CB(skb1)->end_seq)) {
+			if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
+				/* All the bits are present. Drop. */
+				__kfree_skb(skb);
+				tcp_dsack_set(tp, seq, end_seq);
+				goto add_sack;
+			}
+			if (after(seq, TCP_SKB_CB(skb1)->seq)) {
+				/* Partial overlap. */
+				tcp_dsack_set(tp, seq, TCP_SKB_CB(skb1)->end_seq);
+			} else {
+				skb1 = skb1->prev;
 			}
-			
-			if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb1)->seq)) {
-				__skb_append(skb1, skb);
-				if(tp->sack_ok)
-					tcp_sack_new_ofo_skb(sk, skb);
-				break;
+		}
+		__skb_insert(skb, skb1, skb1->next, &tp->out_of_order_queue);
+		
+		/* And clean segments covered by new one as whole. */
+		while ((skb1 = skb->next) != (struct sk_buff*)&tp->out_of_order_queue &&
+		       after(end_seq, TCP_SKB_CB(skb1)->seq)) {
+		       if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
+			       tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, end_seq);
+			       break;
+		       }
+		       __skb_unlink(skb1, skb1->list);
+		       tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, TCP_SKB_CB(skb1)->end_seq);
+		       __kfree_skb(skb1);
+		}
+
+add_sack:
+		if (tp->sack_ok)
+			tcp_sack_new_ofo_skb(sk, seq, end_seq);
+	}
+}
+
+
+static void tcp_collapse_queue(struct sock *sk, struct sk_buff_head *q)
+{
+	struct sk_buff *skb = skb_peek(q);
+	struct sk_buff *skb_next;
+
+	while (skb &&
+	       skb != (struct sk_buff *)q &&
+	       (skb_next = skb->next) != (struct sk_buff *)q) {
+		struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
+		struct tcp_skb_cb *scb_next = TCP_SKB_CB(skb_next);
+
+		if (scb->end_seq == scb_next->seq &&
+		    skb_tailroom(skb) >= skb_next->len &&
+#define TCP_DONT_COLLAPSE (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN)
+		    !(tcp_flag_word(skb->h.th)&TCP_DONT_COLLAPSE) &&
+		    !(tcp_flag_word(skb_next->h.th)&TCP_DONT_COLLAPSE)) {
+			/* OK to collapse two skbs to one */
+			memcpy(skb_put(skb, skb_next->len), skb_next->data, skb_next->len);
+			__skb_unlink(skb_next, skb_next->list);
+			scb->end_seq = scb_next->end_seq;
+			__kfree_skb(skb_next);
+			NET_INC_STATS_BH(TCPRcvCollapsed);
+		} else {
+			/* Lots of spare tailroom, reallocate this skb to trim it. */
+			if (tcp_win_from_space(skb->truesize) > skb->len &&
+			    skb_tailroom(skb) > sizeof(struct sk_buff) + 16) {
+				struct sk_buff *nskb;
+
+				nskb = skb_copy_expand(skb, skb_headroom(skb), 0, GFP_ATOMIC);
+				if (nskb) {
+					tcp_set_owner_r(nskb, sk);
+					memcpy(nskb->data-skb_headroom(skb),
+					       skb->data-skb_headroom(skb),
+					       skb_headroom(skb));
+					__skb_append(skb, nskb);
+					__skb_unlink(skb, skb->list);
+					__kfree_skb(skb);
+				}
 			}
+			skb = skb_next;
+		}
+	}
+}
+
+/* Clean the out_of_order queue if we can, trying to get
+ * the socket within its memory limits again.
+ *
+ * Return less than zero if we should start dropping frames
+ * until the socket owning process reads some of the data
+ * to stabilize the situation.
+ */
+static int tcp_prune_queue(struct sock *sk)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; 
+
+	SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq);
+
+	NET_INC_STATS_BH(PruneCalled);
+
+	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
+		tcp_clamp_window(sk, tp);
+	else if (tcp_memory_pressure)
+		tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss);
+
+	tcp_collapse_queue(sk, &sk->receive_queue);
+	tcp_collapse_queue(sk, &tp->out_of_order_queue);
+	tcp_mem_reclaim(sk);
+
+	if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf)
+		return 0;
+
+	/* Collapsing did not help, destructive actions follow.
+	 * This must not ever occur. */
 
-                        /* See if we've hit the start. If so insert. */
-			if (skb1 == skb_peek(&tp->out_of_order_queue)) {
-				__skb_queue_head(&tp->out_of_order_queue,skb);
-				if(tp->sack_ok)
-					tcp_sack_new_ofo_skb(sk, skb);
-				break;
-			}
-		}
+	/* First, purge the out_of_order queue. */
+	if (skb_queue_len(&tp->out_of_order_queue)) {
+		net_statistics[smp_processor_id()*2].OfoPruned += skb_queue_len(&tp->out_of_order_queue);
+		__skb_queue_purge(&tp->out_of_order_queue);
+
+		/* Reset SACK state.  A conforming SACK implementation will
+		 * do the same at a timeout based retransmit.  When a connection
+		 * is in a sad state like this, we care only about integrity
+		 * of the connection not performance.
+		 */
+		if(tp->sack_ok)
+			tcp_sack_reset(tp);
+		tcp_mem_reclaim(sk);
 	}
-	return;
+
+	if(atomic_read(&sk->rmem_alloc) <= sk->rcvbuf)
+		return 0;
+
+	/* If we are really being abused, tell the caller to silently
+	 * drop receive data on the floor.  It will get retransmitted
+	 * and hopefully then we'll have sufficient space.
+	 */
+	NET_INC_STATS_BH(RcvPruned);
+
+	/* Massive buffer overcommit. */
+	return -1;
 }
 
+static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb)
+{
+	return (int)skb->truesize <= sk->forward_alloc ||
+		tcp_mem_schedule(sk, skb->truesize, 1);
+}
 
 /*
  *	This routine handles the data.  If there is room in the buffer,
@@ -2053,53 +2774,103 @@
         if (skb->len == 0 && !th->fin)
 		goto drop;
 
+	TCP_ECN_accept_cwr(tp, skb);
+
 	/* 
 	 *	If our receive queue has grown past its limits shrink it.
 	 *	Make sure to do this before moving rcv_nxt, otherwise
 	 *	data might be acked for that we don't have enough room.
 	 */
-	if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) { 
-		if (prune_queue(sk) < 0) { 
-			/* Still not enough room. That can happen when
-			 * skb->true_size differs significantly from skb->len.
-			 */
+	if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf ||
+	    !tcp_rmem_schedule(sk, skb)) {
+		if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb))
 			goto drop;
-		}
 	}
 
 	tcp_data_queue(sk, skb);
 
+#ifdef TCP_DEBUG
 	if (before(tp->rcv_nxt, tp->copied_seq)) {
 		printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n");
 		tp->rcv_nxt = tp->copied_seq;
 	}
+#endif
 	return;
 
 drop:
-	kfree_skb(skb);
+	__kfree_skb(skb);
+}
+
+/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto.
+ * As additional protections, we do not touch cwnd in retransmission phases,
+ * and if application hit its sndbuf limit recently.
+ */
+void tcp_cwnd_application_limited(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+	if (tp->ca_state == TCP_CA_Open &&
+	    sk->socket && !test_bit(SOCK_NOSPACE, &sk->socket->flags)) {
+		/* Limited by application or receiver window. */
+		u32 win_used = max(tp->snd_cwnd_used, 2);
+		if (win_used < tp->snd_cwnd) {
+			tp->snd_ssthresh = tcp_current_ssthresh(tp);
+			tp->snd_cwnd = (tp->snd_cwnd+win_used)>>1;
+		}
+		tp->snd_cwnd_used = 0;
+	}
+	tp->snd_cwnd_stamp = tcp_time_stamp;
 }
 
+
 /* When incoming ACK allowed to free some skb from write_queue,
- * we remember this in flag tp->sorry and wake up socket on the exit
- * from tcp input handler. Probably, handler has already eat this space
- * sending ACK and cloned frames from tcp_write_xmit().
+ * we remember this event in flag tp->queue_shrunk and wake up socket
+ * on the exit from tcp input handler.
  */
-static __inline__ void tcp_new_space(struct sock *sk)
+static void tcp_new_space(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct socket *sock;
 
-	tp->sorry = 0;
+	if (tp->packets_out < tp->snd_cwnd &&
+	    !(sk->userlocks&SOCK_SNDBUF_LOCK) &&
+	    !tcp_memory_pressure &&
+	    atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) {
+		int sndmem, demanded;
+
+		sndmem = tp->mss_clamp+MAX_TCP_HEADER+16+sizeof(struct sk_buff);
+		demanded = max(tp->snd_cwnd, tp->reordering+1);
+		sndmem *= 2*demanded;
+		if (sndmem > sk->sndbuf)
+			sk->sndbuf = min(sndmem, sysctl_tcp_wmem[2]);
+		tp->snd_cwnd_stamp = tcp_time_stamp;
+	}
+
+	/* Wakeup users. */
+	if (tcp_wspace(sk) >= tcp_min_write_space(sk)) {
+		struct socket *sock = sk->socket;
 
-	if (sock_wspace(sk) >= tcp_min_write_space(sk) &&
-	    (sock = sk->socket) != NULL) {
 		clear_bit(SOCK_NOSPACE, &sock->flags);
 
 		if (sk->sleep && waitqueue_active(sk->sleep))
 			wake_up_interruptible(sk->sleep);
 
-		if (sock->fasync_list)
+		if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN))
 			sock_wake_async(sock, 2, POLL_OUT);
+
+		/* Satisfy those who hook write_space() callback. */
+		if (sk->write_space != tcp_write_space)
+			sk->write_space(sk);
+	}
+}
+
+static inline void tcp_check_space(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+	if (tp->queue_shrunk) {
+		tp->queue_shrunk = 0;
+		if (sk->socket && test_bit(SOCK_NOSPACE, &sk->socket->flags))
+			tcp_new_space(sk);
 	}
 }
 
@@ -2118,7 +2889,8 @@
 	struct sk_buff *skb = sk->tp_pinfo.af_tcp.send_head;
 
 	if (skb != NULL)
-		__tcp_data_snd_check(sk, skb); 
+		__tcp_data_snd_check(sk, skb);
+	tcp_check_space(sk);
 }
 
 /*
@@ -2128,32 +2900,15 @@
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-	/* This also takes care of updating the window.
-	 * This if statement needs to be simplified.
-	 *
-	 * Rules for delaying an ack:
-	 *      - delay time <= 0.5 HZ
-	 *      - we don't have a window update to send
-	 *      - must send at least every 2 full sized packets
-	 *	- must send an ACK if we have any out of order data
-	 *
-	 * With an extra heuristic to handle loss of packet
-	 * situations and also helping the sender leave slow
-	 * start in an expediant manner.
-	 */
-
-	    /* More than one full frame received or... */
+	    /* More than one full frame received... */
 	if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss
-#ifdef TCP_MORE_COARSE_ACKS
-	     /* Avoid to send immediate ACK from input path, if it
-	      * does not advance window far enough. tcp_recvmsg() will do this.
+	     /* ... and right edge of window advances far enough.
+	      * (tcp_recvmsg() will send ACK otherwise). Or...
 	      */
-	     && (!sysctl_tcp_retrans_collapse || __tcp_select_window(sk) >= tp->rcv_wnd)
-#endif
-	     ) ||
+	     && __tcp_select_window(sk) >= tp->rcv_wnd) ||
 	    /* We ACK each frame or... */
 	    tcp_in_quickack_mode(tp) ||
-	    /* We have out of order data or */
+	    /* We have out of order data. */
 	    (ofo_possible &&
 	     skb_peek(&tp->out_of_order_queue) != NULL)) {
 		/* Then ack it now */
@@ -2167,14 +2922,13 @@
 static __inline__ void tcp_ack_snd_check(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	if (tp->ack.pending == 0) {
+	if (!tcp_ack_scheduled(tp)) {
 		/* We sent a data segment already. */
 		return;
 	}
 	__tcp_ack_snd_check(sk, 1);
 }
 
-
 /*
  *	This routine is only called when we have urgent data
  *	signalled. Its the 'slow' part of tcp_urg. It could be
@@ -2248,92 +3002,6 @@
 	}
 }
 
-/* Clean the out_of_order queue if we can, trying to get
- * the socket within its memory limits again.
- *
- * Return less than zero if we should start dropping frames
- * until the socket owning process reads some of the data
- * to stabilize the situation.
- */
-static int prune_queue(struct sock *sk)
-{
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; 
-	struct sk_buff *skb;
-	int pruned = 0;
-
-	SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq);
-
-	NET_INC_STATS_BH(PruneCalled);
-
-	/* First, purge the out_of_order queue. */
-	skb = __skb_dequeue_tail(&tp->out_of_order_queue);
-	if(skb != NULL) {
-		/* Free it all. */
-		do {
-			pruned += skb->len;
-			net_statistics[smp_processor_id()*2].OfoPruned += skb->len; 
-			kfree_skb(skb);
-			skb = __skb_dequeue_tail(&tp->out_of_order_queue);
-		} while(skb != NULL);
-
-		/* Reset SACK state.  A conforming SACK implementation will
-		 * do the same at a timeout based retransmit.  When a connection
-		 * is in a sad state like this, we care only about integrity
-		 * of the connection not performance.
-		 */
-		if(tp->sack_ok)
-			tp->num_sacks = 0;
-	}
-	
-	/* If we are really being abused, tell the caller to silently
-	 * drop receive data on the floor.  It will get retransmitted
-	 * and hopefully then we'll have sufficient space.
-	 *
-	 * We used to try to purge the in-order packets too, but that
-	 * turns out to be deadly and fraught with races.  Consider:
-	 *
-	 * 1) If we acked the data, we absolutely cannot drop the
-	 *    packet.  This data would then never be retransmitted.
-	 * 2) It is possible, with a proper sequence of events involving
-	 *    delayed acks and backlog queue handling, to have the user
-	 *    read the data before it gets acked.  The previous code
-	 *    here got this wrong, and it lead to data corruption.
-	 * 3) Too much state changes happen when the FIN arrives, so once
-	 *    we've seen that we can't remove any in-order data safely.
-	 *
-	 * The net result is that removing in-order receive data is too
-	 * complex for anyones sanity.  So we don't do it anymore.  But
-	 * if we are really having our buffer space abused we stop accepting
-	 * new receive data.
-	 *
-	 * 8) The arguments are interesting, but I even cannot imagine
-	 * what kind of arguments could force us to drop NICE, ALREADY
-	 * RECEIVED DATA only to get one more packet? --ANK
-	 *
-	 * FIXME: it should recompute SACK state and only remove enough
-	 *        buffers to get into bounds again. The current scheme loses
-	 *        badly sometimes on links with large RTT, especially when 
-	 *        the driver has high overhead per skb.
-	 *        (increasing the rcvbuf is not enough because it inflates the
-	 *         the window too, disabling flow control effectively) -AK
-	 *
-	 *	  Mmm... Why not to scale it seprately then? Just replace
-	 *	  / WINDOW_ADVERTISE_DIVISOR with >> sk->window_advertise_scale
-	 *	  and adjust it dynamically, when TCP window flow control
-	 *	  fails?						-ANK
-	 */
-
-	tp->ack.quick = 0;
-
-	if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1))
-		return 0;
-
-	NET_INC_STATS_BH(RcvPruned);
-
-	/* Massive buffer overcommit. */
-	return -1;
-}
-
 static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
@@ -2454,9 +3122,6 @@
 	 *	We do checksum and copy also but from device to kernel.
 	 */
 
-	/* RED-PEN. Using static variables to pass function arguments
-	 * cannot be good idea...
-	 */
 	tp->saw_tstamp = 0;
 
 	/*	pred_flags is 0xS?10 << 16 + snd_wnd
@@ -2468,7 +3133,7 @@
 	 *	PSH flag is ignored.
 	 */
 
-	if ((tcp_flag_word(th) & ~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) == tp->pred_flags &&
+	if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
 		TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
 		int tcp_header_len = tp->tcp_header_len;
 
@@ -2500,10 +3165,8 @@
 			 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
 			 * Hence, check seq<=rcv_wup reduces to:
 			 */
-			if (tp->rcv_nxt == tp->rcv_wup) {
-				tp->ts_recent = tp->rcv_tsval;
-				tp->ts_recent_stamp = xtime.tv_sec;
-			}
+			if (tp->rcv_nxt == tp->rcv_wup)
+				tcp_store_ts_recent(tp);
 		}
 
 		if (len <= tcp_header_len) {
@@ -2512,18 +3175,15 @@
 				/* We know that such packets are checksummed
 				 * on entry.
 				 */
-				tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
-					TCP_SKB_CB(skb)->ack_seq, len); 
-				kfree_skb(skb); 
+				tcp_ack(sk, skb, 0);
+				__kfree_skb(skb); 
 				tcp_data_snd_check(sk);
-				if (tp->sorry)
-					tcp_new_space(sk);
 				return 0;
 			} else { /* Header too small */
 				TCP_INC_STATS_BH(TcpInErrs);
 				goto discard;
 			}
-		} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
+		} else {
 			int eaten = 0;
 
 			if (tp->ucopy.task == current &&
@@ -2546,67 +3206,59 @@
 				if (tcp_checksum_complete_user(sk, skb))
 					goto csum_error;
 
-				if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
+				if ((int)skb->truesize > sk->forward_alloc)
 					goto step5;
 
 				NET_INC_STATS_BH(TCPHPHits);
 
 				/* Bulk data transfer: receiver */
 				__skb_pull(skb,tcp_header_len);
-
-				/* DO NOT notify forward progress here.
-				 * It saves dozen of CPU instructions in fast path. --ANK
-				 * And where is it signaled then ? -AK
-				 * Nowhere. 8) --ANK
-				 */
 				__skb_queue_tail(&sk->receive_queue, skb);
-				skb_set_owner_r(skb, sk);
-
+				tcp_set_owner_r(skb, sk);
 				tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
-
-				/* FIN bit check is not done since if FIN is set in
-				 * this frame, the pred_flags won't match up. -DaveM
-				 */
-				sk->data_ready(sk, 0);
 			}
 
-			tcp_event_data_recv(tp, skb);
+			tcp_event_data_recv(sk, tp, skb);
+
+			if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) {
+				/* Well, only one small jumplet in fast path... */
+				tcp_ack(sk, skb, FLAG_DATA);
+				tcp_data_snd_check(sk);
+				if (!tcp_ack_scheduled(tp))
+					goto no_ack;
+			}
 
-#ifdef TCP_MORE_COARSE_ACKS
 			if (eaten) {
 				if (tcp_in_quickack_mode(tp)) {
 					tcp_send_ack(sk);
 				} else {
 					tcp_send_delayed_ack(sk);
 				}
-			} else
-#endif
-			__tcp_ack_snd_check(sk, 0);
+			} else {
+				__tcp_ack_snd_check(sk, 0);
+			}
 
+no_ack:
 			if (eaten)
-				kfree_skb(skb);
+				__kfree_skb(skb);
+			else
+				sk->data_ready(sk, 0);
 			return 0;
 		}
-		/* Packet is in sequence, flags are trivial;
-		 * only ACK is strange. Jump to step 5.
-		 */
-		if (tcp_checksum_complete_user(sk, skb))
-			goto csum_error;
-		goto step5;
 	}
 
 slow_path:
-	if (tcp_checksum_complete_user(sk, skb))
+	if (len < (th->doff<<2) || tcp_checksum_complete_user(sk, skb))
 		goto csum_error;
 
 	/*
 	 * RFC1323: H1. Apply PAWS check first.
 	 */
-	if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp &&
+	if (tcp_fast_parse_options(skb, th, tp) && tp->saw_tstamp &&
 	    tcp_paws_discard(tp, skb)) {
 		if (!th->rst) {
 			NET_INC_STATS_BH(PAWSEstabRejected);
-			tcp_send_ack(sk);
+			tcp_send_dupack(sk, skb);
 			goto discard;
 		}
 		/* Resets are accepted even if PAWS failed.
@@ -2620,23 +3272,15 @@
 	 *	Standard slow path.
 	 */
 
-	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->rst)) {
 		/* 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,
 		 * an acknowledgment should be sent in reply (unless the RST bit
 		 * is set, if so drop the segment and return)".
 		 */
-		if (th->rst)
-			goto discard;
-		if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
-			SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
-				   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-				   tp->rcv_wup, tp->rcv_wnd);
-		}
-		tcp_enter_quickack_mode(tp);
-		tcp_send_ack(sk);
-		NET_INC_STATS_BH(DelayedACKLost);
+		if (!th->rst)
+			tcp_send_dupack(sk, skb);
 		goto discard;
 	}
 
@@ -2645,378 +3289,43 @@
 		goto discard;
 	}
 
-	if (tp->saw_tstamp) {
-		tcp_replace_ts_recent(sk, tp,
-				      TCP_SKB_CB(skb)->seq);
-	}
+	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
 
 	if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
-		SOCK_DEBUG(sk, "syn in established state\n");
 		TCP_INC_STATS_BH(TcpInErrs);
+		NET_INC_STATS_BH(TCPAbortOnSyn);
 		tcp_reset(sk);
 		return 1;
 	}
 
 step5:
 	if(th->ack)
-		tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len);
-	
+		tcp_ack(sk, skb, FLAG_SLOWPATH);
+
 	/* Process urgent data. */
 	tcp_urg(sk, th, len);
 
 	/* step 7: process the segment text */
 	tcp_data(skb, sk, len);
 
-	/* Be careful, tcp_data() may have put this into TIME_WAIT. */
-	if(sk->state != TCP_CLOSE) {
-		tcp_data_snd_check(sk);
-		tcp_ack_snd_check(sk);
-		if (tp->sorry)
-			tcp_new_space(sk);
-	}
-
+	tcp_data_snd_check(sk);
+	tcp_ack_snd_check(sk);
 	return 0;
 
 csum_error:
 	TCP_INC_STATS_BH(TcpInErrs);
 
 discard:
-	kfree_skb(skb);
+	__kfree_skb(skb);
 	return 0;
 }
 
-
-/* This is not only more efficient than what we used to do, it eliminates
- * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM
- *
- * Actually, we could lots of memory writes here. tp of listening
- * socket contains all necessary default parameters.
- */
-struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb)
-{
-	struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0);
-
-	if(newsk != NULL) {
-		struct tcp_opt *newtp;
-#ifdef CONFIG_FILTER
-		struct sk_filter *filter;
-#endif
-
-		memcpy(newsk, sk, sizeof(*newsk));
-		newsk->state = TCP_SYN_RECV;
-
-		/* SANITY */
-		newsk->pprev = NULL;
-		newsk->prev = NULL;
-
-		/* Clone the TCP header template */
-		newsk->dport = req->rmt_port;
-
-		sock_lock_init(newsk);
-		bh_lock_sock(newsk);
-
-		atomic_set(&newsk->rmem_alloc, 0);
-		skb_queue_head_init(&newsk->receive_queue);
-		atomic_set(&newsk->wmem_alloc, 0);
-		skb_queue_head_init(&newsk->write_queue);
-		atomic_set(&newsk->omem_alloc, 0);
-
-		newsk->done = 0;
-		newsk->proc = 0;
-		newsk->backlog.head = newsk->backlog.tail = NULL;
-		skb_queue_head_init(&newsk->error_queue);
-		newsk->write_space = tcp_write_space;
-#ifdef CONFIG_FILTER
-		if ((filter = newsk->filter) != NULL)
-			sk_filter_charge(newsk, filter);
-#endif
-
-		/* Now setup tcp_opt */
-		newtp = &(newsk->tp_pinfo.af_tcp);
-		newtp->pred_flags = 0;
-		newtp->rcv_nxt = req->rcv_isn + 1;
-		newtp->snd_nxt = req->snt_isn + 1;
-		newtp->snd_una = req->snt_isn + 1;
-		newtp->snd_sml = req->snt_isn + 1;
-
-		tcp_delack_init(newtp);
-		if (skb->len >= 536)
-			newtp->ack.last_seg_size = skb->len;
-
-		tcp_prequeue_init(newtp);
-
-		newtp->snd_wl1 = req->rcv_isn;
-		newtp->snd_wl2 = req->snt_isn;
-
-		newtp->retransmits = 0;
-		newtp->backoff = 0;
-		newtp->srtt = 0;
-		newtp->mdev = TCP_TIMEOUT_INIT;
-		newtp->rto = TCP_TIMEOUT_INIT;
-
-		newtp->packets_out = 0;
-		newtp->fackets_out = 0;
-		newtp->retrans_out = 0;
-		newtp->snd_ssthresh = 0x7fffffff;
-
-		/* So many TCP implementations out there (incorrectly) count the
-		 * initial SYN frame in their delayed-ACK and congestion control
-		 * algorithms that we must have the following bandaid to talk
-		 * efficiently to them.  -DaveM
-		 */
-		newtp->snd_cwnd = 2;
-		newtp->snd_cwnd_cnt = 0;
-		newtp->high_seq = 0;
-
-		newtp->dup_acks = 0;
-		tcp_init_xmit_timers(newsk);
-		skb_queue_head_init(&newtp->out_of_order_queue);
-		newtp->send_head = newtp->retrans_head = NULL;
-		newtp->rcv_wup = req->rcv_isn + 1;
-		newtp->write_seq = req->snt_isn + 1;
-		newtp->copied_seq = req->rcv_isn + 1;
-
-		newtp->saw_tstamp = 0;
-
-		newtp->probes_out = 0;
-		newtp->num_sacks = 0;
-		newtp->syn_seq = req->rcv_isn;
-		newtp->fin_seq = req->rcv_isn;
-		newtp->urg_data = 0;
-		newtp->listen_opt = NULL;
-		newtp->accept_queue = newtp->accept_queue_tail = NULL;
-		/* Deinitialize syn_wait_lock to trap illegal accesses. */
-		memset(&newtp->syn_wait_lock, 0, sizeof(newtp->syn_wait_lock));
-
-		/* Back to base struct sock members. */
-		newsk->err = 0;
-		newsk->priority = 0;
-		atomic_set(&newsk->refcnt, 1);
-#ifdef INET_REFCNT_DEBUG
-		atomic_inc(&inet_sock_nr);
-#endif
-
-		if (newsk->keepopen)
-			tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp));
-		newsk->socket = NULL;
-		newsk->sleep = NULL;
-
-		newtp->tstamp_ok = req->tstamp_ok;
-		if((newtp->sack_ok = req->sack_ok) != 0)
-			newtp->num_sacks = 0;
-		newtp->window_clamp = req->window_clamp;
-		newtp->rcv_wnd = req->rcv_wnd;
-		newtp->wscale_ok = req->wscale_ok;
-		if (newtp->wscale_ok) {
-			newtp->snd_wscale = req->snd_wscale;
-			newtp->rcv_wscale = req->rcv_wscale;
-		} else {
-			newtp->snd_wscale = newtp->rcv_wscale = 0;
-			newtp->window_clamp = min(newtp->window_clamp,65535);
-		}
-		newtp->snd_wnd = ntohs(skb->h.th->window) << newtp->snd_wscale;
-		newtp->max_window = newtp->snd_wnd;
-
-		if (newtp->tstamp_ok) {
-			newtp->ts_recent = req->ts_recent;
-			newtp->ts_recent_stamp = xtime.tv_sec;
-			newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
-		} else {
-			newtp->ts_recent_stamp = 0;
-			newtp->tcp_header_len = sizeof(struct tcphdr);
-		}
-		newtp->mss_clamp = req->mss;
-	}
-	return newsk;
-}
-
-/* 
- *	Process an incoming packet for SYN_RECV sockets represented
- *	as an open_request.
- */
-
-struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
-			   struct open_request *req,
-			   struct open_request **prev)
-{
-	struct tcphdr *th = skb->h.th;
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
-	int paws_reject = 0;
-	struct tcp_opt ttp;
-	struct sock *child;
-
-	ttp.saw_tstamp = 0;
-	if (th->doff > (sizeof(struct tcphdr)>>2)) {
-		tcp_parse_options(NULL, th, &ttp, 0);
-
-		if (ttp.saw_tstamp) {
-			ttp.ts_recent = req->ts_recent;
-			/* We do not store true stamp, but it is not required,
-			 * it can be estimated (approximately)
-			 * from another data.
-			 */
-			ttp.ts_recent_stamp = xtime.tv_sec - ((TCP_TIMEOUT_INIT/HZ)<<req->retrans);
-			paws_reject = tcp_paws_check(&ttp, th->rst);
-		}
-	}
-
-	/* Check for pure retransmited SYN. */
-	if (TCP_SKB_CB(skb)->seq == req->rcv_isn &&
-	    flg == TCP_FLAG_SYN &&
-	    !paws_reject) {
-		/*
-		 * RFC793 draws (Incorrectly! It was fixed in RFC1122)
-		 * this case on figure 6 and figure 8, but formal
-		 * protocol description says NOTHING.
-		 * To be more exact, it says that we should send ACK,
-		 * because this segment (at least, if it has no data)
-		 * is out of window.
-		 *
-		 *  CONCLUSION: RFC793 (even with RFC1122) DOES NOT
-		 *  describe SYN-RECV state. All the description
-		 *  is wrong, we cannot believe to it and should
-		 *  rely only on common sense and implementation
-		 *  experience.
-		 *
-		 * Enforce "SYN-ACK" according to figure 8, figure 6
-		 * of RFC793, fixed by RFC1122.
-		 */
-		req->class->rtx_syn_ack(sk, req, NULL);
-		return NULL;
-	}
-
-	/* Further reproduces section "SEGMENT ARRIVES"
-	   for state SYN-RECEIVED of RFC793.
-	   It is broken, however, it does not work only
-	   when SYNs are crossed, which is impossible in our
-	   case.
-
-	   But generally, we should (RFC lies!) to accept ACK
-	   from SYNACK both here and in tcp_rcv_state_process().
-	   tcp_rcv_state_process() does not, hence, we do not too.
-
-	   Note that the case is absolutely generic:
-	   we cannot optimize anything here without
-	   violating protocol. All the checks must be made
-	   before attempt to create socket.
-	 */
-
-	/* RFC793: "first check sequence number". */
-
-	if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-					  req->rcv_isn+1, req->rcv_isn+1+req->rcv_wnd)) {
-		/* Out of window: send ACK and drop. */
-		if (!(flg & TCP_FLAG_RST))
-			req->class->send_ack(skb, req);
-		if (paws_reject)
-			NET_INC_STATS_BH(PAWSEstabRejected);
-		return NULL;
-	}
-
-	/* In sequence, PAWS is OK. */
-
-	if (ttp.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1))
-		req->ts_recent = ttp.rcv_tsval;
-
-	if (TCP_SKB_CB(skb)->seq == req->rcv_isn) {
-		/* Truncate SYN, it is out of window starting
-		   at req->rcv_isn+1. */
-		flg &= ~TCP_FLAG_SYN;
-	}
-
-	/* RFC793: "second check the RST bit" and
-	 *	   "fourth, check the SYN bit"
-	 */
-	if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
-		goto embryonic_reset;
-
-	/* RFC793: "fifth check the ACK field" */
-
-	if (!(flg & TCP_FLAG_ACK))
-		return NULL;
-
-	/* Invalid ACK: reset will be sent by listening socket */
-	if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
-		return sk;
-	/* Also, it would be not so bad idea to check rcv_tsecr, which
-	 * is essentially ACK extension and too early or too late values
-	 * should cause reset in unsynchronized states.
-	 */
-
-	/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
-	if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) {
-		req->acked = 1;
-		return NULL;
-	}
-
-	/* OK, ACK is valid, create big socket and
-	 * feed this segment to it. It will repeat all
-	 * the tests. THIS SEGMENT MUST MOVE SOCKET TO
-	 * ESTABLISHED STATE. If it will be dropped after
-	 * socket is created, wait for troubles.
-	 */
-	child = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
-	if (child == NULL)
-		goto listen_overflow;
-
-	tcp_synq_unlink(tp, req, prev);
-	tcp_synq_removed(sk, req);
-
-	tcp_acceptq_queue(sk, req, child);
-	return child;
-
-listen_overflow:
-	if (!sysctl_tcp_abort_on_overflow) {
-		req->acked = 1;
-		return NULL;
-	}
-
-embryonic_reset:
-	NET_INC_STATS_BH(EmbryonicRsts);
-	if (!(flg & TCP_FLAG_RST))
-		req->class->send_reset(skb);
-
-	tcp_synq_drop(sk, req, prev);
-	return NULL;
-}
-
-/*
- * Queue segment on the new socket if the new socket is active,
- * otherwise we just shortcircuit this and continue with
- * the new socket.
- */
-
-int tcp_child_process(struct sock *parent, struct sock *child,
-		      struct sk_buff *skb)
-{
-	int ret = 0;
-	int state = child->state;
-
-	if (child->lock.users == 0) {
-		ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len);
-
-		/* Wakeup parent, send SIGIO */
-		if (state == TCP_SYN_RECV && child->state != state)
-			parent->data_ready(parent, 0);
-	} else {
-		/* Alas, it is possible again, because we do lookup
-		 * in main socket hash table and lock on listening
-		 * socket does not protect us more.
-		 */
-		sk_add_backlog(child, skb);
-	}
-
-	bh_unlock_sock(child);
-	return ret;
-}
-
 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
 					 struct tcphdr *th, unsigned len)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-	tcp_parse_options(sk, th, tp, 0);
+	tcp_parse_options(skb, tp);
 
 	if (th->ack) {
 		/* rfc793:
@@ -3027,24 +3336,12 @@
 		 *        a reset (unless the RST bit is set, if so drop
 		 *        the segment and return)"
 		 *
-		 *  I cite this place to emphasize one essential
-		 *  detail, this check is different of one
-		 *  in established state: SND.UNA <= SEG.ACK <= SND.NXT.
-		 *  SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT,
-		 *  because we have no previous data sent before SYN.
-		 *                                        --ANK(990513)
-		 *
 		 *  We do not send data with SYN, so that RFC-correct
 		 *  test reduces to:
 		 */
 		if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
 			return 1;
 
-		/* Check not from any RFC, but it is evident consequence
-		 * of combining PAWS and usual SYN-SENT logic: ACK _is_
-		 * checked in SYN-SENT unlike another states, hence
-		 * echoed tstamp must be checked too.
-		 */
 		if (tp->saw_tstamp) {
 			if (tp->rcv_tsecr == 0) {
 				/* Workaround for bug in linux-2.1 and early
@@ -3055,13 +3352,9 @@
 				tp->saw_tstamp = 0;
 
 				/* But do not forget to store peer's timestamp! */
-				if (th->syn) {
-					tp->ts_recent = tp->rcv_tsval;
-					tp->ts_recent_stamp = xtime.tv_sec;
-				}
-			} else if ((__s32)(tp->rcv_tsecr - tcp_time_stamp) > 0 ||
-				   (__s32)(tp->rcv_tsecr - tp->syn_stamp) < 0) {
-				NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "TCP: synsent reject.\n"));
+				if (th->syn)
+					tcp_store_ts_recent(tp);
+			} else if (!between(tp->rcv_tsecr, tp->retrans_stamp, tcp_time_stamp)) {
 				NET_INC_STATS_BH(PAWSActiveRejected);
 				return 1;
 			}
@@ -3095,30 +3388,12 @@
 		 *    are acceptable then ...
 		 *    (our SYN has been ACKed), change the connection
 		 *    state to ESTABLISHED..."
-		 *
-		 * Do you see? SYN-less ACKs in SYN-SENT state are
-		 * completely ignored.
-		 *
-		 * The bug causing stalled SYN-SENT sockets
-		 * was here: tcp_ack advanced snd_una and canceled
-		 * retransmit timer, so that bare ACK received
-		 * in SYN-SENT state (even with invalid ack==ISS,
-		 * because tcp_ack check is too weak for SYN-SENT)
-		 * causes moving socket to invalid semi-SYN-SENT,
-		 * semi-ESTABLISHED state and connection hangs.
-		 *                                     --ANK (990514)
-		 *
-		 * Bare ACK is valid, however.
-		 * Actually, RFC793 requires to send such ACK
-		 * in reply to any out of window packet.
-		 * It is wrong, but Linux also send such
-		 * useless ACKs sometimes.
-		 *                                     --ANK (990724)
 		 */
 
+		TCP_ECN_rcv_synack(tp, th);
+
 		tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-		tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
-			TCP_SKB_CB(skb)->ack_seq, len);
+		tcp_ack(sk, skb, FLAG_SLOWPATH);
 
 		/* Ok.. it's good. Set up sequence numbers and
 		 * move to established.
@@ -3130,12 +3405,10 @@
 		 * never scaled.
 		 */
 		tp->snd_wnd = ntohs(th->window);
-		tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-		tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+		tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq);
+		tp->syn_seq = TCP_SKB_CB(skb)->seq;
 		tp->fin_seq = TCP_SKB_CB(skb)->seq;
 
-		tcp_set_state(sk, TCP_ESTABLISHED);
-
 		if (tp->wscale_ok == 0) {
 			tp->snd_wscale = tp->rcv_wscale = 0;
 			tp->window_clamp = min(tp->window_clamp,65535);
@@ -3144,12 +3417,14 @@
 		if (tp->tstamp_ok) {
 			tp->tcp_header_len =
 				sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+			tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
 		} else
 			tp->tcp_header_len = sizeof(struct tcphdr);
-		if (tp->saw_tstamp) {
-			tp->ts_recent = tp->rcv_tsval;
-			tp->ts_recent_stamp = xtime.tv_sec;
-		}
+		if (tp->saw_tstamp)
+			tcp_store_ts_recent(tp);
+		if (tp->sack_ok && sysctl_tcp_fack)
+			tp->sack_ok |= 2;
+
 		tcp_sync_mss(sk, tp->pmtu_cookie);
 		tcp_initialize_rcv_mss(sk);
 		tcp_init_metrics(sk);
@@ -3158,15 +3433,24 @@
 		if (sk->keepopen)
 			tcp_reset_keepalive_timer(sk, keepalive_time_when(tp));
 
+		if (tp->snd_wscale == 0)
+			__tcp_fast_path_on(tp, tp->snd_wnd);
+		else
+			tp->pred_flags = 0;
+
+		/* Remember, tcp_poll() does not lock socket!
+		 * Change state from SYN-SENT only after copied_seq
+		 * is initilized. */
 		tp->copied_seq = tp->rcv_nxt;
-		__tcp_fast_path_on(tp, tp->snd_wnd);
+		mb();
+		tcp_set_state(sk, TCP_ESTABLISHED);
 
 		if(!sk->dead) {
 			sk->state_change(sk);
 			sk_wake_async(sk, 0, POLL_OUT);
 		}
 
-		if (tp->write_pending) {
+		if (tp->write_pending || tp->defer_accept) {
 			/* Save one ACK. Data will be ready after
 			 * several ticks, if write_pending is set.
 			 *
@@ -3174,11 +3458,10 @@
 			 * look so _wonderfully_ clever, that I was not able
 			 * to stand against the temptation 8)     --ANK
 			 */
-			tp->ack.pending = 1;
+			tcp_schedule_ack(tp);
 			tp->ack.lrcvtime = tcp_time_stamp;
 			tcp_enter_quickack_mode(tp);
-			tp->ack.ato = TCP_ATO_MIN;
-			tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MIN);
+			tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX);
 			goto discard;
 		} else {
 			tcp_send_ack(sk);
@@ -3204,20 +3487,12 @@
 
 	if (th->syn) {
 		/* We see SYN without ACK. It is attempt of
-		 *  simultaneous connect with crossed SYNs.
-		 *
-		 * The previous version of the code
-		 * checked for "connecting to self"
-		 * here. that check is done now in
-		 * tcp_connect.
-		 *
-		 * RED-PEN: BTW, it does not. 8)
+		 * simultaneous connect with crossed SYNs.
+		 * Particularly, it can be connect to self.
 		 */
 		tcp_set_state(sk, TCP_SYN_RECV);
-		if (tp->saw_tstamp) {
-			tp->ts_recent = tp->rcv_tsval;
-			tp->ts_recent_stamp = xtime.tv_sec;
-		}
+		if (tp->saw_tstamp)
+			tcp_store_ts_recent(tp);
 
 		tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
 		tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
@@ -3232,6 +3507,8 @@
 		tcp_sync_mss(sk, tp->pmtu_cookie);
 		tcp_initialize_rcv_mss(sk);
 
+		TCP_ECN_rcv_syn(tp, th);
+
 		tcp_send_synack(sk);
 #if 0
 		/* Note, we could accept data and URG from this segment.
@@ -3251,7 +3528,7 @@
 	 */
 
 discard:
-	kfree_skb(skb);
+	__kfree_skb(skb);
 	return 0;
 }
 
@@ -3273,35 +3550,6 @@
 
 	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.
-		 */
-
-		/* 1. The socket may be moved to TIME-WAIT state.
-		   2. While this socket was locked, another socket
-		      with the same identity could be created.
-		   3. To continue?
-
-		   CONCLUSION: discard and only discard!
-
-		   Alternative would be relookup and recurse into tcp_v?_rcv
-		   (not *_do_rcv) to work with timewait and listen states
-		   correctly.
-		 */
 		goto discard;
 
 	case TCP_LISTEN:
@@ -3340,56 +3588,20 @@
 		goto step6;
 	}
 
-	/*   Parse the tcp_options present on this header.
-	 *   By this point we really only expect timestamps.
-	 *   Note that this really has to be here and not later for PAWS
-	 *   (RFC1323) to work.
-	 */
-	if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp &&
+	if (tcp_fast_parse_options(skb, th, tp) && tp->saw_tstamp &&
 	    tcp_paws_discard(tp, skb)) {
 		if (!th->rst) {
-			tcp_send_ack(sk);
+			NET_INC_STATS_BH(PAWSEstabRejected);
+			tcp_send_dupack(sk, skb);
 			goto discard;
 		}
 		/* Reset is accepted even if it did not pass PAWS. */
 	}
 
-	/* 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).
-	 *
-	 * RED-PEN. Seems, the above is not true.
-	 * If at least one end is RFC compliant, it will send ACK to
-	 * out of window FIN and, hence, move peer to TIME-WAIT.
-	 * I comment out this line. --ANK
-	 *
-	 * RED-PEN. DANGER! tcp_sequence check rejects also SYN-ACKs
-	 * received in SYN-RECV. The problem is that description of
-	 * segment processing in SYN-RECV state in RFC792 is WRONG.
-	 * Correct check would accept ACK from this SYN-ACK, see
-	 * figures 6 and 8 (fixed by RFC1122). Compare this
-	 * to problem with FIN, they smell similarly. --ANK
-	 */
-
 	/* step 1: check sequence number */
-	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)
-#if 0
-	    && !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)
-#endif
-	    ) {
-		if (!th->rst) {
-			NET_INC_STATS_BH(DelayedACKLost);
-			tcp_enter_quickack_mode(tp);
-			tcp_send_ack(sk);
-		}
+	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, th->rst)) {
+		if (!th->rst)
+			tcp_send_dupack(sk, skb);
 		goto discard;
 	}
 
@@ -3399,10 +3611,7 @@
 		goto discard;
 	}
 
-	if (tp->saw_tstamp) {
-		tcp_replace_ts_recent(sk, tp,
-				      TCP_SKB_CB(skb)->seq);
-	}
+	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
 
 	/* step 3: check security and precedence [ignored] */
 
@@ -3423,47 +3632,51 @@
 	 */
 
 	if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
+		NET_INC_STATS_BH(TCPAbortOnSyn);
 		tcp_reset(sk);
 		return 1;
 	}
 
 	/* step 5: check the ACK field */
 	if (th->ack) {
-		int acceptable = tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
-					 TCP_SKB_CB(skb)->ack_seq, len);
+		int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
 
 		switch(sk->state) {
 		case TCP_SYN_RECV:
 			if (acceptable) {
-				tcp_set_state(sk, TCP_ESTABLISHED);
 				tp->copied_seq = tp->rcv_nxt;
+				mb();
+				tcp_set_state(sk, TCP_ESTABLISHED);
 
 				/* Note, that this wakeup is only for marginal
 				 * crossed SYN case. Passively open sockets
 				 * are not waked up, because sk->sleep == NULL
 				 * and sk->socket == NULL.
 				 */
-				if (!sk->dead) {
+				if (sk->socket) {
 					sk->state_change(sk);
 					sk_wake_async(sk,0,POLL_OUT);
 				}
 
 				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
 				tp->snd_wnd = ntohs(th->window) << tp->snd_wscale;
-				tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-				tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+				tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq);
 
 				/* tcp_ack considers this ACK as duplicate
 				 * and does not calculate rtt.
 				 * Fix it at least with timestamps.
 				 */
 				if (tp->saw_tstamp && !tp->srtt)
-					tcp_ack_saw_tstamp(sk, tp, 0, 0, FLAG_SYN_ACKED);
+					tcp_ack_saw_tstamp(tp);
+
+				if (tp->tstamp_ok)
+					tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
 
 				tcp_init_metrics(sk);
+				tcp_initialize_rcv_mss(sk);
+				tcp_init_buffer_space(sk);
 				tcp_fast_path_on(tp);
 			} else {
-				SOCK_DEBUG(sk, "bad ack\n");
 				return 1;
 			}
 			break;
@@ -3484,6 +3697,7 @@
 					    (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
 					     after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) {
 						tcp_done(sk);
+						NET_INC_STATS_BH(TCPAbortOnData);
 						return 1;
 					}
 
@@ -3543,6 +3757,7 @@
 		if (sk->shutdown & RCV_SHUTDOWN) {
 			if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
 			    after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
+				NET_INC_STATS_BH(TCPAbortOnData);
 				tcp_reset(sk);
 				return 1;
 			}
@@ -3558,13 +3773,11 @@
 	if (sk->state != TCP_CLOSE) {
 		tcp_data_snd_check(sk);
 		tcp_ack_snd_check(sk);
-		if (tp->sorry)
-			tcp_new_space(sk);
 	}
 
 	if (!queued) { 
 discard:
-		kfree_skb(skb);
+		__kfree_skb(skb);
 	}
 	return 0;
 }

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