patch-1.3.63 linux/net/ipv4/tcp.c

Next file: linux/net/ipv4/tcp_input.c
Previous file: linux/net/ipv4/af_inet.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.62/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
@@ -802,14 +802,31 @@
  *	Modified January 1995 from a go-faster DOS routine by
  *	Jorge Cwik <jorge@laser.satlink.net>
  */
- 
+#undef DEBUG_TCP_CHECK
 void tcp_send_check(struct tcphdr *th, unsigned long saddr, 
-		unsigned long daddr, int len, struct sock *sk)
+		unsigned long daddr, int len, struct sk_buff *skb)
 {
+#ifdef DEBUG_TCP_CHECK
+	u16 check;
+#endif
+	th->check = 0;
+	th->check = tcp_check(th, len, saddr, daddr,
+		csum_partial((char *)th,sizeof(*th),skb->csum));
+
+#ifdef DEBUG_TCP_CHECK
+	check = th->check;
 	th->check = 0;
 	th->check = tcp_check(th, len, saddr, daddr,
 		csum_partial((char *)th,len,0));
-	return;
+	if (check != th->check) {
+		static int count = 0;
+		if (++count < 10) {
+			printk("Checksum %x (%x) from %p\n", th->check, check,
+				(&th)[-1]);
+			printk("TCP=<off:%d a:%d s:%d f:%d>\n", th->doff*4, th->ack, th->syn, th->fin);
+		}
+	}
+#endif
 }
 
 
@@ -823,9 +840,6 @@
 	memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
 	th->seq = htonl(sk->write_seq);
 	th->psh =(push == 0) ? 1 : 0;
-	th->doff = sizeof(*th)/4;
-	th->ack = 1;
-	th->fin = 0;
 	sk->ack_backlog = 0;
 	sk->bytes_rcv = 0;
 	sk->ack_timed = 0;
@@ -1003,30 +1017,29 @@
 	
 			if ((skb = tcp_dequeue_partial(sk)) != NULL) 
 			{
-				int hdrlen;
+				int tcp_size;
 
-				 /* IP header + TCP header */
-				hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
-					 + sizeof(struct tcphdr);
+				tcp_size = skb->tail - (unsigned char *)(skb->h.th + 1);
 	
 				/* Add more stuff to the end of skb->len */
 				if (!(flags & MSG_OOB)) 
 				{
-					copy = min(sk->mss - (skb->len - hdrlen), seglen);
+					copy = min(sk->mss - tcp_size, seglen);
 					if (copy <= 0) 
 					{
 						printk("TCP: **bug**: \"copy\" <= 0\n");
 				  		return -EFAULT;
-					}		  
+					}
+					tcp_size += copy;
 					memcpy_fromfs(skb_put(skb,copy), from, copy);
+					skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0);
 					from += copy;
 					copied += copy;
 					len -= copy;
 					sk->write_seq += copy;
 					seglen -= copy;
 				}
-				if ((skb->len - hdrlen) >= sk->mss ||
-					(flags & MSG_OOB) || !sk->packets_out)
+				if (tcp_size >= sk->mss || (flags & MSG_OOB) || !sk->packets_out)
 					tcp_send_skb(sk, skb);
 				else
 					tcp_enqueue_partial(skb, sk);
@@ -1058,6 +1071,11 @@
 			send_tmp = NULL;
 			if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out) 
 			{
+#if EXTRA_RELEASE
+/*
+ * we don't really need to release even if we sleep: our packets
+ * will be backlogged for us, and that's just fine.
+ */
 				/*
 				 *	We will release the socket in case we sleep here. 
 				 */
@@ -1066,16 +1084,19 @@
 				 *	NB: following must be mtu, because mss can be increased.
 				 *	mss is always <= mtu 
 				 */
+#endif
 				skb = sock_wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL);
 				sk->inuse = 1;
 				send_tmp = skb;
 			} 
 			else 
 			{
+#if EXTRA_RELEASE
 				/*
 				 *	We will release the socket in case we sleep here. 
 				 */
 				release_sock(sk);
+#endif
 				skb = sock_wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL);
   				sk->inuse = 1;
 			}
@@ -1156,7 +1177,8 @@
 				skb->h.th->urg_ptr = ntohs(copy);
 			}
 
