aboutsummaryrefslogtreecommitdiff
path: root/src/putils.c
diff options
context:
space:
mode:
authorlns <matzeton@googlemail.com>2022-06-09 16:46:41 +0200
committerlns <matzeton@googlemail.com>2022-06-09 16:46:41 +0200
commit5825a6dd3781f4f1a37d6924f18f2bfdf34858d6 (patch)
treea75d13590292d23d218aa628c28079a2966ecfc9 /src/putils.c
parentf8904fcfbbeb0336b0516d75c758322cce12de7d (diff)
Signed-off-by: lns <matzeton@googlemail.com>
Diffstat (limited to 'src/putils.c')
-rw-r--r--src/putils.c27
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)