patch-2.3.15 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.3.14/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.170 1999/07/02 11:26:28 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.172 1999/08/23 06:30:35 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -61,6 +61,7 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <net/tcp.h>
+#include <net/inet_common.h>
 #include <linux/ipsec.h>
 
 #ifdef CONFIG_SYSCTL
@@ -70,6 +71,7 @@
 #endif
 
 extern int sysctl_tcp_fin_timeout;
+extern int sysctl_tcp_keepalive_time;
 
 /* These are on by default so the code paths get tested.
  * For the final 2.2 this may be undone at our discretion. -DaveM
@@ -81,6 +83,7 @@
 int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_stdurg;
 int sysctl_tcp_rfc1337;
+int sysctl_tcp_tw_recycle;
 
 static int prune_queue(struct sock *sk);
 
@@ -133,7 +136,7 @@
 	/* Tiny-grams with PSH set artifically deflate our
 	 * ato measurement, but with a lower bound.
 	 */
-	if(th->psh && (skb->len < (tp->mss_cache >> 1))) {
+	if(th->psh && (skb->len < (tp->rcv_mss >> 1))) {
 		/* Preserve the quickack state. */
 		if((tp->ato & 0x7fffffff) > HZ/50)
 			tp->ato = ((tp->ato & 0x80000000) |
@@ -187,6 +190,9 @@
 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.
+	 */
 	tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1));
 }
  
@@ -209,42 +215,196 @@
 		tp->rto = HZ/5;
 }
 
-/* WARNING: this must not be called if tp->saw_timestamp was false. */
-extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp,
-					     __u32 start_seq, __u32 end_seq)
-{
-	/* From draft-ietf-tcplw-high-performance: the correct
-	 * test is last_ack_sent <= end_seq.
-	 * (RFC1323 stated last_ack_sent < end_seq.)
+/* 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)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct dst_entry *dst = __sk_dst_get(sk);
+
+	if (dst) {
+		int m;
+
+		if (tp->backoff || !tp->srtt) {
+			/* This session failed to estimate rtt. Why?
+			 * Probably, no packets returned in time.
+			 * Reset our results.
+			 */
+			if (!(dst->mxlock&(1<<RTAX_RTT)))
+				dst->rtt = 0;
+			return;
+		}
+
+		dst_confirm(dst);
+
+		m = dst->rtt - tp->srtt;
+
+		/* If newly calculated rtt larger than stored one,
+		 * store new one. Otherwise, use EWMA. Remember,
+		 * rtt overestimation is always better than underestimation.
+		 */
+		if (!(dst->mxlock&(1<<RTAX_RTT))) {
+			if (m <= 0)
+				dst->rtt = tp->srtt;
+			else
+				dst->rtt -= (m>>3);
+		}
+
+		if (!(dst->mxlock&(1<<RTAX_RTTVAR))) {
+			if (m < 0)
+				m = -m;
+
+			/* Scale deviation to rttvar fixed point */
+			m >>= 1;
+			if (m < tp->mdev)
+				m = tp->mdev;
+
+			if (m >= dst->rttvar)
+				dst->rttvar = m;
+			else
+				dst->rttvar -= (dst->rttvar - m)>>2;
+		}
+
+		if (tp->snd_ssthresh == 0x7FFFFFFF) {
+			/* Slow start still did not finish. */
+			if (dst->ssthresh &&
+			    !(dst->mxlock&(1<<RTAX_SSTHRESH)) &&
+			    tp->snd_cwnd > dst->ssthresh)
+				dst->ssthresh = tp->snd_cwnd;
+			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) {
+			/* Cong. avoidance phase, cwnd is reliable. */
+			if (!(dst->mxlock&(1<<RTAX_SSTHRESH)))
+				dst->ssthresh = tp->snd_cwnd;
+			if (!(dst->mxlock&(1<<RTAX_CWND)))
+				dst->cwnd = (dst->cwnd + tp->snd_cwnd)>>1;
+		} else {
+			/* Else slow start did not finish, cwnd is non-sense,
+			   ssthresh may be also invalid.
+			 */
+			if (!(dst->mxlock&(1<<RTAX_CWND)))
+				dst->cwnd = (dst->cwnd + tp->snd_ssthresh)>>1;
+			if (dst->ssthresh &&
+			    !(dst->mxlock&(1<<RTAX_SSTHRESH)) &&
+			    tp->snd_ssthresh > dst->ssthresh)
+				dst->ssthresh = tp->snd_ssthresh;
+		}
+	}
+}
+
+/* Initialize metrics on socket. */
+
+static void tcp_init_metrics(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct dst_entry *dst = __sk_dst_get(sk);
+
+	if (dst == NULL)
+		goto reset;
+
+	dst_confirm(dst);
+
+	if (dst->rtt == 0)
+		goto reset;
+
+	if (!tp->srtt || !tp->saw_tstamp)
+		goto reset;
+
+	/* Initial rtt is determined from SYN,SYN-ACK.
+	 * The segment is small and rtt may appear much
+	 * less than real one. Use per-dst memory
+	 * to make it more realistic.
 	 *
-	 * HOWEVER: The current check contradicts the draft statements.
-	 * It has been done for good reasons.
-	 * The implemented check improves security and eliminates
-	 * unnecessary RTT overestimation.
-	 *		1998/06/27  Andrey V. Savochkin <saw@msu.ru>
+	 * A bit of theory. RTT is time passed after "normal" sized packet
+	 * is sent until it is ACKed. In normal curcumstances sending small
+	 * packets force peer to delay ACKs and calculation is correct too.
+	 * The algorithm is adaptive and, provided we follow specs, it
+	 * NEVER underestimate RTT. BUT! If peer tries to make some clever
+	 * tricks sort of "quick acks" for time long enough to decrease RTT
+	 * to low value, and then abruptly stops to do it and starts to delay
+	 * ACKs, wait for troubles.
+	 */
+	if (dst->rtt > tp->srtt)
+		tp->srtt = dst->rtt;
+	if (dst->rttvar > tp->mdev)
+		tp->mdev = dst->rttvar;
+	tcp_set_rto(tp);
+	tcp_bound_rto(tp);
+
+	if (dst->mxlock&(1<<RTAX_CWND))
+		tp->snd_cwnd_clamp = dst->cwnd;
+	if (dst->ssthresh) {
+		tp->snd_ssthresh = dst->ssthresh;
+		if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
+			tp->snd_ssthresh = tp->snd_cwnd_clamp;
+	}
+	return;
+
+
+reset:
+	/* Play conservative. If timestamps are not
+	 * supported, TCP will fail to recalculate correct
+	 * rtt, if initial rto is too small. FORGET ALL AND RESET!
 	 */
-	if (!before(end_seq, tp->last_ack_sent - sk->rcvbuf) &&
-	    !after(start_seq, tp->rcv_wup + tp->rcv_wnd)) {
+	if (!tp->saw_tstamp && tp->srtt) {
+		tp->srtt = 0;
+		tp->mdev = TCP_TIMEOUT_INIT;
+		tp->rto = TCP_TIMEOUT_INIT;
+	}
+}
+
+#define PAWS_24DAYS	(60 * 60 * 24 * 24)
+
+
+/* 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)
+{
+	if (!after(seq, tp->last_ack_sent)) {
 		/* 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((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) {
+
+		if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0 ||
+		   xtime.tv_sec >= tp->ts_recent_stamp + PAWS_24DAYS) {
 			tp->ts_recent = tp->rcv_tsval;
-			tp->ts_recent_stamp = tcp_time_stamp;
+			tp->ts_recent_stamp = xtime.tv_sec;
 		}
 	}
 }
 
-#define PAWS_24DAYS	(HZ * 60 * 60 * 24 * 24)
-
-extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct tcphdr *th, unsigned len)
+extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct sk_buff *skb)
 {
-	/* ts_recent must be younger than 24 days */
-	return (((s32)(tcp_time_stamp - tp->ts_recent_stamp) >= PAWS_24DAYS) ||
-		(((s32)(tp->rcv_tsval - tp->ts_recent) < 0) &&
-		 /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM */
-		 (len != (th->doff * 4))));
+	return ((s32)(tp->rcv_tsval - tp->ts_recent) < 0 &&
+		xtime.tv_sec < tp->ts_recent_stamp + PAWS_24DAYS
+
+		 /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
+
+		    I cannot see quitely as all the idea behind PAWS
+		    is destroyed 8)
+
+		    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));
 }
 
 
