Browse Source

Add inet_csum_slice() to fix checksum for a sliced layer 4 payload

Padding for an odd number of bytes was not calculated properly.
cc430
Ken Bannister 7 years ago
parent
commit
835a2d8a27
  1. 39
      sys/include/net/inet_csum.h
  2. 17
      sys/net/crosslayer/inet_csum/inet_csum.c

39
sys/include/net/inet_csum.h

@ -21,13 +21,15 @@
#define INET_CSUM_H_
#include <inttypes.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Calculates the unnormalized Internet Checksum of @p buf.
* @brief Calculates the unnormalized Internet Checksum of @p buf, where the
* buffer provides a slice of the full checksum domain, calculated in order.
*
* @see <a href="https://tools.ietf.org/html/rfc1071">
* RFC 1071
@ -35,14 +37,41 @@ extern "C" {
*
* @details The Internet Checksum is not normalized (i. e. its 1's complement
* was not taken of the result) to use it for further calculation.
* This function handles padding an odd number of bytes across the full domain.
*
* @param[in] sum An initial value for the checksum.
* @param[in] buf A buffer.
* @param[in] len Length of @p buf in byte.
* @param[in] sum An initial value for the checksum.
* @param[in] buf A buffer.
* @param[in] len Length of @p buf in byte.
* @param[in] accum_len Accumulated length of checksum domain that has already
* been checksummed.
*
* @return The unnormalized Internet Checksum of @p buf.
*/
uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len);
uint16_t inet_csum_slice(uint16_t sum, const uint8_t *buf, uint16_t len, size_t accum_len);
/**
* @brief Calculates the unnormalized Internet Checksum of @p buf, where the
* buffer provides a standalone domain for the checksum.
*
* @see <a href="https://tools.ietf.org/html/rfc1071">
* RFC 1071
* </a>
*
* @details The Internet Checksum is not normalized (i. e. its 1's complement
* was not taken of the result) to use it for further calculation.
* This function, rather than inet_csum_slice(), has been used historically
* when we are not concerned with padding for an odd number of bytes.
*
*
* @param[in] sum An initial value for the checksum.
* @param[in] buf A buffer.
* @param[in] len Length of @p buf in byte.
*
* @return The unnormalized Internet Checksum of @p buf.
*/
static inline uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len) {
return inet_csum_slice(sum, buf, len, 0);
}
#ifdef __cplusplus
}

17
sys/net/crosslayer/inet_csum/inet_csum.c

@ -20,7 +20,7 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len)
uint16_t inet_csum_slice(uint16_t sum, const uint8_t *buf, uint16_t len, size_t accum_len)
{
uint32_t csum = sum;
@ -34,14 +34,23 @@ uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len)
#endif
#endif
if (len == 0)
return csum;
if (accum_len & 1) { /* if accumulated length is odd */
csum += *buf; /* add first byte as bottom half of 16-byte word */
buf++;
len--;
accum_len++;
}
for (int i = 0; i < (len >> 1); buf += 2, i++) {
csum += (*buf << 8) + *(buf + 1); /* group bytes by 16-byte words
* and add them*/
}
if (len & 1) { /* if len is odd */
csum += (*buf << 8); /* add last byte as top half of 16-byte word */
}
if ((accum_len + len) & 1) /* if accumulated length is odd */
csum += (*buf << 8); /* add last byte as top half of 16-byte word */
while (csum >> 16) {
uint16_t carry = csum >> 16;

Loading…
Cancel
Save