mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-28 16:01:18 +01:00
Add inet_csum_slice() to fix checksum for a sliced layer 4 payload
Padding for an odd number of bytes was not calculated properly.
This commit is contained in:
parent
851695cda8
commit
835a2d8a27
@ -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
|
||||
}
|
||||
|
||||
@ -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…
x
Reference in New Issue
Block a user