@@ -283,13 +443,14 @@
 		case TCP_CLOSE_WAIT:
 			sk->err = EPIPE;
 			break;
+		case TCP_CLOSE:
+			return;
 		default:
 			sk->err = ECONNRESET;
 	};
 	tcp_set_state(sk, TCP_CLOSE);
-	sk->shutdown = SHUTDOWN_MASK;
-	if (!sk->dead) 
-		sk->state_change(sk);
+	tcp_clear_xmit_timers(sk);
+	tcp_done(sk);
 }
 
 /* This tags the retransmission queue when SACKs arrive. */
@@ -345,7 +506,6 @@
 {
 	unsigned char *ptr;
 	int length=(th->doff*4)-sizeof(struct tcphdr);
-	int saw_mss = 0;
 
 	ptr = (unsigned char *)(th + 1);
 	tp->saw_tstamp = 0;
@@ -370,11 +530,11 @@
 				case TCPOPT_MSS:
 					if(opsize==TCPOLEN_MSS && th->syn) {
 						u16 in_mss = ntohs(*(__u16 *)ptr);
-						if (in_mss == 0)
-							in_mss = 536;
-						if (tp->mss_clamp > in_mss)
+						if (in_mss) {
+							if (tp->user_mss && tp->user_mss < in_mss)
+								in_mss = tp->user_mss;
 							tp->mss_clamp = in_mss;
-						saw_mss = 1;
+						}
 					}
 					break;
 				case TCPOPT_WINDOW:
@@ -428,8 +588,6 @@
 	  			length-=opsize;
 	  	};
 	}
-	if(th->syn && saw_mss == 0)
-		tp->mss_clamp = 536;
 }
 
 /* Fast parse options. This hopes to only see timestamps.
@@ -448,8 +606,10 @@
 		if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
 					     | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
 			tp->saw_tstamp = 1;
-			tp->rcv_tsval = ntohl(*++ptr);
-			tp->rcv_tsecr = ntohl(*++ptr);
+			++ptr;
+			tp->rcv_tsval = ntohl(*ptr);
+			++ptr;
+			tp->rcv_tsecr = ntohl(*ptr);
 			return 1;
 		}
 	}
@@ -461,6 +621,7 @@
 #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.		*/
 
 static __inline__ void clear_fast_retransmit(struct tcp_opt *tp)
 {
@@ -498,6 +659,8 @@
 			tp->dup_acks++;
 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
                                 tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+				if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
+					tp->snd_ssthresh = tp->snd_cwnd_clamp;
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3);
 				tp->high_seq = tp->snd_nxt;
 				if(!tp->fackets_out)
@@ -595,11 +758,12 @@
 		 * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
 		 */
 		if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-			tp->snd_cwnd++;
+			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+				tp->snd_cwnd++;
 			tp->snd_cwnd_cnt=0;
 		} else
 			tp->snd_cwnd_cnt++;
-        }       
+        }
 }
 
 /* Remove acknowledged frames from the retransmission queue. */
@@ -645,9 +809,10 @@
 			if(tp->fackets_out)
 				tp->fackets_out--;
 		} else {
+			acked |= FLAG_SYN_ACKED;
 			/* This is pure paranoia. */
 			tp->retrans_head = NULL;
-		}		
+		}
 		tp->packets_out--;
 		*seq = scb->seq;
 		*seq_rtt = now - scb->when;
@@ -721,7 +886,7 @@
 	 * See draft-ietf-tcplw-high-performance-00, section 3.3.
 	 * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
 	 */
-	if (!(flag & FLAG_DATA_ACKED))
+	if (!(flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED)))
 		return;
 
 	seq_rtt = tcp_time_stamp - tp->rcv_tsecr;
@@ -856,7 +1021,7 @@
 			 * where the network delay has increased suddenly.
 			 * I.e. Karn's algorithm. (SIGCOMM '87, p5.)
 			 */
