[MIPS] Fix wrong checksum for split TCP packets on 64-bit MIPS
authorDave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
Wed, 18 Apr 2007 14:39:41 +0000 (10:39 -0400)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 20 Apr 2007 13:58:37 +0000 (14:58 +0100)
commit1d464c26b5625215c4b35fb336c8f3c57d248c2e
tree88316e8149c4125dbdb55ff90a4e8d45a024940b
parentba755f8ec80fdbf2b5212622eabf7355464c6327
[MIPS] Fix wrong checksum for split TCP packets on 64-bit MIPS

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: Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
include/asm-mips/checksum.h