From 730c122c1dca346094294b084922a7e0d6df131c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 13 Jun 2026 16:15:57 +0100 Subject: [PATCH] [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 --- src/tests/tcpip_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tests/tcpip_test.c b/src/tests/tcpip_test.c index fac0ec26d..de1ad06f8 100644 --- a/src/tests/tcpip_test.c +++ b/src/tests/tcpip_test.c @@ -140,8 +140,12 @@ TCPIP_RANDOM_TEST ( partial, 0xcafebabe, 121, 5 ); * negative zero (0xffff) if the input data is zero length (or all * zeros) but positive zero (0x0000) for any other data which sums to * zero. + * + * A shift is applied to the trailing byte to ensure that the correct + * result is calculated on a big-endian system. */ static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) { + unsigned int shift = ( ( __BYTE_ORDER == __BIG_ENDIAN ) ? 8 : 0 ); unsigned long sum = 0xffff; while ( len > 1 ) { @@ -151,7 +155,7 @@ static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) { } if ( len > 0 ) - sum += *( ( uint8_t * ) data ); + sum += ( *( ( uint8_t * ) data ) << shift ); while ( sum >> 16 ) sum = ( ( sum & 0xffff ) + ( sum >> 16 ) );