aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorMatthew Dillon <dillon@FreeBSD.org>2002-09-17 22:21:37 +0000
committerMatthew Dillon <dillon@FreeBSD.org>2002-09-17 22:21:37 +0000
commitfa55172bc0e8af9bea7614693f22a03372341ea8 (patch)
tree1df0ecdf97420c007f37152749ea782eb9ce8ba4 /sys/netinet
parent37721c830937200b9e0c48230cdd69d1bdf4ec69 (diff)
downloadsrc-fa55172bc0e8af9bea7614693f22a03372341ea8.tar.gz
src-fa55172bc0e8af9bea7614693f22a03372341ea8.zip
Guido reported an interesting bug where an FTP connection between a
Windows 2000 box and a FreeBSD box could stall. The problem turned out to be a timestamp reply bug in the W2K TCP stack. FreeBSD sends a timestamp with the SYN, W2K returns a timestamp of 0 in the SYN+ACK causing FreeBSD to calculate an insane SRTT and RTT, resulting in a maximal retransmit timeout (60 seconds). If there is any packet loss on the connection for the first six or so packets the retransmit case may be hit (the window will still be too small for fast-retransmit), causing a 60+ second pause. The W2K box gives up and closes the connection. This commit works around the W2K bug. 15:04:59.374588 FREEBSD.20 > W2K.1036: S 1420807004:1420807004(0) win 65535 <mss 1460,nop,wscale 2,nop,nop,timestamp 188297344 0> (DF) [tos 0x8] 15:04:59.377558 W2K.1036 > FREEBSD.20: S 4134611565:4134611565(0) ack 1420807005 win 17520 <mss 1460,nop,wscale 0,nop,nop,timestamp 0 0> (DF) Bug reported by: Guido van Rooij <guido@gvr.org>
Notes
Notes: svn path=/head/; revision=103505
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_input.c28
-rw-r--r--sys/netinet/tcp_reass.c28
2 files changed, 46 insertions, 10 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index d8e77b6f7cf6..3563fff73d9f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -988,13 +988,24 @@ after_listen:
tp->snd_nxt = tp->snd_max;
tp->t_badrxtwin = 0;
}
- if ((to.to_flags & TOF_TS) != 0)
+
+ /*
+ * Recalculate the transmit timer / rtt.
+ *
+ * Some boxes send broken timestamp replies
+ * during the SYN+ACK phase, ignore
+ * timestamps of 0 or we could calculate a
+ * huge RTT and blow up the retransmit timer.
+ */
+ if ((to.to_flags & TOF_TS) != 0 &&
+ to.to_tsecr) {
tcp_xmit_timer(tp,
ticks - to.to_tsecr + 1);
- else if (tp->t_rtttime &&
- SEQ_GT(th->th_ack, tp->t_rtseq))
+ } else if (tp->t_rtttime &&
+ SEQ_GT(th->th_ack, tp->t_rtseq)) {
tcp_xmit_timer(tp,
ticks - tp->t_rtttime);
+ }
tcp_xmit_bandwidth_limit(tp, th->th_ack);
acked = th->th_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
@@ -1810,11 +1821,18 @@ process_ACK:
* Since we now have an rtt measurement, cancel the
* timer backoff (cf., Phil Karn's retransmit alg.).
* Recompute the initial retransmit timer.
+ *
+ * Some boxes send broken timestamp replies
+ * during the SYN+ACK phase, ignore
+ * timestamps of 0 or we could calculate a
+ * huge RTT and blow up the retransmit timer.
*/
- if (to.to_flags & TOF_TS)
+ if ((to.to_flags & TOF_TS) != 0 &&
+ to.to_tsecr) {
tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
- else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq))
+ } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
tcp_xmit_timer(tp, ticks - tp->t_rtttime);
+ }
tcp_xmit_bandwidth_limit(tp, th->th_ack);
/*
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index d8e77b6f7cf6..3563fff73d9f 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -988,13 +988,24 @@ after_listen:
tp->snd_nxt = tp->snd_max;
tp->t_badrxtwin = 0;
}
- if ((to.to_flags & TOF_TS) != 0)
+
+ /*
+ * Recalculate the transmit timer / rtt.
+ *
+ * Some boxes send broken timestamp replies
+ * during the SYN+ACK phase, ignore
+ * timestamps of 0 or we could calculate a
+ * huge RTT and blow up the retransmit timer.
+ */
+ if ((to.to_flags & TOF_TS) != 0 &&
+ to.to_tsecr) {
tcp_xmit_timer(tp,
ticks - to.to_tsecr + 1);
- else if (tp->t_rtttime &&
- SEQ_GT(th->th_ack, tp->t_rtseq))
+ } else if (tp->t_rtttime &&
+ SEQ_GT(th->th_ack, tp->t_rtseq)) {
tcp_xmit_timer(tp,
ticks - tp->t_rtttime);
+ }
tcp_xmit_bandwidth_limit(tp, th->th_ack);
acked = th->th_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
@@ -1810,11 +1821,18 @@ process_ACK:
* Since we now have an rtt measurement, cancel the
* timer backoff (cf., Phil Karn's retransmit alg.).
* Recompute the initial retransmit timer.
+ *
+ * Some boxes send broken timestamp replies
+ * during the SYN+ACK phase, ignore
+ * timestamps of 0 or we could calculate a
+ * huge RTT and blow up the retransmit timer.
*/
- if (to.to_flags & TOF_TS)
+ if ((to.to_flags & TOF_TS) != 0 &&
+ to.to_tsecr) {
tcp_xmit_timer(tp, ticks - to.to_tsecr + 1);
- else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq))
+ } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) {
tcp_xmit_timer(tp, ticks - tp->t_rtttime);
+ }
tcp_xmit_bandwidth_limit(tp, th->th_ack);
/*