-			memcpy_fromfs(skb_put(skb,copy), from, copy);
+			skb->csum = csum_partial_copy_fromuser(from,
+				skb_put(skb,copy), copy, 0);
 		
 			from += copy;
 			copied += copy;
@@ -1240,6 +1262,7 @@
 
 	buff->sk = sk;
 	buff->localroute = sk->localroute;
+	buff->csum = 0;
 	
 	/*
 	 *	Put in the IP header and routing stuff. 
@@ -1258,14 +1281,6 @@
 
 	memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
 	t1->seq = htonl(sk->sent_seq);
-	t1->ack = 1;
-	t1->res1 = 0;
-	t1->res2 = 0;
-	t1->rst = 0;
-	t1->urg = 0;
-	t1->syn = 0;
-	t1->psh = 0;
-
 
 	sk->ack_backlog = 0;
 	sk->bytes_rcv = 0;
@@ -1274,13 +1289,90 @@
 	t1->window = htons(sk->window);
 	t1->ack_seq = htonl(sk->acked_seq);
 	t1->doff = sizeof(*t1)/4;
-	tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+	tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), buff);
 	sk->prot->queue_xmit(sk, dev, buff, 1);
 	tcp_statistics.TcpOutSegs++;
 }
 
 
 /*
+ *	Handle reading urgent data. BSD has very simple semantics for
+ *	this, no blocking and very strange errors 8)
+ */
+ 
+static int tcp_recv_urg(struct sock * sk, int nonblock,
+	     struct msghdr *msg, int len, int flags, int *addr_len)
+{
+	/*
+	 *	No URG data to read
+	 */
+	if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
+		return -EINVAL;	/* Yes this is right ! */
+		
+	if (sk->err) 
+		return sock_error(sk);
+		
+	if (sk->state == TCP_CLOSE || sk->done) 
+	{
+		if (!sk->done) 
+		{
+			sk->done = 1;
+			return 0;
+		}
+		return -ENOTCONN;
+	}
+
+	if (sk->shutdown & RCV_SHUTDOWN) 
+	{
+		sk->done = 1;
+		return 0;
+	}
+	sk->inuse = 1;
+	if (sk->urg_data & URG_VALID) 
+	{
+		char c = sk->urg_data;
+		if (!(flags & MSG_PEEK))
+			sk->urg_data = URG_READ;
+		memcpy_toiovec(msg->msg_iov, &c, 1);
+		if(msg->msg_name)
+		{
+			struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
+			sin->sin_family=AF_INET;
+			sin->sin_addr.s_addr=sk->daddr;
+			sin->sin_port=sk->dummy_th.dest;
+		}
+		if(addr_len)
+			*addr_len=sizeof(struct sockaddr_in);
+		release_sock(sk);
+		return 1;
+	}
+	release_sock(sk);
+	
+	/*
+	 * Fixed the recv(..., MSG_OOB) behaviour.  BSD docs and
+	 * the available implementations agree in this case:
+	 * this call should never block, independent of the
+	 * blocking state of the socket.
+	 * Mike <pall@rz.uni-karlsruhe.de>
+	 */
+	return -EAGAIN;
+}
+
+/*
+ *	Release a skb if it is no longer needed. This routine
+ *	must be called with interrupts disabled or "sk->inuse = 1"
+ *	so that the sk_buff queue operation is ok.
+ */
+ 
+static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
+{
+	sk->ack_backlog++;
+	skb->sk = sk;
+	__skb_unlink(skb, &sk->receive_queue);
+	kfree_skb(skb, FREE_READ);
+}
+
+/*
  * 	FIXME:
  * 	This routine frees used buffers.
  * 	It should consider sending an ACK to let the
@@ -1289,37 +1381,20 @@
 
 static void cleanup_rbuf(struct sock *sk)
 {
-	unsigned long flags;
 	struct sk_buff *skb;
 	unsigned long rspace;
 
-	save_flags(flags);
-	cli();
-
 	/*
-	 * See if we have anything to free up?
+	 * NOTE! 'sk->inuse' must be set, so that we don't get
+	 * a messed-up receive queue.
 	 */
