"TCP: **bug**: copy=0" in 2.0.x

David S. Miller (davem@jenolan.rutgers.edu)
Sun, 4 May 1997 23:28:43 -0400


If you are seeing this still in 2.0.30, please try the following patch
and let me know if the problem persists:

--- linux/net/ipv4/tcp.c.~1~ Thu May 1 00:32:10 1997
+++ linux/net/ipv4/tcp.c Sun May 4 23:11:05 1997
@@ -2261,10 +2261,14 @@
* but not bigger than device MTU
*/

- if(sk->mtu <32)
- sk->mtu = 32; /* Sanity limit */
-
sk->mtu = min(sk->mtu, dev->mtu - sizeof(struct iphdr) - sizeof(struct tcphdr));
+
+ /* Must check it here, just to be absolutely safe. If we end up
+ * with an sk->mtu of zero, we can thus end up with an sk->mss
+ * of zero, which causes us to bomb out in tcp_do_sendmsg. -DaveM
+ */
+ if(sk->mtu < 32)
+ sk->mtu = 32; /* Sanity limit */

/*
* Put in the TCP options to say MTU.
--- linux/net/ipv4/tcp_input.c.~1~ Thu May 1 00:32:11 1997
+++ linux/net/ipv4/tcp_input.c Sun May 4 23:15:50 1997
@@ -701,7 +701,7 @@
newsk->rtt = 0;
newsk->rto = TCP_TIMEOUT_INIT;
newsk->mdev = TCP_TIMEOUT_INIT;
- newsk->max_window = 0;
+ newsk->max_window = 32; /* It cannot be left at zero. -DaveM */
/*
* See draft-stevens-tcpca-spec-01 for discussion of the
* initialization of these values.
@@ -824,6 +824,14 @@

newsk->mtu = min(newsk->mtu, dev->mtu - sizeof(struct iphdr) - sizeof(struct tcphdr));

+ /* Must check it here, just to be absolutely safe. If we end up
+ * with a newsk->{max_window,mtu} of zero, we can thus end up with
+ * a newsk->mss of zero, which causes us to bomb out in
+ * tcp_do_sendmsg. -DaveM
+ */
+ if(newsk->mtu < 32)
+ newsk->mtu = 32;
+
#ifdef CONFIG_SKIP

/*
@@ -963,7 +971,7 @@
newsk->rtt = 0;
newsk->rto = TCP_TIMEOUT_INIT;
newsk->mdev = TCP_TIMEOUT_INIT;
- newsk->max_window = 0;
+ newsk->max_window = 32; /* It cannot be left at zero. -DaveM */
/*
* See draft-stevens-tcpca-spec-01 for discussion of the
* initialization of these values.
@@ -1651,6 +1659,14 @@
if (sk->state==TCP_SYN_RECV)
{
tcp_set_state(sk, TCP_ESTABLISHED);
+
+ /* Must check for peer advertising zero sized window
+ * or else we get a sk->{mtu,mss} of zero and thus bomb out
+ * in tcp_do_sendmsg. -DaveM
+ */
+ if(sk->max_window == 0)
+ sk->max_window = 32;
+
tcp_options(sk,th);

#if 0
@@ -1661,11 +1677,7 @@
sk->copied_seq = sk->acked_seq;
if(!sk->dead)
sk->state_change(sk);
- if(sk->max_window==0)
- {
- sk->max_window=32; /* Sanity check */
- sk->mss=min(sk->max_window,sk->mtu);
- }
+
/* Reset the RTT estimator to the initial
* state rather than testing to avoid
* updating it on the ACK to the SYN packet.
@@ -2520,6 +2532,13 @@
*/
tcp_ack(sk,th,skb->ack_seq,len);

+ /* We must check here (before tcp_options) whether
+ * peer advertised a zero sized window on us, else
+ * we end up with a zero sk->{mtu,mss} and thus bomb
+ * out in tcp_do_sendmsg. -DaveM
+ */
+ if(sk->max_window == 0)
+ sk->max_window = 32;

/*
* Ok.. it's good. Set up sequence numbers and
@@ -2543,11 +2562,7 @@
sk->state_change(sk);
sock_wake_async(sk->socket, 0);
}
- if(sk->max_window==0)
- {
- sk->max_window = 32;
- sk->mss = min(sk->max_window, sk->mtu);
- }
+
/* Reset the RTT estimator to the initial
* state rather than testing to avoid
* updating it on the ACK to the SYN packet.