aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2005-10-27 04:47:46 -0400
committerArnaldo Carvalho de Melo <acme@mandriva.com>2005-10-27 13:11:04 -0400
commit2ad41065d9fe518759b695fc2640cf9c07261dd2 (patch)
tree7fdfe22d6e6876c2c3bcf0c6b8883368507952c5
parent7a4ed937aa44acdeb8c6ba671509dc7b54b09d3a (diff)
[TCP]: Clear stale pred_flags when snd_wnd changes
This bug is responsible for causing the infamous "Treason uncloaked" messages that's been popping up everywhere since the printk was added. It has usually been blamed on foreign operating systems. However, some of those reports implicate Linux as both systems are running Linux or the TCP connection is going across the loopback interface. In fact, there really is a bug in the Linux TCP header prediction code that's been there since at least 2.1.8. This bug was tracked down with help from Dale Blount. The effect of this bug ranges from harmless "Treason uncloaked" messages to hung/aborted TCP connections. The details of the bug and fix is as follows. When snd_wnd is updated, we only update pred_flags if tcp_fast_path_check succeeds. When it fails (for example, when our rcvbuf is used up), we will leave pred_flags with an out-of-date snd_wnd value. When the out-of-date pred_flags happens to match the next incoming packet we will again hit the fast path and use the current snd_wnd which will be wrong. In the case of the treason messages, it just happens that the snd_wnd cached in pred_flags is zero while tp->snd_wnd is non-zero. Therefore when a zero-window packet comes in we incorrectly conclude that the window is non-zero. In fact if the peer continues to send us zero-window pure ACKs we will continue making the same mistake. It's only when the peer transmits a zero-window packet with data attached that we get a chance to snap out of it. This is what triggers the treason message at the next retransmit timeout. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
-rw-r--r--net/ipv4/tcp_input.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 677419d0c9ad..3e98b57578dc 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2239,6 +2239,7 @@ static int tcp_ack_update_window(struct sock *sk, struct tcp_sock *tp,
2239 /* Note, it is the only place, where 2239 /* Note, it is the only place, where
2240 * fast path is recovered for sending TCP. 2240 * fast path is recovered for sending TCP.
2241 */ 2241 */
2242 tp->pred_flags = 0;
2242 tcp_fast_path_check(sk, tp); 2243 tcp_fast_path_check(sk, tp);
2243 2244
2244 if (nwin > tp->max_window) { 2245 if (nwin > tp->max_window) {