-
-	skb = skb_peek(&sk->receive_queue);
-	if (!skb || !skb->used || skb->users) {
-		restore_flags(flags);
-		return;
+	while ((skb=skb_peek(&sk->receive_queue)) != NULL) {
+		if (!skb->used || skb->users)
+			break;
+		tcp_eat_skb(sk, skb);
 	}
 
 	/*
-	 *	We have to loop through all the buffer headers,
-	 *	and try to free up all the space we can.
-	 */
-
-	do {
-		skb_unlink(skb);
-		skb->sk = sk;
-		kfree_skb(skb, FREE_READ);
-		skb = skb_peek(&sk->receive_queue);
-	} while (skb && skb->used && !skb->users);
-	restore_flags(flags);
-
-	/*
 	 *	FIXME:
 	 *	At this point we should send an ack if the difference
 	 *	in the window, and the amount of space is bigger than
@@ -1339,7 +1414,6 @@
 	 * immediately.  Otherwise we will wait up to .5 seconds in case
 	 * the user reads some more.
 	 */
-	sk->ack_backlog++;
 
 	/*
 	 * It's unclear whether to use sk->mtu or sk->mss here.  They differ only
@@ -1370,70 +1444,6 @@
 
 
 /*
- *	Handle reading urgent data. BSD has very simple semantics for
- *	this, no blocking and very strange errors 8)
- */
- 
-static int tcp_recv_urg(struct sock * sk, int nonblock,
-	     struct msghdr *msg, int len, int flags, int *addr_len)
-{
-	/*
-	 *	No URG data to read
-	 */
-	if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
-		return -EINVAL;	/* Yes this is right ! */
-		
-	if (sk->err) 
-		return sock_error(sk);
-		
-	if (sk->state == TCP_CLOSE || sk->done) 
-	{
-		if (!sk->done) 
-		{
-			sk->done = 1;
-			return 0;
-		}
-		return -ENOTCONN;
-	}
-
-	if (sk->shutdown & RCV_SHUTDOWN) 
-	{
-		sk->done = 1;
-		return 0;
-	}
-	sk->inuse = 1;
-	if (sk->urg_data & URG_VALID) 
-	{
-		char c = sk->urg_data;
-		if (!(flags & MSG_PEEK))
-			sk->urg_data = URG_READ;
-		memcpy_toiovec(msg->msg_iov, &c, 1);
-		if(msg->msg_name)
-		{
-			struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
-			sin->sin_family=AF_INET;
-			sin->sin_addr.s_addr=sk->daddr;
-			sin->sin_port=sk->dummy_th.dest;
-		}
-		if(addr_len)
-			*addr_len=sizeof(struct sockaddr_in);
-		release_sock(sk);
-		return 1;
-	}
-	release_sock(sk);
-	
-	/*
-	 * Fixed the recv(..., MSG_OOB) behaviour.  BSD docs and
-	 * the available implementations agree in this case:
-	 * this call should never block, independent of the
-	 * blocking state of the socket.
-	 * Mike <pall@rz.uni-karlsruhe.de>
-	 */
-	return -EAGAIN;
-}
-
-
-/*
  *	This routine copies from a sock struct into the user buffer. 
  */
  
@@ -1637,6 +1647,8 @@
 		if (flags & MSG_PEEK)
 			continue;
 		skb->used = 1;
+		if (!skb->users)
+			tcp_eat_skb(sk, skb);		
 		continue;
 
 	found_fin_ok:
@@ -2001,13 +2013,7 @@
 	buff->end_seq = sk->write_seq;
 	t1->ack = 0;
 	t1->window = 2;
-	t1->res1=0;
-	t1->res2=0;
-	t1->rst = 0;
-	t1->urg = 0;
-	t1->psh = 0;
 	t1->syn = 1;
-	t1->urg_ptr = 0;
 	t1->doff = 6;
 	/* use 512 or whatever user asked for */
 	
@@ -2056,8 +2062,9 @@
 	ptr[1] = 4;
 	ptr[2] = (sk->mtu) >> 8;
 	ptr[3] = (sk->mtu) & 0xff;
+	buff->csum = csum_partial(ptr, 4, 0);
 	tcp_send_check(t1, sk->saddr, sk->daddr,
-		  sizeof(struct tcphdr) + 4, sk);
+		  sizeof(struct tcphdr) + 4, buff);
 
 	/*
 	 *	This must go first otherwise a really quick response will get reset. 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this