diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e806839acdd9..e990d562f5e3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2495,9 +2495,9 @@ static void tcp_conservative_spur_to_response(struct tcp_sock *tp) /* F-RTO spurious RTO detection algorithm (RFC4138) * - * F-RTO affects during two new ACKs following RTO. State (ACK number) is kept - * in frto_counter. When ACK advances window (but not to or beyond highest - * sequence sent before RTO): + * F-RTO affects during two new ACKs following RTO (well, almost, see inline + * comments). State (ACK number) is kept in frto_counter. When ACK advances + * window (but not to or beyond highest sequence sent before RTO): * On First ACK, send two new segments out. * On Second ACK, RTO was likely spurious. Do spurious response (response * algorithm is not part of the F-RTO detection algorithm @@ -2527,6 +2527,13 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) if (flag&FLAG_DATA_ACKED) inet_csk(sk)->icsk_retransmits = 0; + /* RFC4138 shortcoming in step 2; should also have case c): ACK isn't + * duplicate nor advances window, e.g., opposite dir data, winupdate + */ + if ((tp->snd_una == prior_snd_una) && (flag&FLAG_NOT_DUP) && + !(flag&FLAG_FORWARD_PROGRESS)) + return; + if (tp->snd_una == prior_snd_una || !before(tp->snd_una, tp->frto_highmark)) { tcp_enter_frto_loss(sk);