diff --git a/sys/net/crosslayer/ng_inet_csum/ng_inet_csum.c b/sys/net/crosslayer/ng_inet_csum/ng_inet_csum.c index b4447814d579450945fe8a432e5b1072c2602b64..f38935bbf6f5f1af7403ad81cb2ed2f430a17b29 100644 --- a/sys/net/crosslayer/ng_inet_csum/ng_inet_csum.c +++ b/sys/net/crosslayer/ng_inet_csum/ng_inet_csum.c @@ -43,11 +43,14 @@ uint16_t ng_inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len) csum += (*buf << 8); /* add last byte as top half of 16-byte word */ } - csum += csum >> 16; + while (csum >> 16) { + uint16_t carry = csum >> 16; + csum = (csum & 0xffff) + carry; + } - DEBUG("inet_sum: new sum = 0x%04" PRIx32 "\n", csum & 0xffff); + DEBUG("inet_sum: new sum = 0x%04" PRIx32 "\n", csum); - return (csum & 0xffff); + return csum; } /** @} */ diff --git a/tests/unittests/tests-inet_csum/tests-inet_csum.c b/tests/unittests/tests-inet_csum/tests-inet_csum.c index 1bbb7ee77c6e96af1129b846afe164037c252053..589d18f32e4bbb4eab2184e2434ca97e34bea6f4 100644 --- a/tests/unittests/tests-inet_csum/tests-inet_csum.c +++ b/tests/unittests/tests-inet_csum/tests-inet_csum.c @@ -75,6 +75,21 @@ static void test_inet_csum__set_initial_sum(void) TEST_ASSERT_EQUAL_INT(0xffff, ng_inet_csum(0x38 + 0x3a, data, sizeof(data))); } +static void test_inet_csum__wraps_more_than_once(void) +{ + /* catches the corner-case that the internal wrap-around does not suffice + * to be done once */ + uint8_t data[] = { + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x86, 0xcd, 0xff, 0xfe, 0x0f, 0xce, 0x49, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0xaa, 0x2d, 0xff, 0xfe, 0x44, 0x43, 0xac + }; + + /* values were taken from a case I encountered in the wild */ + TEST_ASSERT_EQUAL_INT(0x0002, ng_inet_csum(0x1785, data, sizeof(data))); +} + static void test_inet_csum__calculate_csum(void) { /* source: http://en.wikipedia.org/w/index.php?title=IPv4_header_checksum&oldid=645516564 @@ -112,6 +127,7 @@ Test *tests_inet_csum_tests(void) new_TestFixture(test_inet_csum__rfc_example), new_TestFixture(test_inet_csum__ipv6_pseudo_hdr), new_TestFixture(test_inet_csum__set_initial_sum), + new_TestFixture(test_inet_csum__wraps_more_than_once), new_TestFixture(test_inet_csum__calculate_csum), new_TestFixture(test_inet_csum__odd_len), };