-			if (flag & FLAG_DATA_ACKED) {
+			if (flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED)) {
 				if(!(flag & FLAG_RETRANS_DATA_ACKED)) {
 					tp->backoff = 0;
 					tcp_rtt_estimator(tp, seq_rtt);
@@ -910,37 +1075,50 @@
 }
 
 /* New-style handling of TIME_WAIT sockets. */
-extern void tcp_tw_schedule(struct tcp_tw_bucket *tw);
-extern void tcp_tw_reschedule(struct tcp_tw_bucket *tw);
-extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
 
 /* Must be called only from BH context. */
 void tcp_timewait_kill(struct tcp_tw_bucket *tw)
 {
-	struct tcp_bind_bucket *tb = tw->tb;
-
-	SOCKHASH_LOCK_WRITE_BH();
-
-	/* Disassociate with bind bucket. */
-	if(tw->bind_next)
-		tw->bind_next->bind_pprev = tw->bind_pprev;
-	*(tw->bind_pprev) = tw->bind_next;
-	if (tb->owners == NULL) {
-		if (tb->next)
-			tb->next->pprev = tb->pprev;
-		*(tb->pprev) = tb->next;
-		kmem_cache_free(tcp_bucket_cachep, tb);
-	}
+	struct tcp_ehash_bucket *ehead;
+	struct tcp_bind_hashbucket *bhead;
+	struct tcp_bind_bucket *tb;
 
 	/* 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) = tw->next;
+	tw->pprev = NULL;
+	write_unlock(&ehead->lock);
 
-	SOCKHASH_UNLOCK_WRITE_BH();
-
-	/* Ok, now free it up. */
-	kmem_cache_free(tcp_timewait_cachep, tw);
+	/* 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));
+	}
+#endif
+	tcp_tw_put(tw);
 }
 
 /* We come here as a special case from the AF specific TCP input processing,
@@ -949,9 +1127,36 @@
  * entire timeout period.  The only special cases are for BSD TIME_WAIT
  * reconnects and SYN/RST bits being set in the TCP header.
  */
-int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
-			       struct tcphdr *th, unsigned len)
+
+/* 
+ * * 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.
+ */
+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;
+
 	/*	RFC 1122:
 	 *	"When a connection is [...] on TIME-WAIT state [...]
 	 *	[a TCP] MAY accept a new SYN from the remote TCP to
@@ -965,58 +1170,101 @@
 	 *	(2)  returns to TIME-WAIT state if the SYN turns out 
 	 *	to be an old duplicate".
 	 */
-	if(th->syn && !th->rst && after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) {
-		struct sock *sk;
-		struct tcp_func *af_specific = tw->af_specific;
-		__u32 isn;
-		int ret;
 
-		isn = tw->rcv_nxt + 128000;
-		if(isn == 0)
-			isn++;
-		tcp_tw_deschedule(tw);
-		tcp_timewait_kill(tw);
-		sk = af_specific->get_sock(skb, th);
-		if(sk == NULL ||
-		   !ipsec_sk_policy(sk,skb))
-			return 0;
+	tp.saw_tstamp = 0;
+	if (th->doff > (sizeof(struct tcphdr)>>2) && tw->ts_recent_stamp) {
+		tcp_parse_options(NULL, th, &tp, 0);
+
+		paws_reject = tp.saw_tstamp &&
+			((s32)(tp.rcv_tsval - tw->ts_recent) < 0 &&
+			 xtime.tv_sec < tw->ts_recent_stamp + PAWS_24DAYS);
+	}
+
+	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) {
+#ifdef CONFIG_TCP_TW_RECYCLE
+			/* When recycling, always follow rfc1337,
+			 * but mark bucket as ready to recycling immediately.
+			 */
+			if (sysctl_tcp_tw_recycle) {
+				/* May kill it now. */
+				tw->rto = 0;
+				tw->ttd = jiffies;
+			} else
+#endif
+			/* 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) {
+				tcp_tw_deschedule(tw);
+				tcp_timewait_kill(tw);
+			}
+		} else {
+			tcp_tw_reschedule(tw);
+		}
 
-		bh_lock_sock(sk);
+		if (tp.saw_tstamp) {
+			tw->ts_recent = tp.rcv_tsval;
+			tw->ts_recent_stamp = xtime.tv_sec;
+		}
+		tcp_tw_put(tw);
+		return TCP_TW_SUCCESS;
+	}
 
-		/* Default is to discard the frame. */
-		ret = 0;
+	/* Out of window segment.
 
-		if(sk->lock.users)
-			goto out_unlock;
+	   All the segments are ACKed immediately.
 
-		skb_set_owner_r(skb, sk);
-		af_specific = sk->tp_pinfo.af_tcp.af_specific;
+	   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(af_specific->conn_request(sk, skb, isn) < 0)
-			ret = 1; /* Toss a reset back. */
-	out_unlock:
-		bh_unlock_sock(sk);
-		return ret;
+	if (th->syn && !th->rst && !th->ack && !paws_reject &&
+	    (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) ||
+	     (tp.saw_tstamp && tw->ts_recent != tp.rcv_tsval))) {
+		u32 isn = tw->snd_nxt + 2;
+		if (isn == 0)
+			isn++;
+		TCP_SKB_CB(skb)->when = isn;
+		return TCP_TW_SYN;
 	}
 
-	/* Check RST or SYN */
-	if(th->rst || th->syn) {
-		/* This is TIME_WAIT assasination, in two flavors.
-		 * Oh well... nobody has a sufficient solution to this
-		 * protocol bug yet.
+	if(!th->rst) {
+		/* In this case we must reset the TIMEWAIT timer.
+
+		   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.
 		 */
-		if(sysctl_tcp_rfc1337 == 0) {
-			tcp_tw_deschedule(tw);
-			tcp_timewait_kill(tw);
-		}
-		if(!th->rst)
-			return 1; /* toss a reset back */
-	} else {
-		/* In this case we must reset the TIMEWAIT timer. */
-		if(th->ack)
+		if (paws_reject || th->ack) {
 			tcp_tw_reschedule(tw);
+#ifdef CONFIG_TCP_TW_RECYCLE
+			tw->rto = min(120*HZ, tw->rto<<1);
+			tw->ttd = jiffies + tw->rto;
+#endif
+		}
+
+		/* Send ACK. Note, we do not put the bucket,
+		 * it will be released by caller.
+		 */
+		return TCP_TW_ACK;
 	}
-	return 0; /* Discard the frame. */
+	tcp_tw_put(tw);
+	return TCP_TW_SUCCESS;
 }
 
 /* Enter the time wait state.  This is always called from BH
@@ -1024,37 +1272,54 @@
  * relevant info into it from the SK, and mess with hash chains
  * and list linkage.
  */
-static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
+static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
 {
+	struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->hashent];
+	struct tcp_bind_hashbucket *bhead;
 	struct sock **head, *sktw;
 
-	/* Step 1: Remove SK from established hash. */
-	if(sk->next)
-		sk->next->pprev = sk->pprev;
-	*sk->pprev = sk->next;
-	sk->pprev = NULL;
-	tcp_reg_zap(sk);
-
-	/* Step 2: Put TW into bind hash where SK was. */
-	tw->tb = (struct tcp_bind_bucket *)sk->prev;
-	if((tw->bind_next = sk->bind_next) != NULL)
-		sk->bind_next->bind_pprev = &tw->bind_next;
-	tw->bind_pprev = sk->bind_pprev;
-	*sk->bind_pprev = (struct sock *)tw;
-	sk->prev = NULL;
+	write_lock(&ehead->lock);
 
-	/* Step 3: Un-charge protocol socket in-use count. */
-	sk->prot->inuse--;
+	/* 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;
+	}
 
-	/* Step 4: Hash TW into TIMEWAIT half of established hash table. */
-	head = &tcp_ehash[sk->hashent + (tcp_ehash_size >> 1)];
+	/* 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);
+
+	write_unlock(&ehead->lock);
+
+	/* 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);
+
+	/* Step 4: Un-charge protocol socket in-use count. */
+	sk->prot->inuse--;
 }
 
