patch-2.1.9 linux/net/ipv6/tcp_ipv6.c

Next file: linux/net/ipv6/udp.c
Previous file: linux/net/ipv6/sit.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.8/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
@@ -779,6 +779,87 @@
 	tcp_statistics.TcpOutSegs++;
 }
 
+struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct open_request *req;
+	
+
+	/*
+	 *	assumption: the socket is not in use.
+	 *	as we checked the user count on tcp_rcv and we're
+	 *	running from a soft interrupt.
+	 */
+		
+	req = tp->syn_wait_queue;
+	
+
+	if (!req)
+	{
+		return sk;
+	}
+	
+	do {
+		struct tcp_v6_open_req *af_req;
+
+		af_req = (struct tcp_v6_open_req *) req;
+
+		if (!ipv6_addr_cmp(&af_req->rmt_addr, &skb->ipv6_hdr->saddr) &&
+		    !ipv6_addr_cmp(&af_req->loc_addr, &skb->ipv6_hdr->daddr) &&
+		    req->rmt_port == skb->h.th->source)
+		{
+			u32 flg;
+				
+			if (req->sk)
+			{
+				printk(KERN_DEBUG "BUG: syn_recv:"
+				       "socket exists\n");
+				break;
+			}
+
+			/* match */
+
+			/*
+			 *	Check for syn retransmission
+			 */
+			flg = *(((u32 *)skb->h.th) + 3);
+			flg &= __constant_htonl(0x002f0000);
+				
+			if ((flg == __constant_htonl(0x00020000)) &&
+			    (!after(skb->seq, req->rcv_isn)))
+			{
+				/*
+				 *	retransmited syn
+				 *	FIXME: must send an ack
+				 */
+				return NULL;
+			}
+
+			atomic_sub(skb->truesize, &sk->rmem_alloc);
+			sk = tp->af_specific->syn_recv_sock(sk, skb, req);
+
+			tcp_dec_slow_timer(TCP_SLT_SYNACK);
+
+			if (sk == NULL)
+			{
+				return NULL;
+			}
+
+			atomic_add(skb->truesize, &sk->rmem_alloc);
+			req->expires = 0UL;
+			req->sk = sk;
+			skb->sk = sk;
+			break;
+		}
+
+		req = req->dl_next;
+	} while (req != tp->syn_wait_queue);
+	
+
+	return sk;
+
+}
+
 int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
 	       struct in6_addr *saddr, struct in6_addr *daddr,
 	       struct ipv6_options *opt, unsigned short len,
@@ -890,40 +971,14 @@
 	
 	if (sk->state == TCP_LISTEN)
 	{
-		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-		struct open_request *req;
-		struct tcp_v6_open_req *af_req;
+		/*
+		 *	find possible connection requests
+		 */
+		sk = tcp_v6_check_req(sk, skb);
 
-		req = tp->syn_wait_queue;
-		af_req = (struct tcp_v6_open_req *) req;
-		
-		if (req)
+		if (sk == NULL)
 		{
-			do {
-				if (!ipv6_addr_cmp(&af_req->rmt_addr, saddr) &&
-				    !ipv6_addr_cmp(&af_req->loc_addr, daddr) &&
-				    req->rmt_port == th->source)
-				{
-					/* match */
-					
-					atomic_sub(skb->truesize, &sk->rmem_alloc);
-					sk = tp->af_specific->syn_recv_sock(sk, skb,
-									    req);
-					tcp_dec_slow_timer(TCP_SLT_SYNACK);
-					
-					if (sk == NULL)
-					{
-						goto no_tcp_socket;
-					}
-					
-					atomic_add(skb->truesize, &sk->rmem_alloc);
-					req->sk = sk;
-					skb->sk = sk;
-					break;
-				}
-
-				req = req->dl_next;
-			} while (req != tp->syn_wait_queue);
+			goto discard_it;
 		}
 
 	}

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