Bug in tcp_output?

Rui Paulo rpaulo at freebsd.org
Sat Mar 20 11:14:12 UTC 2010


On 18 Mar 2010, at 20:19, Chris Harrer wrote:

> Hi All,
> 
> 
> 
> In the following block of code, running on a x86_64 platform, I believe that
> cwin should be declared as an int:
> 
>        /*
> 
>         * If snd_nxt == snd_max and we have transmitted a FIN, the
> 
>         * offset will be > 0 even if so_snd.sb_cc is 0, resulting in
> 
>         * a negative length.  This can also occur when TCP opens up
> 
>         * its congestion window while receiving additional duplicate
> 
>         * acks after fast-retransmit because TCP will reset snd_nxt
> 
>         * to snd_max after the fast-retransmit.
> 
>         *
> 
>         * In the normal retransmit-FIN-only case, however, snd_nxt will
> 
>         * be set to snd_una, the offset will be 0, and the length may
> 
>         * wind up 0.
> 
>         *
> 
>         * If sack_rxmit is true we are retransmitting from the scoreboard
> 
>         * in which case len is already set.
> 
>         */
> 
>        if (sack_rxmit == 0) {
> 
>               if (sack_bytes_rxmt == 0)
> 
>                       len = ((long)ulmin(so->so_snd.sb_cc, sendwin) - off);
> 
>               else {
> 
>                       long cwin;  ß-- Should be an int
> 
> 
> 
>                        /*
> 
>                        * We are inside of a SACK recovery episode and are
> 
>                        * sending new data, having retransmitted all the
> 
>                        * data possible in the scoreboard.
> 
>                        */
> 
>                       len = ((long)ulmin(so->so_snd.sb_cc, tp->snd_wnd) 
> 
>                              - off);
> 
>                       /*
> 
>                        * Don't remove this (len > 0) check !
> 
>                        * We explicitly check for len > 0 here (although it 
> 
>                        * isn't really necessary), to work around a gcc 
> 
>                        * optimization issue - to force gcc to compute
> 
>                        * len above. Without this check, the computation
> 
>                        * of len is bungled by the optimizer.
> 
>                        */
> 
>                       if (len > 0) {
> 
>                               cwin = tp->snd_cwnd - 
> 
>                                      (tp->snd_nxt - tp->sack_newdata) -
> 
>                                      sack_bytes_rxmt;
> 
>                               if (cwin < 0)
> 
>                                      cwin = 0;
> 
>                               len = lmin(len, cwin);
> 
>                       }
> 
>               }
> 
>        }
> 
> 
> 
> Consider the case where:
> 
> sack_rxmit = 0
> 
> sack_bytes_rxmt = 0x2238
> 
> off = 0
> 
> len =0xa19c
> 
> tp->snd_cwnd = 0x2238
> 
> tp->snd_nxt = 0xdd6d7974
> 
> tp->sack_newdata = 0xdd6d6858
> 
> In this case cwin evaluates to 0x00000000ffffe37c, which is not <0, but
> instead huge.  This causes the remaining data on the socket’s so->so_snd
> buffer to be sent to the network causing more problems at the receiver which
> is already dropping frames.

I see. This is most likely a bug. Can you send-pr so this doesn't get lost?

Regards,
--
Rui Paulo



More information about the freebsd-net mailing list