+/* 
+ * Move a socket to time-wait.
+ */ 
 void tcp_time_wait(struct sock *sk)
 {
 	struct tcp_tw_bucket *tw;
@@ -1071,8 +1336,16 @@
 		tw->dport	= sk->dport;
 		tw->family	= sk->family;
 		tw->reuse	= sk->reuse;
+		tw->hashent	= sk->hashent;
 		tw->rcv_nxt	= sk->tp_pinfo.af_tcp.rcv_nxt;
-		tw->af_specific	= sk->tp_pinfo.af_tcp.af_specific;
+		tw->snd_nxt	= sk->tp_pinfo.af_tcp.snd_nxt;
+		tw->ts_recent	= sk->tp_pinfo.af_tcp.ts_recent;
+		tw->ts_recent_stamp= sk->tp_pinfo.af_tcp.ts_recent_stamp;
+#ifdef CONFIG_TCP_TW_RECYCLE
+		tw->rto		= sk->tp_pinfo.af_tcp.rto;
+		tw->ttd		= jiffies + 2*tw->rto;
+#endif
+		atomic_set(&tw->refcnt, 0);
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 		if(tw->family == PF_INET6) {
@@ -1085,9 +1358,7 @@
 		}
 #endif
 		/* Linkage updates. */
-		SOCKHASH_LOCK_WRITE();
-		tcp_tw_hashdance(sk, tw);
-		SOCKHASH_UNLOCK_WRITE();
+		__tcp_tw_hashdance(sk, tw);
 
 		/* Get the TIME_WAIT timeout firing. */
 		tcp_tw_schedule(tw);
@@ -1096,8 +1367,6 @@
 		if(sk->state == TCP_ESTABLISHED)
 			tcp_statistics.TcpCurrEstab--;
 		sk->state = TCP_CLOSE;
-		net_reset_timer(sk, TIME_DONE,
-				min(sk->tp_pinfo.af_tcp.srtt * 2, TCP_DONE_TIME));
 	} else {
 		/* Sorry, we're out of memory, just CLOSE this
 		 * socket up.  We've got bigger problems than
@@ -1106,10 +1375,9 @@
 		tcp_set_state(sk, TCP_CLOSE);
 	}
 
-	/* Prevent rcvmsg/sndmsg calls, and wake people up. */
-	sk->shutdown = SHUTDOWN_MASK;
-	if(!sk->dead)
-		sk->state_change(sk);
+	tcp_update_metrics(sk);
+	tcp_clear_xmit_timers(sk);
+	tcp_done(sk);
 }
 
 /*
@@ -1134,7 +1402,7 @@
 	tcp_send_ack(sk);
 
 	if (!sk->dead) {
-		sk->state_change(sk);
+		wake_up_interruptible(sk->sleep);
 		sock_wake_async(sk->socket, 1);
 	}
 
@@ -1143,8 +1411,6 @@
 		case TCP_ESTABLISHED:
 			/* Move to CLOSE_WAIT */
 			tcp_set_state(sk, TCP_CLOSE_WAIT);
-			if (th->rst)
-				sk->shutdown = SHUTDOWN_MASK;
 			break;
 
 		case TCP_CLOSE_WAIT:
@@ -1161,12 +1427,6 @@
 			/* This case occurs when a simultaneous close
 			 * happens, we must ack the received FIN and
 			 * enter the CLOSING state.
-			 *
-			 * This causes a WRITE timeout, which will either
-			 * move on to TIME_WAIT when we timeout, or resend
-			 * the FIN properly (maybe we get rid of that annoying
-			 * FIN lost hang). The TIME_WRITE code is already 
-			 * correct for handling this timeout.
 			 */
 			tcp_set_state(sk, TCP_CLOSING);
 			break;
@@ -1423,7 +1683,7 @@
 		/* Turn on fast path. */ 
 		if (skb_queue_len(&tp->out_of_order_queue) == 0)
 			tp->pred_flags = htonl(((tp->tcp_header_len >> 2) << 28) |
-					       (0x10 << 16) |
+					       ntohl(TCP_FLAG_ACK) |
 					       tp->snd_wnd);
 		return;
 	}
@@ -1545,8 +1805,8 @@
 	 * Now tell the user we may have some data.
 	 */
 	if (!sk->dead) {
-		SOCK_DEBUG(sk, "Data wakeup.\n");
-		sk->data_ready(sk,0);
+		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket,1);
 	}
 	return(1);
 }
@@ -1575,28 +1835,59 @@
 
 /* 
  * Adapt the MSS value used to make delayed ack decision to the 
- * real world. 
+ * 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 sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	unsigned int len = skb->len, lss; 
+	unsigned int len, lss;
 
-	if (len > tp->rcv_mss) 
-		tp->rcv_mss = len; 
 	lss = tp->last_seg_size; 
 	tp->last_seg_size = 0; 
-	if (len >= 536) {
-		if (len == lss) 
-			tp->rcv_mss = len; 
-		tp->last_seg_size = len; 
+
+	/* skb->len may jitter because of SACKs, even if peer
+	 * sends good full-sized frames.
+	 */
+	len = skb->len;
+	if (len >= tp->rcv_mss) {
+		tp->rcv_mss = len;
+	} else {
+		/* Otherwise, we make more careful check taking into account,
+		 * that SACKs block is variable.
+		 *
+		 * "len" is invariant segment length, including TCP header.
+		 */
+		len = skb->tail - skb->h.raw;
+		if (len >= 536 + sizeof(struct tcphdr)) {
+			/* 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->rcv_mss = len;
+			tp->last_seg_size = len;
+		}
 	}
 }
 
 /*
  * Check if sending an ack is needed.
  */
-static __inline__ void __tcp_ack_snd_check(struct sock *sk)
+static __inline__ void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
@@ -1621,12 +1912,12 @@
 	    /* We entered "quick ACK" mode or... */
 	    tcp_in_quickack_mode(tp) ||
 	    /* We have out of order data */
-	    (skb_peek(&tp->out_of_order_queue) != NULL)) {
+	    (ofo_possible && (skb_peek(&tp->out_of_order_queue) != NULL))) {
 		/* Then ack it now */
 		tcp_send_ack(sk);
 	} else {
 		/* Else, send delayed ack. */
-		tcp_send_delayed_ack(tp, HZ/2);
+		tcp_send_delayed_ack(sk, HZ/2);
 	}
 }
 
@@ -1637,7 +1928,7 @@
 		/* We sent a data segment already. */
 		return;
 	}
-	__tcp_ack_snd_check(sk);
+	__tcp_ack_snd_check(sk, 1);
 }
 
 
@@ -1767,6 +2058,13 @@
 	 * 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.
+	 *
+	 * 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
 	 */
 	if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1))
 		return 0;
@@ -1782,7 +2080,7 @@
  * 	disabled when:
  *	- A zero window was announced from us - zero window probing
  *        is only handled properly in the slow path. 
- *      - Out of order segments arrived.
+ *  - Out of order segments arrived.
  *	- Urgent data is expected.
  *	- There is no buffer space left
  *	- Unexpected TCP flags/window values/header lengths are received
@@ -1790,6 +2088,7 @@
  *	- Data is sent in both directions. Fast path only supports pure senders
  *	  or pure receivers (this means either the sequence number or the ack
  *	  value must stay constant)
+ *  - Unexpected TCP option.
  *
  *	When these conditions are not satisfied it drops into a standard 
  *	receive procedure patterned after RFC793 to handle all cases.
@@ -1801,12 +2100,10 @@
 			struct tcphdr *th, unsigned len)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int queued;
