diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e2cbfc3ffa3f..695f840acc14 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5748,6 +5748,21 @@ static void smc_check_reset_syn(struct tcp_sock *tp) #endif } +static void tcp_try_undo_spurious_syn(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + u32 syn_stamp; + + /* undo_marker is set when SYN or SYNACK times out. The timeout is + * spurious if the ACK's timestamp option echo value matches the + * original SYN timestamp. + */ + syn_stamp = tp->retrans_stamp; + if (tp->undo_marker && syn_stamp && tp->rx_opt.saw_tstamp && + syn_stamp == tp->rx_opt.rcv_tsecr) + tp->undo_marker = 0; +} + static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th) { @@ -5815,6 +5830,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_ecn_rcv_synack(tp, th); tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + tcp_try_undo_spurious_syn(sk); tcp_ack(sk, skb, FLAG_SLOWPATH); /* Ok.. it's good. Set up sequence numbers and diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index f262f2cace29..d4d687330e2b 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -517,7 +517,7 @@ void tcp_init_metrics(struct sock *sk) * initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK * retransmission has occurred. */ - if (tp->total_retrans > 1) + if (tp->total_retrans > 1 && tp->undo_marker) tp->snd_cwnd = 1; else tp->snd_cwnd = tcp_init_cwnd(tp, dst);