patch-2.1.124 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.123/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.92 1998/09/15 02:11:42 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.93 1998/10/03 09:38:50 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -53,6 +53,7 @@
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
 					      struct ipv6hdr *ip6h,
 					      struct tcphdr *th,
+					      int iif,
 					      struct open_request **prevp);
 
 static struct tcp_func ipv6_mapped;
@@ -363,6 +364,12 @@
 	return retval;
 }
 
+static __inline__ int tcp_v6_iif(struct sk_buff *skb)
+{
+	struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+	return opt->iif;
+}
+
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 
 			  int addr_len)
 {
@@ -580,7 +587,6 @@
 	struct ipv6_pinfo *np;
 	struct sock *sk;
 	int err;
-	int opening;
 	struct tcp_opt *tp; 
 	__u32 seq; 
 
@@ -597,18 +603,18 @@
 	tp = &sk->tp_pinfo.af_tcp;
 	seq = ntohl(th->seq); 
 	if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
-		if (net_ratelimit()) 
-			printk(KERN_DEBUG "icmp packet outside the tcp window:"
-					  " s:%d %u,%u,%u\n",
-			       (int)sk->state, seq, tp->snd_una, tp->snd_nxt); 
+		net_statistics.OutOfWindowIcmps++;
 		return; 
 	}
 
 	np = &sk->net_pinfo.af_inet6;
