• Dave Johnson's avatar
    [MIPS] Fix wrong checksum for split TCP packets on 64-bit MIPS · 1d464c26
    Dave Johnson authored
    I've traced down an off-by-one TCP checksum calculation error under
    the following conditions:
    
    1) The TCP code needs to split a full-sized packet due to a reduced
       MSS (typically due to the addition of TCP options mid-stream like
       SACK).
       _AND_
    2) The checksum of the 2nd fragment is larger than the checksum of the
       original packet.  After subtraction this results in a checksum for
       the 1st fragment with bits 16..31 set to 1. (this is ok)
       _AND_
    3) The checksum of the 1st fragment's TCP header plus the previously
       32bit checksum of the 1st fragment DOES NOT cause a 32bit overflow
       when added together.  This results in a checksum of the TCP header
       plus TCP data that still has the upper 16 bits as 1's.
       _THEN_
    4) The TCP+data checksum is added to the checksum of the pseudo IP
       header with csum_tcpudp_nofold() incorrectly (the bug).
        
    The problem is the checksum of the TCP+data is passed to
    csum_tcpudp_nofold() as an 32bit unsigned value, however the assembly
    code acts on it as if it is a 64bit unsigned value.
    
    This causes an incorrect 32->64bit extension if the sum has bit 31
    set.  The resulting checksum is off by one.
        
    This problems is data and TCP header dependent due to #2 and #3
    above so it doesn't occur on every TCP packet split.
    Signed-off-by: default avatarDave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
    Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
    1d464c26
checksum.h 5.68 KB