patch-2.3.4 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.3/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.165 1999/05/14 23:10:08 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.167 1999/05/29 22:37:54 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -914,8 +914,11 @@
 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)
 {
+	SOCKHASH_LOCK_WRITE_BH();
+
 	/* Unlink from various places. */
 	if(tw->bind_next)
 		tw->bind_next->bind_pprev = tw->bind_pprev;
@@ -933,6 +936,8 @@
 	tw->sklist_next->sklist_prev = tw->sklist_prev;
 	tw->sklist_prev->sklist_next = tw->sklist_next;
 
+	SOCKHASH_UNLOCK_WRITE_BH();
+
 	/* Ok, now free it up. */
 	kmem_cache_free(tcp_timewait_cachep, tw);
 }
@@ -963,6 +968,7 @@
 		struct sock *sk;
 		struct tcp_func *af_specific = tw->af_specific;
 		__u32 isn;
+		int ret;
 
 		isn = tw->rcv_nxt + 128000;
 		if(isn == 0)
@@ -971,14 +977,25 @@
 		tcp_timewait_kill(tw);
 		sk = af_specific->get_sock(skb, th);
 		if(sk == NULL ||
-		   !ipsec_sk_policy(sk,skb) ||
-		   atomic_read(&sk->sock_readers) != 0)
+		   !ipsec_sk_policy(sk,skb))
 			return 0;
+
+		bh_lock_sock(sk);
+
+		/* Default is to discard the frame. */
+		ret = 0;
+
+		if(sk->lock.users)
+			goto out_unlock;
+
 		skb_set_owner_r(skb, sk);
 		af_specific = sk->tp_pinfo.af_tcp.af_specific;
+
 		if(af_specific->conn_request(sk, skb, isn) < 0)
-			return 1; /* Toss a reset back. */
-		return 0; /* Discard the frame. */
+			ret = 1; /* Toss a reset back. */
+	out_unlock:
+		bh_unlock_sock(sk);
+		return ret;
 	}
 
 	/* Check RST or SYN */
@@ -1031,7 +1048,7 @@
 	sk->prot->inuse--;
 
 	/* Step 4: Hash TW into TIMEWAIT half of established hash table. */
-	head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+	head = &tcp_ehash[sk->hashent + (tcp_ehash_size >> 1)];
 	sktw = (struct sock *)tw;
 	if((sktw->next = *head) != NULL)
 		(*head)->pprev = &sktw->next;
@@ -1069,7 +1086,9 @@
 		}
 #endif
 		/* Linkage updates. */
+		SOCKHASH_LOCK_WRITE();
 		tcp_tw_hashdance(sk, tw);
+		SOCKHASH_UNLOCK_WRITE();
 
 		/* Get the TIME_WAIT timeout firing. */
 		tcp_tw_schedule(tw);
@@ -1819,7 +1838,7 @@
 		}
 	}
 
-	flg = *(((u32 *)th) + 3) & ~htonl(0x8 << 16);
+	flg = *(((u32 *)th) + 3) & ~htonl(0xFC8 << 16);
 
 	/*	pred_flags is 0xS?10 << 16 + snd_wnd
 	 *	if header_predition is to be made
@@ -2049,8 +2068,26 @@
 		/* These use the socket TOS.. 
 		 * might want to be the received TOS 
 		 */
-		if(th->ack)
-			return 1;
+		if(th->ack) {
+			struct sock *realsk;
+			int ret;
+
+			realsk = tp->af_specific->get_sock(skb, th);
+			if(realsk == sk)
+				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)

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