-	u32 flg;
 
 	/*
 	 *	Header prediction.
-	 *	The code follows the one in the famous 
+	 *	The code losely follows the one in the famous 
 	 *	"30 instruction TCP receive" Van Jacobson mail.
 	 *	
 	 *	Van's trick is to deposit buffers into socket queue 
@@ -1819,39 +2116,63 @@
 	 *	We do checksum and copy also but from device to kernel.
 	 */
 
-	/*
-	 * RFC1323: H1. Apply PAWS check first.
-	 */
-	if (tcp_fast_parse_options(sk, th, tp)) {
-		if (tp->saw_tstamp) {
-			if (tcp_paws_discard(tp, th, len)) {
-				tcp_statistics.TcpInErrs++;
-				if (!th->rst) {
-					tcp_send_ack(sk);
-					goto discard;
-				}
-			}
-			tcp_replace_ts_recent(sk, tp,
-					      TCP_SKB_CB(skb)->seq,
-					      TCP_SKB_CB(skb)->end_seq);
-		}
-	}
 
-	flg = *(((u32 *)th) + 3) & ~htonl(0xFC8 << 16);
+	/* 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
 	 *	if header_predition is to be made
 	 *	'S' will always be tp->tcp_header_len >> 2
-	 *	'?' will be 0 else it will be !0
-	 *	(when there are holes in the receive 
+	 *	'?' will be 0 for the fast path, otherwise pred_flags is 0 to
+	 *  turn it off	(when there are holes in the receive 
 	 *	 space for instance)
 	 *	PSH flag is ignored.
-         */
+	 */
 
-	if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
-		if (len <= th->doff*4) {
+	if ((tcp_flag_word(th) & ~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) == tp->pred_flags &&
+		TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
+		int tcp_header_len = th->doff*4;
+
+		/* Timestamp header prediction */
+
+		/* Non-standard header f.e. SACKs -> slow path */
+		if (tcp_header_len != tp->tcp_header_len)
+			goto slow_path;
+
+		/* Check timestamp */
+		if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
+			__u32 *ptr = (__u32 *)(th + 1);
+
+			/* No? Slow path! */
+			if (*ptr != __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+						     | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
+				goto slow_path;
+
+			tp->saw_tstamp = 1;
+			++ptr; 
+			tp->rcv_tsval = ntohl(*ptr);
+			++ptr;
+			tp->rcv_tsecr = ntohl(*ptr);
+
+			/* If PAWS failed, check it more carefully in slow path */
+			if ((s32)(tp->rcv_tsval - tp->ts_recent) < 0)
+				goto slow_path;
+
+			/* Predicted packet is in window by definition.
+			   seq == rcv_nxt and last_ack_sent <= rcv_nxt.
+			   Hence, check seq<=last_ack_sent reduces to:
+			 */
+			if (tp->rcv_nxt == tp->last_ack_sent) {
+				tp->ts_recent = tp->rcv_tsval;
+				tp->ts_recent_stamp = xtime.tv_sec;
+			}
+		}
+
+		if (len <= tcp_header_len) {
 			/* Bulk data transfer: sender */
-			if (len == th->doff*4) {
+			if (len == tcp_header_len) {
 				tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
 					TCP_SKB_CB(skb)->ack_seq, len); 
 				kfree_skb(skb); 
@@ -1864,12 +2185,14 @@
 		} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una &&
 			   atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
 			/* Bulk data transfer: receiver */
-			__skb_pull(skb,th->doff*4);
+			__skb_pull(skb,tcp_header_len);
 
+			/* Is it possible to simplify this? */
 			tcp_measure_rcv_mss(sk, skb); 
 
 			/* DO NOT notify forward progress here.
 			 * It saves dozen of CPU instructions in fast path. --ANK
+			 * And where is it signaled then ? -AK
 			 */
 			__skb_queue_tail(&sk->receive_queue, skb);
 			tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
@@ -1877,14 +2200,37 @@
 			/* 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);
+			wake_up_interruptible(sk->sleep);
+			sock_wake_async(sk->socket,1);
 			tcp_delack_estimator(tp);
 
 			tcp_remember_ack(tp, th, skb); 
 
-			__tcp_ack_snd_check(sk);
+			__tcp_ack_snd_check(sk, 0);
 			return 0;
 		}
+		/* Packet is in sequence, flags are trivial;
+		 * only ACK is strange or we are tough on memory.
+		 * Jump to step 5.
+		 */
+		goto step5;
+	}
+
+slow_path:
+	/*
+	 * RFC1323: H1. Apply PAWS check first.
+	 */
+	if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp &&
+	    tcp_paws_discard(tp, skb)) {
+		if (!th->rst) {
+			tcp_send_ack(sk);
+			goto discard;
+		}
+		/* Resets are accepted even if PAWS failed.
+
+		   ts_recent update must be made after we are sure
+		   that the packet is in window.
+		 */
 	}
 
 	/*
@@ -1909,44 +2255,34 @@
 		goto discard;
 	}
 
+	if(th->rst) {
+		tcp_reset(sk);
+		goto discard;
+	}
+
+	if (tp->saw_tstamp) {
+		tcp_replace_ts_recent(sk, 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_statistics.TcpInErrs++;
 		tcp_reset(sk);
 		return 1;
 	}
-	
-	if(th->rst) {
-		tcp_reset(sk);
-		goto discard;
-	}
 
+step5:
 	if(th->ack)
 		tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len);
 	
 	/* Process urgent data. */
 	tcp_urg(sk, th, len);
 
+	{
 	/* step 7: process the segment text */
-	queued = tcp_data(skb, sk, len);
+	int queued = tcp_data(skb, sk, len);
 
-	/* This must be after tcp_data() does the skb_pull() to
-	 * remove the header size from skb->len.
-	 *
-	 * Dave!!! Phrase above (and all about rcv_mss) has 
-	 * nothing to do with reality. rcv_mss must measure TOTAL
-	 * size, including sacks, IP options etc. Hence, measure_rcv_mss
-	 * must occure before pulling etc, otherwise it will flap
-	 * like hell. Even putting it before tcp_data is wrong,
-	 * it should use skb->tail - skb->nh.raw instead.
-	 *					--ANK (980805)
-	 * 
-	 * BTW I broke it. Now all TCP options are handled equally
-	 * in mss_clamp calculations (i.e. ignored, rfc1122),
-	 * and mss_cache does include all of them (i.e. tstamps)
-	 * except for sacks, to calulate effective mss faster.
-	 * 					--ANK (980805)
-	 */
 	tcp_measure_rcv_mss(sk, skb); 
 
 	/* Be careful, tcp_data() may have put this into TIME_WAIT. */
@@ -1959,76 +2295,541 @@
 	discard:
 		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);
+
+		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->srtt = 0;
+		newtp->ato = 0;
+		newtp->snd_wl1 = req->rcv_isn;
+		newtp->snd_wl2 = req->snt_isn;
+
+		/* RFC1323: The window in SYN & SYN/ACK segments
+		 * is never scaled.
+		 */
+		newtp->snd_wnd = ntohs(skb->h.th->window);
+
+		newtp->max_window = newtp->snd_wnd;
+		newtp->pending = 0;
+		newtp->retransmits = 0;
+		newtp->last_ack_sent = req->rcv_isn + 1;
+		newtp->backoff = 0;
+		newtp->mdev = TCP_TIMEOUT_INIT;
+
+		/* 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->rto = TCP_TIMEOUT_INIT;
+		newtp->packets_out = 0;
+		newtp->fackets_out = 0;
+		newtp->retrans_out = 0;
+		newtp->high_seq = 0;
+		newtp->snd_ssthresh = 0x7fffffff;
+		newtp->snd_cwnd_cnt = 0;
+		newtp->dup_acks = 0;
+		newtp->delayed_acks = 0;
+		init_timer(&newtp->retransmit_timer);
+		newtp->retransmit_timer.function = &tcp_retransmit_timer;
+		newtp->retransmit_timer.data = (unsigned long) newsk;
+		init_timer(&newtp->delack_timer);
+		newtp->delack_timer.function = &tcp_delack_timer;
+		newtp->delack_timer.data = (unsigned long) 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;
+
+		init_timer(&newtp->probe_timer);
+		newtp->probe_timer.function = &tcp_probe_timer;
+		newtp->probe_timer.data = (unsigned long) newsk;
+		newtp->probes_out = 0;
+		newtp->syn_seq = req->rcv_isn;
+		newtp->fin_seq = req->rcv_isn;
+		newtp->urg_data = 0;
+		tcp_synq_init(newtp);
+		newtp->syn_backlog = 0;
+		if (skb->len >= 536)
+			newtp->last_seg_size = skb->len; 
+
+		/* Back to base struct sock members. */
+		newsk->err = 0;
+		newsk->ack_backlog = 0;
+		newsk->max_ack_backlog = SOMAXCONN;
+		newsk->priority = 0;
+		atomic_set(&newsk->refcnt, 1);
+		atomic_inc(&inet_sock_nr);
+
+		spin_lock_init(&sk->timer_lock);
+		init_timer(&newsk->timer);
+		newsk->timer.function = &tcp_keepalive_timer;
+		newsk->timer.data = (unsigned long) newsk;
+		if (newsk->keepopen)
+			tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time);
+		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);
+		}
+		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;
+}
+
+static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
+{
+	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);
+}
+
+
 /* 
- *	Process an incoming SYN or SYN-ACK for SYN_RECV sockets represented
- *	as an open_request. 
+ *	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 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;
+	u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
+	int paws_reject = 0;
+	struct tcp_opt ttp;
+
+	/* If socket has already been created, process
+	   packet in its context.
+
+	   We fall here only due to race, when packets were enqueued
+	   to backlog of listening socket.
+	 */
+	if (req->sk)
+		return req->sk;
+
+	ttp.saw_tstamp = 0;
+	if (th->doff > (sizeof(struct tcphdr)>>2)) {
+
+		tcp_parse_options(NULL, th, &ttp, 0);
+
+		paws_reject = ttp.saw_tstamp &&
+			(s32)(ttp.rcv_tsval - req->ts_recent) < 0;
+	}
+
+	/* 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);
+		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.
 
-	/*	assumption: the socket is not in use.
-	 *	as we checked the user count on tcp_rcv and we're
-	 *	running from a soft interrupt.
+	   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.
 	 */
 
