From 66bc2ffbe6636ba8e3c512e89cc372b467c94e21 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Mon, 31 Oct 2022 14:48:46 +0800 Subject: [PATCH] net/utils: add net_chksum_adjust defined by RFC3022 net_chksum_adjust is used for fast checksum adjustment after modifying some fields in a network packet. Will be used in NAT. Signed-off-by: Zhe Weng --- net/utils/net_chksum.c | 65 ++++++++++++++++++++++++++++++++++++++++++ net/utils/utils.h | 22 ++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/net/utils/net_chksum.c b/net/utils/net_chksum.c index 13737714a4c..311dc7e665b 100644 --- a/net/utils/net_chksum.c +++ b/net/utils/net_chksum.c @@ -123,4 +123,69 @@ uint16_t net_chksum(FAR uint16_t *data, uint16_t len) } #endif /* CONFIG_NET_ARCH_CHKSUM */ +/**************************************************************************** + * Name: net_chksum_adjust + * + * Description: + * Adjusts the checksum of a packet without having to completely + * recalculate it, as described in RFC 3022, Section 4.2, Page 9. + * + * Input Parameters: + * chksum - points to the chksum in the packet + * optr - points to the old data in the packet + * olen - length of old data + * nptr - points to the new data in the packet + * nlen - length of new data + * + * Limitations: + * The algorithm is applicable only for even offsets and even lengths. + ****************************************************************************/ + +void net_chksum_adjust(FAR uint16_t *chksum, + FAR const uint16_t *optr, ssize_t olen, + FAR const uint16_t *nptr, ssize_t nlen) +{ +#ifdef CONFIG_ENDIAN_BIG +# warning "Not verified on big-endian yet." +#endif + + int32_t x; + int32_t oldval; + int32_t newval; + + x = NTOHS(*chksum); + x = ~x & 0xffff; + while (olen > 0) + { + oldval = NTOHS(*optr); + + x -= oldval & 0xffff; + if (x <= 0) + { + x--; + x &= 0xffff; + } + + optr++; + olen -= 2; + } + while (nlen > 0) + { + newval = NTOHS(*nptr); + + x += newval & 0xffff; + if ((x & 0x10000) != 0) + { + x++; + x &= 0xffff; + } + + nptr++; + nlen -= 2; + } + + x = ~x & 0xffff; + *chksum = HTONS(x); +} + #endif /* CONFIG_NET */ diff --git a/net/utils/utils.h b/net/utils/utils.h index 06d6d3a44a4..a891f1682d0 100644 --- a/net/utils/utils.h +++ b/net/utils/utils.h @@ -238,6 +238,28 @@ uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len); uint16_t net_chksum(FAR uint16_t *data, uint16_t len); +/**************************************************************************** + * Name: net_chksum_adjust + * + * Description: + * Adjusts the checksum of a packet without having to completely + * recalculate it, as described in RFC 3022, Section 4.2, Page 9. + * + * Input Parameters: + * chksum - points to the chksum in the packet + * optr - points to the old data in the packet + * olen - length of old data + * nptr - points to the new data in the packet + * nlen - length of new data + * + * Limitations: + * The algorithm is applicable only for even offsets and even lengths. + ****************************************************************************/ + +void net_chksum_adjust(FAR uint16_t *chksum, + FAR const uint16_t *optr, ssize_t olen, + FAR const uint16_t *nptr, ssize_t nlen); + /**************************************************************************** * Name: ipv4_upperlayer_chksum *