[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>
This commit is contained in:
parent
ba755f8ec8
commit
1d464c26b5
@ -166,7 +166,7 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr,
|
||||
#else
|
||||
"r" (proto + len),
|
||||
#endif
|
||||
"r" (sum));
|
||||
"r" ((__force unsigned long)sum));
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user