From b70d8dde6f35e2656d7a72e6f8125ed1f9a60b24 Mon Sep 17 00:00:00 2001 From: phil <me@filou.se> Date: Wed, 9 Jun 2021 16:55:54 +0200 Subject: [PATCH] upd ipv4 checksum computation and fixes --- scripts/sapd-cmd.sh | 7 ++++++ src/core/def.c | 17 +++++++++++++ src/core/eth.c | 54 +++++++++++++++++++++++++++++++++-------- src/include/aes67/def.h | 2 ++ src/include/aes67/eth.h | 4 +++ src/include/aes67/rtp.h | 4 +-- test/unit/eth.cpp | 38 +++++++++++++++++++++++++---- 7 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 scripts/sapd-cmd.sh diff --git a/scripts/sapd-cmd.sh b/scripts/sapd-cmd.sh new file mode 100644 index 0000000..894ca03 --- /dev/null +++ b/scripts/sapd-cmd.sh @@ -0,0 +1,7 @@ +#!/bin/bash + + +usage(){ + +} + diff --git a/src/core/def.c b/src/core/def.c index 8834a21..99eda2f 100644 --- a/src/core/def.c +++ b/src/core/def.c @@ -267,6 +267,23 @@ u8_t aes67_xor8(u8_t * buf, size_t count) return (xor8 ^ 0xff) + 1; } + +u16_t aes67_16bit_ones_complement_sum(u8_t * bytes, size_t u16_count, u16_t initial_value) +{ + u32_t sum = initial_value; + while(u16_count--){ + sum += *(bytes++) << 8; + sum += *(bytes++); + } + + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + sum = (~sum) & 0xffff; + + return sum; +} + #ifndef aes67_crc32 // https://stackoverflow.com/questions/21001659/crc32-algorithm-implementation-in-c-without-a-look-up-table-and-with-a-public-li diff --git a/src/core/eth.c b/src/core/eth.c index 2a3ac49..424aadc 100644 --- a/src/core/eth.c +++ b/src/core/eth.c @@ -16,22 +16,56 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "aes67/eth.h" +#include <aes67/debug.h> +#include <aes67/eth.h> +#include <aes67/def.h> u16_t aes67_ipv4_header_checksum(u8_t * header) { int len = (header[AES67_IPV4_HEADER_IHL_OFFSET] & AES67_IPV4_HEADER_IHL_MASK) << 1; + return aes67_16bit_ones_complement_sum(header, len, 0); +} - u32_t sum = 0; - while(len--){ - sum += *(header++) << 8; - sum += *(header++); - } +u16_t aes67_udp_checksum(u8_t * ip_header) +{ + // ipv4 + if ((ip_header[AES67_IPV4_HEADER_VERSION_OFFSET] & AES67_IPV4_HEADER_VERSION_MASK) == AES67_IPV4_HEADER_VERSION_4){ + + // total ip packet length + u16_t tlen = aes67_ntohs(*(u16_t*)(ip_header + AES67_IPV4_HEADER_LENGTH_OFFSET)); + + u16_t iphdrlen = ((ip_header[AES67_IPV4_HEADER_IHL_OFFSET] & AES67_IPV4_HEADER_IHL_MASK) << 2); + + // udp header + body length + u16_t udplen = tlen - iphdrlen; + + printf("tlen = %d, iplen = %d, udplen = %d\n", tlen, iphdrlen, udplen); + + // save ttl/checksum and set to pseudo header values + u8_t ttl = ip_header[AES67_IPV4_HEADER_TTL_OFFSET]; + u16_t header_checksum = *(u16_t*)(ip_header + AES67_IPV4_HEADER_HEADER_CHECKSUM_OFFSET); - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); + ip_header[AES67_IPV4_HEADER_TTL_OFFSET] = 0; + *(u16_t*)(ip_header + AES67_IPV4_HEADER_HEADER_CHECKSUM_OFFSET) = aes67_htons(udplen); - sum = (~sum) & 0xffff; + // partial checksum of (pseudo-)header (6 short := 12 octets) + u16_t checksum = aes67_16bit_ones_complement_sum(ip_header + AES67_IPV4_HEADER_TTL_OFFSET, 6, 0); + + // restore original ipv4 header + ip_header[AES67_IPV4_HEADER_TTL_OFFSET] = ttl; + *(u16_t*)(ip_header + AES67_IPV4_HEADER_HEADER_CHECKSUM_OFFSET) = header_checksum; + + // sum of udp (we have to take into account any potential optional ipv4 headers, otherwise we could just go over all at once..) + + checksum = aes67_16bit_ones_complement_sum(ip_header + iphdrlen, udplen >> 1, ~checksum ); + + return checksum; + } + + // ipv6 + if ((ip_header[AES67_IPV4_HEADER_VERSION_OFFSET] & AES67_IPV4_HEADER_VERSION_MASK) == AES67_IPV4_HEADER_VERSION_6){ + // TODO + } - return sum; + AES67_ASSERT("invalid ip header version", 0); } \ No newline at end of file diff --git a/src/include/aes67/def.h b/src/include/aes67/def.h index ab9f0f9..1c60f9d 100644 --- a/src/include/aes67/def.h +++ b/src/include/aes67/def.h @@ -160,6 +160,8 @@ s32_t aes67_atoi(u8_t * str, size_t len, s32_t base, u16_t * readlen); u8_t aes67_xor8(u8_t * buf, size_t count); +u16_t aes67_16bit_ones_complement_sum(u8_t * bytes, size_t u16_count, u16_t initial_value); + #ifndef aes67_crc32 #define AES67_CRC32_VERIFY_VALUE 0x2144DF1C u32_t aes67_crc32(u8_t * buf, size_t count); diff --git a/src/include/aes67/eth.h b/src/include/aes67/eth.h index 8f6fc1c..2a0e753 100644 --- a/src/include/aes67/eth.h +++ b/src/include/aes67/eth.h @@ -72,6 +72,7 @@ extern "C" { #define AES67_IPV4_HEADER_DATA_OFFSET 20 // assuming IHL == 5 (ie no extra headers) #define AES67_IPV4_HEADER_VERSION_4 0x40 +#define AES67_IPV4_HEADER_VERSION_6 0x60 #define AES67_IPV4_HEADER_IHL_BASIC 0x05 #define AES67_IPV4_HEADER_DSCP_DEFAULT 0 @@ -148,8 +149,11 @@ struct aes67_udp_ipv4_pseudoheader { struct aes67_udp_packet udp; }; + u16_t aes67_ipv4_header_checksum(u8_t * header); +u16_t aes67_udp_checksum(u8_t * ip_header); + #ifdef __cplusplus } #endif diff --git a/src/include/aes67/rtp.h b/src/include/aes67/rtp.h index c0e9f16..2e51182 100644 --- a/src/include/aes67/rtp.h +++ b/src/include/aes67/rtp.h @@ -107,7 +107,7 @@ struct aes67_rtp_packet { } PACK_STRUCT; /** - * The data buffer herein is assumed be to interleaved (as L16/24 would have it). + * The data buffer herein is assumed to be interleaved (as L16/24 would have it). */ struct aes67_rtp_buffer { size_t nchannels; @@ -199,7 +199,7 @@ inline ptime_t aes67_rtp_packet2nsamples(void * packet, u16_t len, u32_t nchanne * * It generally is assumed that all sources and sinks are synchronized which implies that * all samples are generally produced and consumed at the same rate - which is why there is no guard - * against overflowing buffers (to keep complexitly lower). A certain degree of asynchronicity is possible. + * against overflowing buffers (to keep complexity lower). A certain degree of asynchronicity is possible. * * Single, serial and block-wise sample buffers operations are available. * diff --git a/test/unit/eth.cpp b/test/unit/eth.cpp index bd198c5..f6b732e 100644 --- a/test/unit/eth.cpp +++ b/test/unit/eth.cpp @@ -31,7 +31,9 @@ TEST(Eth_TestGroup, eth_ipv4_header_checksum) { // without checksum uint8_t ip1[] = { - 0x45, 0x00, 0x00, 0x73, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, + 0x45, 0x00, 0x00, 0x73, + 0x00, 0x00, 0x40, 0x00, + 0x40, 0x11, 0, 0, // checksum 0xc0, 0xa8, 0x00, 0x01, 0xc0, 0xa8, 0x00, 0xc7, // end of header @@ -44,9 +46,11 @@ TEST(Eth_TestGroup, eth_ipv4_header_checksum) { // same WITH checksum uint8_t ip2[] = { - 0x45, 0x00, 0x00, 0x73, 0x00, 0x00, 0x40, 0x00, 0x40, - 0x11, 0xb8, // checksum - 0x61, 0xc0, 0xa8, 0x00, 0x01, + 0x45, 0x00, 0x00, 0x73, + 0x00, 0x00, 0x40, 0x00, + 0x40, 0x11, + 0xb8, 0x61,// checksum + 0xc0, 0xa8, 0x00, 0x01, 0xc0, 0xa8, 0x00, 0xc7, // end of header 0x00, 0x35, 0xe9, 0x7c, 0x00, 0x5f, 0x27, 0x9f, 0x1e, 0x4b, 0x81, 0x80 }; @@ -54,4 +58,28 @@ TEST(Eth_TestGroup, eth_ipv4_header_checksum) { ck = aes67_ipv4_header_checksum(ip2); CHECK_EQUAL(0x0000, ck); -} \ No newline at end of file +} + +TEST(Eth_TestGroup, eth_udp_ipv4_checksum) { + + uint8_t p1[] = { + 0x45, 0x00, 0x00, 0x38, + 0x2f, 0x76, 0x00, 0x00, + 0x01, 0x11, 0xe7, 0x31, + 0xc0, 0xa8, 0x01, 0x69, + 0xe0, 0x00, 0x00, 0xfc, + + 0xcd, 0x71, 0x14, 0xeb, + 0x00, 0x24, + 0,0 , // checksum + + 0x21, 0x44, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x69, 0x61, 0x67, + 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x01, 0x00, + 0x01 + }; + + u16_t ck = aes67_udp_checksum(p1); + + CHECK_EQUAL(0x71d8, ck); +} -- GitLab