#include #include /* 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]); }