Skip to content

Commit 730c122

Browse files
committed
[test] Fix RFC 1071 checksum calculation for big-endian targets
Calculation of the TCP/IP checksum is fundamentally endian-agnostic: the checksum is designed to be symmetric so that both big-endian and little-endian systems can use native addition in any word size without any byte swapping. The result is then stored into the checksum field in the packet header as a native-endian value. The reference algorithm presented in RFC 1071 (and used in our test suite) is implicitly little-endian: the trailing byte is on a 16-bit word boundary and is added to the least significant byte of the 16-bit checksum value. Fix by shifting the trailing byte by 8 bits on big-endian targets. Signed-off-by: Michael Brown <mcb30@ipxe.org>
1 parent 8570052 commit 730c122

1 file changed

Lines changed: 5 additions & 1 deletion

File tree

src/tests/tcpip_test.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ TCPIP_RANDOM_TEST ( partial, 0xcafebabe, 121, 5 );
140140
* negative zero (0xffff) if the input data is zero length (or all
141141
* zeros) but positive zero (0x0000) for any other data which sums to
142142
* zero.
143+
*
144+
* A shift is applied to the trailing byte to ensure that the correct
145+
* result is calculated on a big-endian system.
143146
*/
144147
static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) {
148+
unsigned int shift = ( ( __BYTE_ORDER == __BIG_ENDIAN ) ? 8 : 0 );
145149
unsigned long sum = 0xffff;
146150

147151
while ( len > 1 ) {
@@ -151,7 +155,7 @@ static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) {
151155
}
152156

153157
if ( len > 0 )
154-
sum += *( ( uint8_t * ) data );
158+
sum += ( *( ( uint8_t * ) data ) << shift );
155159

156160
while ( sum >> 16 )
157161
sum = ( ( sum & 0xffff ) + ( sum >> 16 ) );

0 commit comments

Comments
 (0)