- Update Makefile:
- Change test binary name to `libicmp.test`.
- Add `-Wpedantic` and `-Wconversion` to global CFLAGS for stricter
warnings.
- Add dedicated `TEST_CFLAGS`.
- Ensure test build uses `TEST_CFLAGS`.
- Refactor code for better correctness.
BREAKING CHANGE: Test binary is now named `libicmp.test` instead of
`test.out` and stricter compiler flags may trigger new warnings or
errors in code outside this patch.
64 lines
1.4 KiB
C
64 lines
1.4 KiB
C
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
/* Forward Declarations */
|
|
static inline uint16_t read_be16(const uint8_t *ptr);
|
|
static uint32_t sum_words(const uint8_t *data, size_t len);
|
|
static inline uint16_t fold_carries(uint32_t sum);
|
|
/* -------------------- */
|
|
|
|
/* RFC 1071: Compute ICMP checksum (16-bit one's complement sum) */
|
|
uint16_t
|
|
icmp_checksum(const void *data, size_t len)
|
|
{
|
|
uint32_t sum;
|
|
|
|
sum = sum_words(data, len);
|
|
sum = fold_carries(sum);
|
|
|
|
return (uint16_t)~sum;
|
|
}
|
|
|
|
/* Sum all 16-bit words */
|
|
static uint32_t
|
|
sum_words(const uint8_t *data, size_t len)
|
|
{
|
|
const uint8_t *ptr = data;
|
|
uint32_t sum = 0;
|
|
size_t words = len >> 1;
|
|
|
|
/* Duff's device: unroll loop by 4 */
|
|
if (words > 0)
|
|
{
|
|
size_t n = (words + 3) >> 2;
|
|
switch (words & 3) {
|
|
case 0: do { sum += read_be16(ptr); ptr += 2;
|
|
case 3: sum += read_be16(ptr); ptr += 2;
|
|
case 2: sum += read_be16(ptr); ptr += 2;
|
|
case 1: sum += read_be16(ptr); ptr += 2;
|
|
} while (--n > 0);
|
|
}
|
|
}
|
|
|
|
/* Handle odd byte if present */
|
|
if (len & 1)
|
|
sum += (uint32_t)(*ptr << 8);
|
|
|
|
return sum;
|
|
}
|
|
|
|
/* Fold 32-bit sum to 16 bits by adding carry bits back */
|
|
static inline uint16_t
|
|
fold_carries(uint32_t sum)
|
|
{
|
|
while (sum >> 16)
|
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
return (uint16_t)sum;
|
|
}
|
|
|
|
/* Read 16-bit word in network byte order (big-endian) */
|
|
static inline uint16_t
|
|
read_be16(const uint8_t *ptr)
|
|
{
|
|
return (uint16_t)((*ptr << 8) | ptr[1]);
|
|
}
|