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