-	if (type == ICMPV6_PKT_TOOBIG && sk->state != TCP_LISTEN) {
+	if (type == ICMPV6_PKT_TOOBIG) {
 		struct dst_entry *dst = NULL;
 		/* icmp should have updated the destination cache entry */
 
+		if (sk->state == TCP_LISTEN)
+			return;
+
 		if (sk->dst_cache)
 			dst = dst_check(&sk->dst_cache, np->dst_cookie);
 
@@ -632,7 +638,7 @@
 			dst = dst_clone(dst);
 
 		if (dst->error) {
-			sk->err_soft = dst->error;
+			sk->err_soft = -dst->error;
 		} else if (tp->pmtu_cookie > dst->pmtu
 			   && !atomic_read(&sk->sock_readers)) {
 			lock_sock(sk); 
@@ -644,26 +650,29 @@
 		return;
 	}
 
-	opening = 0; 
+	icmpv6_err_convert(type, code, &err);
+
 	/* Might be for an open_request */
 	switch (sk->state) {
 		struct open_request *req, *prev;
 		struct ipv6hdr hd;
 	case TCP_LISTEN:
-		if (atomic_read(&sk->sock_readers))
-			return;
+		if (atomic_read(&sk->sock_readers)) {
+			net_statistics.LockDroppedIcmps++;
+			 /* If too many ICMPs get dropped on busy
+			  * servers this needs to be solved differently.
+			  */
+ 			return;
+		}
 
 		/* Grrrr - fix this later. */
 		ipv6_addr_copy(&hd.saddr, saddr);
 		ipv6_addr_copy(&hd.daddr, daddr); 
-		req = tcp_v6_search_req(tp, &hd,th, &prev);
+		req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
 		if (!req)
 			return;
 		if (seq != req->snt_isn) {
-			if (net_ratelimit())
-				printk(KERN_DEBUG "icmp packet for openreq "
-				       "with wrong seq number:%d:%d\n",
-				       seq, req->snt_isn);
+			net_statistics.OutOfWindowIcmps++;
 			return;
 		}
 		if (req->sk) {
@@ -676,21 +685,26 @@
 		}
 		/* FALL THROUGH */ 
 	case TCP_SYN_SENT:
-	case TCP_SYN_RECV: 
-		opening = 1;
-		break; 
+	case TCP_SYN_RECV:  /* Cannot happen */ 
+		tcp_statistics.TcpAttemptFails++;
+		sk->err = err;
+		sk->zapped = 1;
+		mb();
+		sk->error_report(sk);
+		return;
 	}
 
-	if (icmpv6_err_convert(type, code, &err) || opening) {
+	if (np->recverr) {
+		/* This code isn't serialized with the socket code */
+		/* ANK (980927) ... which is harmless now,
+		   sk->err's may be safely lost.
+		 */
 		sk->err = err;
-
-		if (opening) {
-			tcp_statistics.TcpAttemptFails++;
-			tcp_set_state(sk,TCP_CLOSE);
-			sk->error_report(sk);
-		}
+		mb();
+		sk->error_report(sk);
 	} else {
 		sk->err_soft = err;
+		mb();
 	}
 }
 
@@ -853,7 +867,7 @@
 
 	/* So that link locals have meaning */
 	if (!sk->bound_dev_if && ipv6_addr_type(&req->af.v6_req.rmt_addr)&IPV6_ADDR_LINKLOCAL)
-		req->af.v6_req.iif = skb->dev->ifindex;
+		req->af.v6_req.iif = tcp_v6_iif(skb);
 
 	req->class = &or_ipv6;
 	req->retrans = 0;
@@ -1035,6 +1049,9 @@
 	if (th->rst)
 		return;
 
+	if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
+		return; 
+
 	/*
 	 * We need to grab some memory, and put together an RST,
 	 * and then put it into the queue to be sent.
@@ -1076,7 +1093,7 @@
 				    buff->csum);
 
 	fl.proto = IPPROTO_TCP;
-	fl.oif = skb->dev->ifindex;
+	fl.oif = tcp_v6_iif(skb);
 	fl.uli_u.ports.dport = t1->dest;
 	fl.uli_u.ports.sport = t1->source;
 
@@ -1096,6 +1113,7 @@
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
 					      struct ipv6hdr *ip6h,
 					      struct tcphdr *th,
+					      int iif,
 					      struct open_request **prevp)
 {
 	struct open_request *req, *prev; 
@@ -1109,9 +1127,10 @@
 	for (req = prev->dl_next; req; req = req->dl_next) {
 		if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
 		    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
-		    req->rmt_port == rport) {
-			*prevp = prev; 
-			return req; 
+		    req->rmt_port == rport &&
+		    (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
+			*prevp = prev;
+			return req;
 		}
 		prev = req; 
 	}
@@ -1123,7 +1142,7 @@
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	struct open_request *req, *prev;
 
-	req = tcp_v6_search_req(tp,skb->nh.ipv6h,skb->h.th,&prev);
+	req = tcp_v6_search_req(tp,skb->nh.ipv6h,skb->h.th,tcp_v6_iif(skb),&prev);
 	if (!req)
 		return;
 	/* Sequence number check required by RFC793 */
@@ -1156,7 +1175,7 @@
 		struct open_request *req, *dummy;
 		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 			
-		req = tcp_v6_search_req(tp, skb->nh.ipv6h,th, &dummy);
+		req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &dummy);
 		if (req) {
 			sk = tcp_check_req(sk, skb, req);
 		}
@@ -1292,7 +1311,6 @@
 {
 	struct tcphdr *th;	
 	struct sock *sk;
-	struct device *dev = skb->dev;
 	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
 	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
 
@@ -1330,7 +1348,7 @@
 		/* CHECKSUM_UNNECESSARY */
 	};
 
-	sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, dev->ifindex);
+	sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
 
 	if (!sk)
 		goto no_tcp_socket;
@@ -1412,7 +1430,7 @@
 
 	saddr = &skb->nh.ipv6h->saddr;
 	daddr = &skb->nh.ipv6h->daddr;
-	return tcp_v6_lookup(saddr, th->source, daddr, th->dest, skb->dev->ifindex);
+	return tcp_v6_lookup(saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
 }
 
 static void tcp_v6_xmit(struct sk_buff *skb)
@@ -1441,7 +1459,7 @@
 		dst = ip6_route_output(sk, &fl);
 
 		if (dst->error) {
-			sk->err_soft = dst->error;
+			sk->err_soft = -dst->error;
 			dst_release(dst);
 			return;
 		}

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