diff --git a/CMakeLists.txt b/CMakeLists.txt index ba8d1d90bdb54de37a3e23de29fce1b859fd62d6..011e57cb1c192fc3146abaa79d528e43980b65ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ set(AES67_INCLUDES ${AES67_DIR}/src/include/aes67/rtp-avp.h ${AES67_DIR}/src/include/aes67/rtp.h ${AES67_DIR}/src/include/aes67/audio.h + ${AES67_DIR}/src/include/aes67/eth.h ${AES67_DIR}/src/include/aes67/host/time.h ${AES67_DIR}/src/include/aes67/host/timer.h @@ -69,6 +70,7 @@ set(AES67_SOURCE_FILES ${AES67_DIR}/src/core/sdp.c ${AES67_DIR}/src/core/sap.c ${AES67_DIR}/src/core/rtp.c + ${AES67_DIR}/src/core/eth.c ) diff --git a/README.md b/README.md index 63b46a4a4ed283f1c80eb6d75ad5737ea6a6d343..02f76c8b434daee7e5bdd77f2200be3f44b4424d 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ https://github.com/tschiemer/aes67 - Stream - - [ ] RTP/RTCP + - [ ] RTP + - [ ] RTCP - Command line / developer utilities diff --git a/src/core/eth.c b/src/core/eth.c new file mode 100644 index 0000000000000000000000000000000000000000..2a3ac496ff101d9a9d8f97894020da8c8428af11 --- /dev/null +++ b/src/core/eth.c @@ -0,0 +1,37 @@ +/** + * AES67 Framework + * Copyright (C) 2021 Philip Tschiemer, https://github.com/tschiemer/aes67 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "aes67/eth.h" + +u16_t aes67_ipv4_header_checksum(u8_t * header) +{ + int len = (header[AES67_IPV4_HEADER_IHL_OFFSET] & AES67_IPV4_HEADER_IHL_MASK) << 1; + + u32_t sum = 0; + while(len--){ + sum += *(header++) << 8; + sum += *(header++); + } + + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + sum = (~sum) & 0xffff; + + return sum; +} \ No newline at end of file diff --git a/src/include/aes67/def.h b/src/include/aes67/def.h index 21859f199a5176b834b15130b34a1314a82e98b2..ab9f0f91bdc69fc44d494ed9740d7f239543092b 100644 --- a/src/include/aes67/def.h +++ b/src/include/aes67/def.h @@ -161,6 +161,7 @@ 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); #ifndef aes67_crc32 +#define AES67_CRC32_VERIFY_VALUE 0x2144DF1C u32_t aes67_crc32(u8_t * buf, size_t count); #endif diff --git a/src/include/aes67/eth.h b/src/include/aes67/eth.h new file mode 100644 index 0000000000000000000000000000000000000000..8f6fc1ccf4781b3a33560a975a78f612abfe3e49 --- /dev/null +++ b/src/include/aes67/eth.h @@ -0,0 +1,157 @@ +/** + * @file eth.h + * Lower level networking utilities, ethernet, ip, udp. + * + * References: + * AES67-2018 https://www.aes.org/publications/standards/search.cfm?docID=96 + */ + +/** + * AES67 Framework + * Copyright (C) 2021 Philip Tschiemer, https://github.com/tschiemer/aes67 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AES67_ETH_H +#define AES67_ETH_H + +#include "aes67/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//#define AES67_ETH_HEADER_DST 0 +//#define AES67_ETH_HEADER_SRC 6 +//#define + +#define AES67_ETH_ETHERTYPE_IPv4 0x0800 +#define AES67_ETH_ETHERTYPE_ARP 0x0806 // address resolution protocol +#define AES67_ETH_ETHERTYPE_AVTP 0x22f0 // audio video transport protocol +#define AES67_ETH_ETHERTYPE_SRP 0x22ea // stream reservation protocol +#define AES67_ETH_ETHERTYPE_IPv6 0x86dd +#define AES67_ETH_ETHERTYPE_VLAN_TAG 0x8100 +#define AES67_ETH_ETHERTYPE_IPv6 0x86dd +#define AES67_ETH_ETHERTYPE_CobraNet 0x8819 + +//#define AES67_ETH_CRC32_POLY 0x04c11db7 +//#define AES67_ETH_CRC32_INITIAL 0xffffffff + +#define AES67_IPV4_HEADER_MINSIZE 20 + +#define AES67_IPV4_HEADER_VERSION_OFFSET 0 +#define AES67_IPV4_HEADER_VERSION_MASK 0xf0 +#define AES67_IPV4_HEADER_IHL_OFFSET 0 +#define AES67_IPV4_HEADER_IHL_MASK 0x0f +#define AES67_IPV4_HEADER_DSCP_OFFSET 1 // Differentiated Services Code Point (DiffServ) +#define AES67_IPV4_HEADER_DSCP_MASK 0b11111100 +#define AES67_IPV4_HEADER_ECN_OFFSET 1 // Explicit Congestion Notification +#define AES67_IPV4_HEADER_ECN_MASK 0b11 +#define AES67_IPV4_HEADER_LENGTH_OFFSET 2 +#define AES67_IPV4_HEADER_IDENTIFICATION_OFFSET 4 +#define AES67_IPV4_HEADER_FRAGMENTATION_OFFSET 6 +#define AES67_IPV4_HEADER_FRAGMENTATION_FLAGS_MASK 0b1110000000000000 +#define AES67_IPV4_HEADER_FRAGMENTATION_FOFFSET_MASK 0b000111111111111 +#define AES67_IPV4_HEADER_TTL_OFFSET 8 +#define AES67_IPV4_HEADER_PROTOCOL_OFFSET 9 +#define AES67_IPV4_HEADER_HEADER_CHECKSUM_OFFSET 10 +#define AES67_IPV4_HEADER_SOURCE_OFFSET 12 +#define AES67_IPV4_HEADER_DESTINATION_OFFSET 16 +#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_IHL_BASIC 0x05 + +#define AES67_IPV4_HEADER_DSCP_DEFAULT 0 +#define AES67_IPV4_HEADER_DSCP_DEFAULT_CLOCK (46<<2) // Class EF +#define AES67_IPV4_HEADER_DSCP_DEFAULT_MEDIA (34<<2) // Class AF41 + +#define AES67_IPV4_HEADER_ECN_NON_ECT 0 // Non ECN capable transport +#define AES67_IPV4_HEADER_ECN_ECT0 1 // ECN capable transport 0 +#define AES67_IPV4_HEADER_ECN_ECT1 2 // ECN capable transport 1 +#define AES67_IPV4_HEADER_ECN_CE 3 // Congestion encountered + + +#define AES67_IPV4_HEADER_FRAGMENTATION_FLAGS_DF 0b0100000000000000 // don't fragment +#define AES67_IPV4_HEADER_FRAGMENTATION_FLAGS_MF 0b0010000000000000 // more fragments + +#define AES67_IPV4_HEADER_PROTOCOL_ICMP 0x01 +#define AES67_IPV4_HEADER_PROTOCOL_IGMP 0x02 +#define AES67_IPV4_HEADER_PROTOCOL_TCP 0x06 +#define AES67_IPV4_HEADER_PROTOCOL_UDP 0x11 +#define AES67_IPV4_HEADER_PROTOCOL_RSVP 0x2e + +// No 802.1Q headers +struct aes67_eth_frame { + u8_t destination[6]; + u8_t source[6]; + u8_t tpid[2]; + u16_t length; + u8_t data[]; +} PACK_STRUCT; + + +struct aes67_ipv4_packet { + u8_t byte0; // version + IHL + u8_t byte1; // DSCP + ECN + u16_t length; // total packet size (header + data, >= 20) + u16_t identification; // fragmentation identification + u16_t fragmentation; // flags + offset + u8_t ttl; // time to live + u8_t protocol; // + u16_t header_checksum; // The checksum field is the 16-bit ones' complement of the ones' complement sum of all + // 16-bit words in the header. For purposes of computing the checksum, the value of the + // checksum field is zero. + union { + u8_t bytes[4]; + u32_t value; + } PACK_STRUCT source; + union { + u8_t bytes[4]; + u32_t value; + } PACK_STRUCT destination; + u8_t data[]; +} PACK_STRUCT; + +struct aes67_udp_packet { + u16_t source_port; + u16_t destination_port; + u16_t length; + u16_t checksum; + u8_t data[]; +} PACK_STRUCT; + +struct aes67_udp_ipv4_pseudoheader { + union { + u8_t bytes[4]; + u32_t value; + } PACK_STRUCT source; + union { + u8_t bytes[4]; + u32_t value; + } PACK_STRUCT destination; + u8_t zeroes; + u8_t protocol; + u16_t udp_length; + struct aes67_udp_packet udp; +}; + +u16_t aes67_ipv4_header_checksum(u8_t * header); + +#ifdef __cplusplus +} +#endif + +#endif //AES67_ETH_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fbf7bf4920bd7bb0b714375ca4cabd7bcdf65a80..8d0ecea2bc0314d7c2f8d595a3929eae2b9e3d41 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,6 +30,7 @@ set(TEST_UNIT_SOURCE_FILES unit/sap.cpp unit/sdp.cpp unit/rtp.cpp + unit/eth.cpp ) diff --git a/test/unit/eth.cpp b/test/unit/eth.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd198c52afca5e31a4eb7d0848f0549a7c68c6ad --- /dev/null +++ b/test/unit/eth.cpp @@ -0,0 +1,57 @@ +/** + * AES67 Framework + * Copyright (C) 2021 Philip Tschiemer, https://github.com/tschiemer/aes67 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "CppUTest/TestHarness.h" + +#include <string> + +#include "aes67/eth.h" + +TEST_GROUP(Eth_TestGroup){}; + +TEST(Eth_TestGroup, eth_ipv4_header_checksum) { + + // test value from https://en.wikipedia.org/wiki/IPv4_header_checksum + + // without checksum + uint8_t ip1[] = { + 0x45, 0x00, 0x00, 0x73, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, + 0, 0, // checksum + 0xc0, 0xa8, 0x00, 0x01, + 0xc0, 0xa8, 0x00, 0xc7, // end of header + 0x00, 0x35, 0xe9, 0x7c, 0x00, 0x5f, 0x27, 0x9f, 0x1e, 0x4b, 0x81, 0x80 + }; + + u16_t ck = aes67_ipv4_header_checksum(ip1); + + CHECK_EQUAL(0xb861, ck); + + // same WITH checksum + uint8_t ip2[] = { + 0x45, 0x00, 0x00, 0x73, 0x00, 0x00, 0x40, 0x00, 0x40, + 0x11, 0xb8, // checksum + 0x61, 0xc0, 0xa8, 0x00, 0x01, + 0xc0, 0xa8, 0x00, 0xc7, // end of header + 0x00, 0x35, 0xe9, 0x7c, 0x00, 0x5f, 0x27, 0x9f, 0x1e, 0x4b, 0x81, 0x80 + }; + + ck = aes67_ipv4_header_checksum(ip2); + + CHECK_EQUAL(0x0000, ck); +} \ No newline at end of file