-	/* Check for syn retransmission */
-	flg = *(((u32 *)skb->h.th) + 3);
-	
-	flg &= __constant_htonl(0x00170000);
-	/* Only SYN set? */
-	if (flg == __constant_htonl(0x00020000)) {
-		if (!after(TCP_SKB_CB(skb)->seq, req->rcv_isn)) {
-			/*	retransmited syn.
+	/* 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);
+		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;
+
+	/* 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.
+	 */
+	sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
+	if (sk == NULL)
+		return NULL;
+
+	tcp_dec_slow_timer(TCP_SLT_SYNACK);
+	req->sk = sk;
+	return sk;
+
+embryonic_reset:
+	tcp_synq_unlink(tp, req, prev);
+	tp->syn_backlog--;
+	tcp_dec_slow_timer(TCP_SLT_SYNACK);
+
+	net_statistics.EmbryonicRsts++;
+	if (!(flg & TCP_FLAG_RST))
+		req->class->send_reset(skb);
+
+	req->class->destructor(req);
+	tcp_openreq_free(req); 
+	return NULL;
+}
+
+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);
+
+#ifdef CONFIG_TCP_TW_RECYCLE
+	if (tp->ts_recent_stamp && tp->saw_tstamp && !th->rst &&
+	    (s32)(tp->rcv_tsval - tp->ts_recent) < 0 &&
+	    xtime.tv_sec < tp->ts_recent_stamp + PAWS_24DAYS) {
+		/* Old duplicate segment. We remember last
+		   ts_recent from this host in timewait bucket.
+
+		   Actually, we could implement per host cache
+		   to truncate timewait state after RTO. Paranoidal arguments
+		   of rfc1337 are not enough to close this nice possibility.
+		*/
+		if (net_ratelimit())
+			printk(KERN_DEBUG "TCP: tw recycle, PAWS worked. Good.\n");
+		if (th->ack)
+			return 1;
+		goto discard;
+	}
+#endif
+
+	if (th->ack) {
+		/* rfc793:
+		 * "If the state is SYN-SENT then
+		 *    first check the ACK bit
+		 *      If the ACK bit is set
+		 *	  If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
+		 *        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 (sk->zapped ||
+		    TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
+			return 1;
+
+		/* Now ACK is acceptable.
+		 *
+		 * "If the RST bit is set
+		 *    If the ACK was acceptable then signal the user "error:
+		 *    connection reset", drop the segment, enter CLOSED state,
+		 *    delete TCB, and return."
+		 */
+
+		if (th->rst) {
+			tcp_reset(sk);
+			goto discard;
+		}
+
+		/* rfc793:
+		 *   "fifth, if neither of the SYN or RST bits is set then
+		 *    drop the segment and return."
+		 *
+		 *    See note below!
+		 *                                        --ANK(990513)
+		 */
+		if (!th->syn)
+			goto discard;
+
+		/* rfc793:
+		 *   "If the SYN bit is on ...
+		 *    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.
+		 *
+		 * There exist buggy stacks, which really send
+		 * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp)
+		 * Actually, if this host did not try to get something
+		 * from ftp.inr.ac.ru I'd never find this bug 8)
+		 *
+		 *                                     --ANK (990514)
+		 *
+		 * I was wrong, I apologize. Bare ACK is valid.
+		 * Actually, RFC793 requires to send such ACK
+		 * in reply to any out of window packet.
+		 * It is wrong, but Linux also does it sometimes.
+		 *                                     --ANK (990724)
+		 */
+
+		tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+		tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
+			TCP_SKB_CB(skb)->ack_seq, len);
+
+		/* Ok.. it's good. Set up sequence numbers and
+		 * move to established.
+		 */
+		tp->rcv_nxt = TCP_SKB_CB(skb)->seq+1;
+		tp->rcv_wup = TCP_SKB_CB(skb)->seq+1;
+
+		/* RFC1323: The window in SYN & SYN/ACK segments is
+		 * never scaled.
+		 */
+		tp->snd_wnd = htons(th->window);
+		tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+		tp->snd_wl2 = TCP_SKB_CB(skb)->ack_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);
+		}
+
+		if (tp->tstamp_ok) {
+			tp->tcp_header_len =
+				sizeof(struct tcphdr) + 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;
+		}
+		tcp_sync_mss(sk, tp->pmtu_cookie);
+		tcp_initialize_rcv_mss(sk);
+		tcp_init_metrics(sk);
+
+		if (tp->write_pending) {
+			/* Save one ACK. Data will be ready after
+			 * several ticks, if write_pending is set.
+			 *
+			 * How to make this correctly?
 			 */
-			req->class->rtx_syn_ack(sk, req); 
-			return NULL;
+			tp->delayed_acks++;
+			if (tp->ato == 0)
+				tp->ato = tp->rto;
+			tcp_send_delayed_ack(sk, tp->rto);
 		} else {
-			return sk; /* Pass new SYN to the listen socket. */
+			tcp_send_ack(sk);
 		}
