diff options
Diffstat (limited to 'src/putils.c')
-rw-r--r-- | src/putils.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/src/putils.c b/src/putils.c index 3f8563d..3ae1baf 100644 --- a/src/putils.c +++ b/src/putils.c @@ -162,25 +162,44 @@ static inline uint16_t get_n16bit(uint8_t const * cbuf) uint16_t icmp_checksum_iovec(struct iovec const * iovec, size_t iovec_size) { uint32_t checksum = 0; + uint16_t result; + uint8_t is_overlapping = 0; + uint8_t overlap[2] = {0x00, 0x00}; for (size_t iov_i = 0; iov_i < iovec_size; ++iov_i) { uint8_t const * buf = iovec[iov_i].iov_base; size_t len = iovec[iov_i].iov_len; + if (is_overlapping != 0 && len > 0) { + overlap[1] = buf[0]; + checksum += get_n16bit(overlap); + buf++; + len--; + is_overlapping = 0; + } + for (; len > 1; len -= 2) { checksum += get_n16bit(buf); buf += 2; } if (len == 1) { - checksum += *buf; + overlap[0] = *buf; + is_overlapping = 1; } } - checksum = (checksum >> 16) + (checksum & 0xFFFF); - checksum += (checksum >> 16); + if (is_overlapping != 0) { + checksum += overlap[0]; + } + + while (checksum >> 16 > 0) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + + result = ~checksum; - return ~checksum; + return result; } uint16_t icmp_generate_identifier(void) |