During a recovery, we should always reduce send window if the host is notifying a window reduction.
This is needed because in the recovery phase the host requires to buffer the packets between the beginning of the recovery and the data we're sending "forward" with ssthresh window and sacked_out count. So it isn't buffering the in_flight packets, but a number of packets that could be much higher. If the host asks a window reduction its buffer is filling up, and if we ignore the reduction, when the buffer is full all the packets arriving to the host will be dropped. When the first packet is dropped the host will begin asking for a zero window; this request will be eventually granted, however in the meantime we will have lost a full window of packets. Anyway we could neither set the FLAG_WIN_UPDATE, otherwise the ack will not be considered a DUPACK and when using Reno the sacked_out count will not be updated. Regards, Angelo P. Castellani
diff -urd linux-2.6.16-orig/net/ipv4/tcp_input.c linux-2.6.16-winupdate/net/ipv4/tcp_input.c --- linux-2.6.16-orig/net/ipv4/tcp_input.c 2006-05-16 14:53:02.000000000 +0200 +++ linux-2.6.16-winupdate/net/ipv4/tcp_input.c 2006-07-05 15:38:08.000000000 +0200 @@ -2365,12 +2365,44 @@ { int flag = 0; u32 nwin = ntohs(skb->h.th->window); + struct inet_connection_sock *icsk = inet_csk(sk); + int silent_update = 0; if (likely(!skb->h.th->syn)) nwin <<= tp->rx_opt.snd_wscale; - if (tcp_may_update_window(tp, ack, ack_seq, nwin)) { - flag |= FLAG_WIN_UPDATE; + /* + * During a recovery, we should always reduce send window if the host + * is notifying a window reduction. + * + * This is needed because in the recovery phase the host requires + * to buffer the packets between the beginning of the recovery + * and the data we're sending "forward" with ssthresh window and + * sacked_out count. + * + * So it isn't buffering the in_flight packets, but a number of packets + * that could be much higher. + * + * If the host asks a window reduction its buffer is filling up, and if we + * ignore the reduction, when the buffer is full all the packets arriving + * to the host will be dropped. + * + * When the first packet is dropped the host will begin asking for a zero + * window; this request will be eventually granted, however in the + * meantime we will have lost a full window of packets. + * + * Anyway we could neither set the FLAG_WIN_UPDATE, otherwise the + * ack will not be considered a DUPACK and when using Reno the + * sacked_out count will not be updated. + * + */ + if (icsk->icsk_ca_state == TCP_CA_Recovery && + nwin < tp->snd_wnd) + silent_update = 1; + + if (silent_update || tcp_may_update_window(tp, ack, ack_seq, nwin)) { + if (!silent_update) + flag |= FLAG_WIN_UPDATE; tcp_update_wl(tp, ack, ack_seq); if (tp->snd_wnd != nwin) {