+
+		tp->copied_seq = tp->rcv_nxt;
+
+		if(!sk->dead) {
+			wake_up_interruptible(sk->sleep);
+			sock_wake_async(sk->socket, 0);
+		}
+		return -1;
+	}
+
+	/* No ACK in the segment */
+
+	if (th->rst) {
+		/* rfc793:
+		 * "If the RST bit is set
+		 *
+		 *      Otherwise (no ACK) drop the segment and return."
+		 */
+
+		goto discard;
 	}
 
-	/* We know it's an ACK here */	
-	if (req->sk) {
-		/*	socket already created but not
-		 *	yet accepted()...
+	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)
 		 */
-		sk = req->sk;
-	} else {
-		/* In theory the packet could be for a cookie, but
-		 * TIME_WAIT should guard us against this. 
-		 * XXX: Nevertheless check for cookies?
-		 * This sequence number check is done again later,
-		 * but we do it here to prevent syn flood attackers
-		 * from creating big SYN_RECV sockets.
-		 */ 
-		if (!between(TCP_SKB_CB(skb)->ack_seq, req->snt_isn, req->snt_isn+1) ||
-		    !between(TCP_SKB_CB(skb)->seq, req->rcv_isn, 
-			     req->rcv_isn+1+req->rcv_wnd)) {
-			req->class->send_reset(skb);
-			return NULL;
+		tcp_set_state(sk, TCP_SYN_RECV);
+		if (tp->saw_tstamp) {
+			tp->ts_recent = tp->rcv_tsval;
+			tp->ts_recent_stamp = xtime.tv_sec;
 		}
-	
-		sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
-		tcp_dec_slow_timer(TCP_SLT_SYNACK);
-		if (sk == NULL)
-			return NULL;
-		
-		req->expires = 0UL;
-		req->sk = sk;
+
+		tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+		tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
+
+		/* RFC1323: The window in SYN & SYN/ACK segments is
+		 * never scaled.
+		 */
+		tp->snd_wnd = htons(th->window);
+		tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+
+		tcp_sync_mss(sk, tp->pmtu_cookie);
+		tcp_initialize_rcv_mss(sk);
+
+		tcp_send_synack(sk);
+#if 0
+		/* Note, we could accept data and URG from this segment.
+		 * There are no obstacles to make this.
+		 *
+		 * However, if we ignore data in ACKless segments sometimes,
+		 * we have no reasons to accept it sometimes.
+		 * Also, seems the code doing it in step6 of tcp_rcv_state_process
+		 * is not flawless. So, discard packet for sanity.
+		 * Uncomment this return to process the data.
+		 */
+		return -1;
+#endif
 	}
-	skb_orphan(skb); 
-	skb_set_owner_r(skb, sk);
-	return sk; 
+	/* "fifth, if neither of the SYN or RST bits is set then
+	 * drop the segment and return."
+	 */
+
+discard:
+	kfree_skb(skb);
+	return 0;
 }
 
+
 /*
  *	This function implements the receiving procedure of RFC 793 for
  *	all states except ESTABLISHED and TIME_WAIT. 
@@ -2042,6 +2843,8 @@
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	int queued = 0;
 
+	tp->saw_tstamp = 0;
+
 	switch (sk->state) {
 	case TCP_CLOSE:
 		/* When state == CLOSED, hash lookup always fails.
@@ -2061,35 +2864,26 @@
 		 * a TCP_CLOSE socket does not exist.  Drop the frame
 		 * and send a RST back to the other end.
 		 */
-		return 1;
 
-	case TCP_LISTEN:
-		/* These use the socket TOS.. 
-		 * might want to be the received TOS 
+		/* 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.
 		 */
-		if(th->ack) {
-			struct sock *realsk;
-			int ret;
+		goto discard;
 
-			realsk = tp->af_specific->get_sock(skb, th);
-			if(realsk == sk)
-				return 1;
+	case TCP_LISTEN:
+		if(th->ack)
+			return 1;
 
-			bh_lock_sock(realsk);
-			ret = 0;
-			if(realsk->lock.users != 0) {
-				skb_orphan(skb);
-				sk_add_backlog(realsk, skb);
-			} else {
-				ret = tcp_rcv_state_process(realsk, skb,
-							    skb->h.th, skb->len);
-			}
-			bh_unlock_sock(realsk);
-			return ret;
-		}
-		
 		if(th->syn) {
-			if(tp->af_specific->conn_request(sk, skb, 0) < 0)
+			if(tp->af_specific->conn_request(sk, skb) < 0)
 				return 1;
 
 			/* Now we have several options: In theory there is 
@@ -2110,172 +2904,14 @@
 			 */
 			goto discard;
 		}
-		
 		goto discard;
-		break;
 
 	case TCP_SYN_SENT:
-		/* SYN sent means we have to look for a suitable ack and 
-		 * either reset for bad matches or go to connected. 
-		 * The SYN_SENT case is unusual and should
-		 * not be in line code. [AC]
-		 */
-		if(th->ack) {
-			/* rfc793:
-			 * "If the state is SYN-SENT then
-			 *    first check the ACK bit
-			 *      If the ACK bit is set
-			 *	  If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
-			 *        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 (sk->zapped ||
-			    TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
-				return 1;
-
-			/* Now ACK is acceptable.
-			 *
-			 * "If the RST bit is set
-			 *    If the ACK was acceptable then signal the user "error:
-			 *    connection reset", drop the segment, enter CLOSED state,
-			 *    delete TCB, and return."
-			 */
-
-			if (th->rst) {
-				tcp_reset(sk);
-				goto discard;
-			}
-
-			/* rfc793:
-			 *   "fifth, if neither of the SYN or RST bits is set then
-			 *    drop the segment and return."
-			 *
-			 *    See note below!
-			 *                                        --ANK(990513)
-		         */
-			
-			if (!th->syn)
-				goto discard;
-
-			/* rfc793:
-			 *   "If the SYN bit is on ...
-			 *    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.
-			 *
-			 * There exist buggy stacks, which really send
-			 * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp)
-			 * Actually, if this host did not try to get something
-			 * from ftp.inr.ac.ru I'd never find this bug 8)
-			 *
-			 *                                     --ANK (990514)
-			 */
-
-			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-			tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
-				TCP_SKB_CB(skb)->ack_seq, len);
-
-			/* Ok.. it's good. Set up sequence numbers and
-			 * move to established.
-			 */
-			tp->rcv_nxt = TCP_SKB_CB(skb)->seq+1;
-			tp->rcv_wup = TCP_SKB_CB(skb)->seq+1;
-
-			/* RFC1323: The window in SYN & SYN/ACK segments is
-			 * never scaled.
-			 */
-			tp->snd_wnd = htons(th->window);
-			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-			tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
-			tp->fin_seq = TCP_SKB_CB(skb)->seq;
-
-			tcp_set_state(sk, TCP_ESTABLISHED);
-			tcp_parse_options(sk, th, tp, 0);
-
-        		if (tp->wscale_ok == 0) {
-                		tp->snd_wscale = tp->rcv_wscale = 0;
-                		tp->window_clamp = min(tp->window_clamp,65535);
-        		}
-
-			if (tp->tstamp_ok) {
-				tp->tcp_header_len =
-					sizeof(struct tcphdr) + 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 = tcp_time_stamp;
-			}
-
-			/* Can't be earlier, doff would be wrong. */
-			tcp_send_ack(sk);
-
-			sk->dport = th->source;
-			tp->copied_seq = tp->rcv_nxt;
-
-			if(!sk->dead) {
-				sk->state_change(sk);
-				sock_wake_async(sk->socket, 0);
-			}
-		} else {
-			if(th->syn && !th->rst) {
-				/* The previous version of the code
-				 * checked for "connecting to self"
-				 * here. that check is done now in
-				 * tcp_connect.
-				 */
-				tcp_set_state(sk, TCP_SYN_RECV);
-				tcp_parse_options(sk, th, tp, 0);
-				if (tp->saw_tstamp) {
-					tp->ts_recent = tp->rcv_tsval;
-					tp->ts_recent_stamp = tcp_time_stamp;
-				}
-				
-				tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
-				tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
-
-				/* RFC1323: The window in SYN & SYN/ACK segments is
-				 * never scaled.
-				 */
-				tp->snd_wnd = htons(th->window);
-				tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-				
-				tcp_send_synack(sk);
-			} else
-				break; 
-		}
-
-		/* tp->tcp_header_len and tp->mss_clamp
-		   probably changed, synchronize mss.
-		   */
-		tcp_sync_mss(sk, tp->pmtu_cookie);
-		tp->rcv_mss = tp->mss_cache;
-
-		if (sk->state == TCP_SYN_RECV)
-			goto discard;
-		
-		goto step6; 
+		queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
+		if (queued >= 0)
+			return queued;
+		queued = 0;
+		goto step6;
 	}
 
 	/*   Parse the tcp_options present on this header.
@@ -2283,23 +2919,13 @@
 	 *   Note that this really has to be here and not later for PAWS
 	 *   (RFC1323) to work.
 	 */
-	if (tcp_fast_parse_options(sk, th, tp)) {
-		/* NOTE: assumes saw_tstamp is never set if we didn't
-		 * negotiate the option. tcp_fast_parse_options() must
-		 * guarantee this.
-		 */
-		if (tp->saw_tstamp) {
-			if (tcp_paws_discard(tp, th, len)) {
-				tcp_statistics.TcpInErrs++;
-				if (!th->rst) {
-					tcp_send_ack(sk);
-					goto discard;
-				}
-			}
-			tcp_replace_ts_recent(sk, tp,
-					      TCP_SKB_CB(skb)->seq,
-					      TCP_SKB_CB(skb)->end_seq);
+	if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp &&
+	    tcp_paws_discard(tp, skb)) {
+		if (!th->rst) {
+			tcp_send_ack(sk);
+			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
@@ -2313,11 +2939,26 @@
 	 * 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) &&
-	    !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)) {
+	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) {
 			tcp_send_ack(sk);
 		}
@@ -2330,6 +2971,11 @@
 		goto discard;
 	}
 
+	if (tp->saw_tstamp) {
+		tcp_replace_ts_recent(sk, tp,
+				      TCP_SKB_CB(skb)->seq);
+	}
+
 	/* step 3: check security and precedence [ignored] */
 
 	/*	step 4:
@@ -2357,22 +3003,36 @@
 	if (th->ack) {
 		int acceptable = tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
 					 TCP_SKB_CB(skb)->ack_seq, len);
-		
+
 		switch(sk->state) {
 		case TCP_SYN_RECV:
 			if (acceptable) {
 				tcp_set_state(sk, TCP_ESTABLISHED);
-				sk->dport = th->source;
 				tp->copied_seq = tp->rcv_nxt;
 
-				if(!sk->dead)
-					sk->state_change(sk);		
+				/* 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 && sk->sleep) {
+					wake_up_interruptible(sk->sleep);
+					sock_wake_async(sk->socket, 1);
+				}
 
 				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
 				tp->snd_wnd = htons(th->window) << tp->snd_wscale;
 				tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
 				tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
 
+				/* tcp_ack considers this ACK as duplicate
+				 * and does not calculate rtt. It is wrong.
+				 * Fix it at least with timestamps.
+				 */
+				if (tp->saw_tstamp && !tp->srtt)
+					tcp_ack_saw_tstamp(sk, tp, 0, 0, FLAG_SYN_ACKED);
+
+				tcp_init_metrics(sk);
 			} else {
 				SOCK_DEBUG(sk, "bad ack\n");
 				return 1;
@@ -2386,7 +3046,8 @@
 				if (!sk->dead)
 					sk->state_change(sk);
 				else
-					tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+					tcp_reset_keepalive_timer(sk, sysctl_tcp_fin_timeout);
+				dst_confirm(sk->dst_cache);
 			}
 			break;
 
@@ -2399,10 +3060,9 @@
 
 		case TCP_LAST_ACK:
 			if (tp->snd_una == tp->write_seq) {
-				sk->shutdown = SHUTDOWN_MASK;
 				tcp_set_state(sk,TCP_CLOSE);
-				if (!sk->dead)
-					sk->state_change(sk);
+				tcp_update_metrics(sk);
+				tcp_done(sk);
 				goto discard;
 			}
 			break;
@@ -2444,8 +3104,11 @@
 		break;
 	}
 
-	tcp_data_snd_check(sk);
-	tcp_ack_snd_check(sk);
+	/* tcp_data could move socket to TIME-WAIT */
+	if (sk->state != TCP_CLOSE) {
+		tcp_data_snd_check(sk);
+		tcp_ack_snd_check(sk);
+	}
 
 	if (!queued) { 
 discard:

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