From 9c30851b454fd4ecc253e1e6bb988e88a9ff4d79 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sat, 28 Mar 2015 14:05:17 +0100 Subject: [PATCH 1/2] ipv6_hdr: Initial import --- Makefile.dep | 5 + sys/Makefile | 3 + sys/include/net/ng_ipv6.h | 1 + sys/include/net/ng_ipv6/hdr.h | 324 ++++++++++++++++++ sys/net/network_layer/ng_ipv6/hdr/Makefile | 3 + .../network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c | 85 +++++ 6 files changed, 421 insertions(+) create mode 100644 sys/include/net/ng_ipv6/hdr.h create mode 100644 sys/net/network_layer/ng_ipv6/hdr/Makefile create mode 100644 sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c diff --git a/Makefile.dep b/Makefile.dep index 8a90097714..f63ce39e8d 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -48,6 +48,11 @@ ifneq (,$(filter sixlowpan,$(USEMODULE))) USEMODULE += vtimer endif +ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE))) + USEMODULE += ng_inet_csum + USEMODULE += ng_pktbuf +endif + ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) USEMODULE += ng_ipv6_addr endif diff --git a/sys/Makefile b/sys/Makefile index d7117e0286..b5b18b7a8d 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -65,6 +65,9 @@ endif ifneq (,$(filter ng_ipv6_addr,$(USEMODULE))) DIRS += net/network_layer/ng_ipv6/addr endif +ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE))) + DIRS += net/network_layer/ng_ipv6/hdr +endif ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) DIRS += net/network_layer/ng_ipv6/nc endif diff --git a/sys/include/net/ng_ipv6.h b/sys/include/net/ng_ipv6.h index 0b0086918f..7468121ce8 100644 --- a/sys/include/net/ng_ipv6.h +++ b/sys/include/net/ng_ipv6.h @@ -23,6 +23,7 @@ #define NG_IPV6_H_ #include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/hdr.h" #include "net/ng_ipv6/netif.h" #ifdef __cplusplus diff --git a/sys/include/net/ng_ipv6/hdr.h b/sys/include/net/ng_ipv6/hdr.h new file mode 100644 index 0000000000..3a18ba0646 --- /dev/null +++ b/sys/include/net/ng_ipv6/hdr.h @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_ipv6_hdr IPv6 header defintions + * @ingroup net_ng_ipv6 + * @{ + * + * @file + * @brief IPv6 header + * + * @author Martine Lenders + */ +#ifndef NG_IPV6_HDR_H_ +#define NG_IPV6_HDR_H_ + +#include +#include + +#include "byteorder.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_inet_csum.h" +#include "net/ng_pkt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Data type to represent an IPv6 packet header + * + * @details The structure of the header is as follows: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.unparsed} + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| Traffic Class | Flow Label | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload Length | Next Header | Hop Limit | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Source Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Destination Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see + * RFC 2460, section 3 + * + */ +typedef struct __attribute__((packed)) { + /** + * @brief Version, traffic class, and flow label + * + * @details The version are the 4 most significant bits, the traffic class + * the 8 next bit, and the remainding 20 bits are the flow label (see + * above). + * + * This module provides helper functions to set, get, and check these + * fields accordingly: + * * ng_ipv6_hdr_set_version() + * * ng_ipv6_hdr_get_version() + * * ng_ipv6_hdr_is_ipv6_hdr() + * * ng_ipv6_hdr_set_tc() + * * ng_ipv6_hdr_set_tc_ecn() + * * ng_ipv6_hdr_set_tc_dscp() + * * ng_ipv6_hdr_get_tc() + * * ng_ipv6_hdr_get_tc_ecn() + * * ng_ipv6_hdr_get_tc_dscp() + * * ng_ipv6_hdr_set_fl() + * * ng_ipv6_hdr_get_fl() + */ + network_uint32_t v_tc_fl; + network_uint16_t len; /**< payload length of this packet. */ + uint8_t nh; /**< type of next header in this packet. */ + uint8_t hl; /**< hop limit for this packet. */ + ng_ipv6_addr_t src; /**< source address of this packet. */ + ng_ipv6_addr_t dst; /**< destination address of this packet. */ +} ng_ipv6_hdr_t; + +/** + * @brief Sets the version field of @p hdr to 6 + * + * @param[out] hdr Pointer to an IPv6 header. + */ +static inline void ng_ipv6_hdr_set_version(ng_ipv6_hdr_t *hdr) +{ + hdr->v_tc_fl.u8[0] &= 0x0f; + hdr->v_tc_fl.u8[0] |= 0x60; +} + +/** + * @brief Gets the value of the version field of @p hdr + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the version field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_version(const ng_ipv6_hdr_t *hdr) +{ + return ((hdr->v_tc_fl.u8[0]) >> 4); +} + +/** + * @brief Checks if the version field is set to 6 + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return true, if version field is 6 + * @return false, otherwise + */ +static inline bool ng_ipv6_hdr_is_ipv6_hdr(const ng_ipv6_hdr_t *hdr) +{ + return (((hdr->v_tc_fl.u8[0]) & 0xf0) == 0x60); +} + +/** + * @brief Sets the traffic class field of @p hdr + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] tc The new value for the traffic class field. + */ +static inline void ng_ipv6_hdr_set_tc(ng_ipv6_hdr_t *hdr, uint8_t tc) +{ + hdr->v_tc_fl.u8[0] &= 0xf0; + hdr->v_tc_fl.u8[0] |= (0x0f & (tc >> 4)); + hdr->v_tc_fl.u8[1] &= 0x0f; + hdr->v_tc_fl.u8[1] |= (0xf0 & (tc << 4)); +} + +/** + * @brief Sets the value of the Explicit Congestion Notification (ECN) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see + * RFC 3168, section 5 + * + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] ecn The new value for the 2-bit ECN part of the traffic class + * field. + */ +static inline void ng_ipv6_hdr_set_tc_ecn(ng_ipv6_hdr_t *hdr, uint8_t ecn) +{ + hdr->v_tc_fl.u8[0] &= 0xf3; + hdr->v_tc_fl.u8[0] |= (0x0c & (ecn << 2)); +} + +/** + * @brief Sets the value of the Differentiated Service Codepoint (DSCP) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see + * RFC 2474, section 3 + * + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] dscp The new value for the 6-bit DSCP ng_part of the traffic class + * field. + */ +static inline void ng_ipv6_hdr_set_tc_dscp(ng_ipv6_hdr_t *hdr, uint8_t dscp) +{ + hdr->v_tc_fl.u8[0] &= 0xfc; + hdr->v_tc_fl.u8[0] |= (0x03 & (dscp >> 4)); + hdr->v_tc_fl.u8[1] &= 0x0f; + hdr->v_tc_fl.u8[1] |= (0xf0 & (dscp << 4)); +} + +/** + * @brief Gets the value of the traffic class field of @p hdr + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the traffic class field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_tc(const ng_ipv6_hdr_t *hdr) +{ + return ((((hdr->v_tc_fl.u8[0]) & 0x0f) << 4) | + ((hdr->v_tc_fl.u8[1] & 0xf0) >> 4)); +} + +/** + * @brief Gets the value of the Explicit Congestion Notification (ECN) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see + * RFC 3168, section 5 + * + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the ECN part of the traffic class field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_tc_ecn(const ng_ipv6_hdr_t *hdr) +{ + return (((hdr->v_tc_fl.u8[0]) & 0x0c) >> 2); +} + + +/** + * @brief Gets the value of the Differentiated Service Codepoint (DSCP) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see + * RFC 2474, section 3 + * + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the DSCP part of the traffic class field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_tc_dscp(const ng_ipv6_hdr_t *hdr) +{ + return ((((hdr->v_tc_fl.u8[0]) & 0x03) << 4) | + ((hdr->v_tc_fl.u8[1] & 0xf0) >> 4)); +} + +/** + * @brief Sets the flow label field of @p hdr + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] fl The new value for the flow label field in host byte order. + */ +static inline void ng_ipv6_hdr_set_fl(ng_ipv6_hdr_t *hdr, uint32_t fl) +{ + hdr->v_tc_fl.u8[1] &= 0xf0; + hdr->v_tc_fl.u8[1] |= (0x0f & (byteorder_htonl(fl).u8[1])); + hdr->v_tc_fl.u16[1] = byteorder_htonl(fl).u16[1]; +} + +/** + * @brief Gets the value of the flow label field of @p hdr + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the flow label field of @p hdr. + */ +static inline uint32_t ng_ipv6_hdr_get_fl(const ng_ipv6_hdr_t *hdr) +{ + return byteorder_ntohl(hdr->v_tc_fl) & 0x000fffff; +} + +/** + * @brief Calculates the Internet Checksum for the IPv6 Pseudo Header. + * + * @see + * RFC 2460, section 8.1 + * + * + * @param[in] sum Preinialized value of the sum. + * @param[in] prot_num The @ref net_ng_protnum you want to calculate the + * checksum for. Can not be inferred from + * ng_ipv6_hdr_t::nh, since it can be an IPv6 exentension + * header. + * @param[in] hdr An IPv6 header to derive the Pseudo Header from. + * @param[in] len The upper-layer packet length for the pseudo header. + * Can not be inferred from ng_ipv6_hdr_t::len, since + * there can be extension headers between the IPv6 header + * and the payload. + * + * @return The non-normalized Internet Checksum of the given IPv6 pseudo header. + */ +static inline uint16_t ng_ipv6_hdr_inet_csum(uint16_t sum, ng_ipv6_hdr_t *hdr, + uint8_t prot_num, uint16_t len) +{ + return ng_inet_csum(sum + len + prot_num, hdr->src.u8, + (2 * sizeof(ng_ipv6_addr_t))); +} + +/** + * @brief Builds an IPv6 header for sending and adds it to the packet buffer. + * + * @details Initializes version field with 6, traffic class, flow label, and + * hop limit with 0, and next header with @ref NG_PROTNUM_RESERVED. + * + * @param[in] payload Payload for the packet. + * @param[in] src Source address for the header. Can be NULL if not + * known or required. + * @param[in] src_len Length of @p src. Can be 0 if not known or required or + * must be `sizeof(ng_ipv6_addr_t)`. + * @param[in] dst Destination address for the header. Can be NULL if not + * known or required. + * @param[in] dst_len Length of @p dst. Can be 0 if not known or required or + * must be `sizeof(ng_ipv6_addr_t)`. + * + * @return The an IPv6 header in packet buffer on success. + * @return NULL on error. + */ +ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload, + uint8_t *src, uint8_t src_len, + uint8_t *dst, uint8_t dst_len); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_IPV6_HDR_H_ */ +/** @} */ diff --git a/sys/net/network_layer/ng_ipv6/hdr/Makefile b/sys/net/network_layer/ng_ipv6/hdr/Makefile new file mode 100644 index 0000000000..204e78e385 --- /dev/null +++ b/sys/net/network_layer/ng_ipv6/hdr/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_ipv6_hdr + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c b/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c new file mode 100644 index 0000000000..9804b72308 --- /dev/null +++ b/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ + +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/hdr.h" +#include "net/ng_nettype.h" +#include "net/ng_pktbuf.h" +#include "net/ng_protnum.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if ENABLE_DEBUG && defined(MODULE_NG_IPV6_ADDR) +static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN]; +#endif + +/* For independent testing */ +#ifdef MODULE_NG_IPV6 +#define HDR_NETTYPE (NG_NETTYPE_IPV6) +#else +#define HDR_NETTYPE (NG_NETTYPE_UNDEF) +#endif + +ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload, + uint8_t *src, uint8_t src_len, + uint8_t *dst, uint8_t dst_len) +{ + ng_pktsnip_t *ipv6; + ng_ipv6_hdr_t *hdr; + + if (((src_len != 0) && (src_len != sizeof(ng_ipv6_addr_t))) || + ((dst_len != 0) && (dst_len != sizeof(ng_ipv6_addr_t)))) { + DEBUG("ipv6_hdr: Address length was not 0 or %zu byte.\n", + sizeof(ng_ipv6_addr_t)); + return NULL; + } + + ipv6 = ng_pktbuf_add(payload, NULL, sizeof(ng_ipv6_hdr_t), HDR_NETTYPE); + + if (ipv6 == NULL) { + DEBUG("ipv6_hdr: no space left in packet buffer\n"); + return NULL; + } + + hdr = (ng_ipv6_hdr_t *)ipv6->data; + + if ((src != NULL) && (src_len != 0)) { +#ifdef MODULE_NG_IPV6_ADDR + DEBUG("ipv6_hdr: set packet source to %s\n", + ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)src, + sizeof(addr_str))); +#endif + memcpy(&hdr->src, src, src_len); + } + + memset(&hdr->dst + dst_len, 0, sizeof(ng_ipv6_addr_t) - dst_len); + + if ((dst != NULL) && (dst_len != 0)) { +#ifdef MODULE_NG_IPV6_ADDR + DEBUG("ipv6_hdr: set packet destination to %s\n", + ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)dst, + sizeof(addr_str))); +#endif + memcpy(&hdr->dst, dst, dst_len); + } + + hdr->v_tc_fl = byteorder_htonl(0x60000000); /* set version, tc and fl in one go*/ + hdr->nh = NG_PROTNUM_RESERVED; + hdr->hl = 0; + + return ipv6; +} + +/** @} */ From 7a3c373038d739883a0106656add914b7fdf08da Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 29 Mar 2015 03:17:31 +0200 Subject: [PATCH 2/2] unittests: add tests for ipv6_hdr --- tests/unittests/tests-ipv6_hdr/Makefile | 1 + .../unittests/tests-ipv6_hdr/Makefile.include | 1 + .../unittests/tests-ipv6_hdr/tests-ipv6_hdr.c | 406 ++++++++++++++++++ .../unittests/tests-ipv6_hdr/tests-ipv6_hdr.h | 37 ++ 4 files changed, 445 insertions(+) create mode 100644 tests/unittests/tests-ipv6_hdr/Makefile create mode 100644 tests/unittests/tests-ipv6_hdr/Makefile.include create mode 100644 tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.c create mode 100644 tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.h diff --git a/tests/unittests/tests-ipv6_hdr/Makefile b/tests/unittests/tests-ipv6_hdr/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/tests/unittests/tests-ipv6_hdr/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-ipv6_hdr/Makefile.include b/tests/unittests/tests-ipv6_hdr/Makefile.include new file mode 100644 index 0000000000..e8dcdd2cba --- /dev/null +++ b/tests/unittests/tests-ipv6_hdr/Makefile.include @@ -0,0 +1 @@ +USEMODULE += ng_ipv6_hdr diff --git a/tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.c b/tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.c new file mode 100644 index 0000000000..dda7bb09b8 --- /dev/null +++ b/tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.c @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2014 Martine Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ +#include +#include + +#include "embUnit.h" + +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/hdr.h" +#include "net/ng_pktbuf.h" +#include "net/ng_protnum.h" +#include "net/ng_inet_csum.h" + +#include "unittests-constants.h" +#include "tests-ipv6_hdr.h" + +#define OTHER_BYTE (TEST_UINT16 >> 8) +#define DEFAULT_TEST_SRC { { \ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f \ + } \ + } +#define DEFAULT_TEST_DST { { \ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f \ + } \ + } + +static void test_ipv6_hdr_set_version(void) +{ + uint8_t val[] = { TEST_UINT8 }; + + ng_ipv6_hdr_set_version((ng_ipv6_hdr_t *)val); + + /* + * Header format: + * 1 + * +----+-- + * | 6 | + * +----+-- + */ + TEST_ASSERT_EQUAL_INT(0x60, val[0] & 0xf0); + TEST_ASSERT_EQUAL_INT(TEST_UINT8 & 0x0f, val[0] & 0x0f); +} + +static void test_ipv6_hdr_get_version(void) +{ + uint8_t val[] = { TEST_UINT8 }; + + /* + * Header format: + * 8 + * +----+---- + * | 6 | + * +----+---- + */ + TEST_ASSERT_EQUAL_INT(TEST_UINT8 >> 4, + ng_ipv6_hdr_get_version((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_is_ipv6_hdr__false(void) +{ + /* + * Header format: + * 8 + * +----+---- + * | 6 | + * +----+---- + */ + uint8_t val[] = { 0 }; + + TEST_ASSERT(!ng_ipv6_hdr_is_ipv6_hdr((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_is_ipv6_hdr__true(void) +{ + /* + * Header format: + * 8 + * +----+---- + * | 6 | + * +----+---- + */ + uint8_t val[] = { 0x60 | (TEST_UINT8 & 0x0f) }; + + TEST_ASSERT(ng_ipv6_hdr_is_ipv6_hdr((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_set_tc(void) +{ + uint8_t val[] = { TEST_UINT8, 0 }; + + ng_ipv6_hdr_set_tc((ng_ipv6_hdr_t *)val, OTHER_BYTE); + + /* + * Header format: + * 8 + * +----+--------+-- + * | 6 | tc | + * +----+--------+-- + */ + TEST_ASSERT_EQUAL_INT((TEST_UINT8 & 0xf0) | (OTHER_BYTE >> 4), val[0]); + TEST_ASSERT_EQUAL_INT((OTHER_BYTE << 4) & 0xf0, val[1]); +} + +static void test_ipv6_hdr_set_tc_ecn(void) +{ + uint8_t val[] = { TEST_UINT8 }; + + ng_ipv6_hdr_set_tc_ecn((ng_ipv6_hdr_t *)val, OTHER_BYTE); + + /* + * Header format: + * 8 + * +----+--------+-- + * | 6 | tc | + * +----+--------+-- + * / \ + * 8 12 + * +----+------------+ + * | ecn| dscp | + * +----+------------+ + */ + TEST_ASSERT_EQUAL_INT((TEST_UINT8 & 0xf3) | ((OTHER_BYTE & 0x03) << 2), val[0]); +} + +static void test_ipv6_hdr_set_tc_dscp(void) +{ + uint8_t val[] = { TEST_UINT8, 0 }; + + ng_ipv6_hdr_set_tc_dscp((ng_ipv6_hdr_t *)val, OTHER_BYTE); + + /* + * Header format: + * 8 + * +----+--------+-- + * | 6 | tc | + * +----+--------+-- + * / \ + * 8 12 + * +----+------------+ + * | ecn| dscp | + * +----+------------+ + */ + TEST_ASSERT_EQUAL_INT((TEST_UINT8 & 0xfc) | ((OTHER_BYTE & 0x30) >> 4), val[0]); + TEST_ASSERT_EQUAL_INT((OTHER_BYTE & 0x0f) << 4, val[1]); +} + +static void test_ipv6_hdr_get_tc(void) +{ + uint8_t val[] = { TEST_UINT8, OTHER_BYTE }; + + /* + * Header format: + * 8 + * +----+--------+-- + * | 6 | tc | + * +----+--------+-- + */ + TEST_ASSERT_EQUAL_INT(((TEST_UINT8 << 4) & 0xf0) | (OTHER_BYTE >> 4), + ng_ipv6_hdr_get_tc((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_get_tc_ecn(void) +{ + uint8_t val[] = { TEST_UINT8 }; + + /* + * Header format: + * 8 + * +----+--------+-- + * | 6 | tc | + * +----+--------+-- + * / \ + * 8 12 + * +----+------------+ + * | ecn| dscp | + * +----+------------+ + */ + TEST_ASSERT_EQUAL_INT(TEST_UINT8 & 0x03, + ng_ipv6_hdr_get_tc_ecn((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_get_tc_dscp(void) +{ + uint8_t val[] = { TEST_UINT8, OTHER_BYTE }; + + /* + * Header format: + * 8 + * +----+--------+-- + * | 6 | tc | + * +----+--------+-- + * / \ + * 8 12 + * +----+------------+ + * | ecn| dscp | + * +----+------------+ + */ + TEST_ASSERT_EQUAL_INT(((TEST_UINT8 & 0x03) << 4) | ((OTHER_BYTE & 0xf0) >> 4), + ng_ipv6_hdr_get_tc_dscp((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_set_fl(void) +{ + uint8_t val[] = { 0, TEST_UINT8, 0, 0 }; + + ng_ipv6_hdr_set_fl((ng_ipv6_hdr_t *)val, TEST_UINT32); + + /* + * Header format: + * 8 16 24 32 + * +----+--------+--------------------+ + * | 6 | tc | flow label | + * +----+--------+--------------------+ + */ + TEST_ASSERT_EQUAL_INT(0, val[0]); + TEST_ASSERT_EQUAL_INT((TEST_UINT8 & 0xf0) | ((TEST_UINT32 & 0x000f0000) >> 16), + val[1]); + TEST_ASSERT_EQUAL_INT((TEST_UINT32 & 0x0000ff00) >> 8, + val[2]); + TEST_ASSERT_EQUAL_INT((TEST_UINT32 & 0x000000ff), val[3]); +} + +static void test_ipv6_hdr_get_fl(void) +{ + uint8_t val[] = { TEST_UINT8, OTHER_BYTE, 0, 0 }; + + /* + * Header format: + * 8 16 24 32 + * +----+--------+--------------------+ + * | 6 | tc | flow label | + * +----+--------+--------------------+ + */ + TEST_ASSERT_EQUAL_INT((OTHER_BYTE & 0x0f) << 16, + ng_ipv6_hdr_get_fl((ng_ipv6_hdr_t *)val)); +} + +static void test_ipv6_hdr_inet_csum(void) +{ + /* source: https://www.cloudshark.org/captures/ea72fbab241b (No. 56) */ + uint16_t res = 0, payload_len; + uint8_t val[] = { + 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, /* IPv6 header */ + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0x6d, 0x8f, 0xff, 0xfe, 0x56, 0x30, 0x09, + 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x86, 0x00, 0x00, 0x00, 0x40, 0x58, 0x07, 0x08, /* ICMPv6 payload */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* set checksum to 0 */ + 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x02, 0x18, 0x3d, 0xdb, 0xa4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x58, 0x6d, 0x8f, 0x56, 0x30, 0x09 + }; + + payload_len = sizeof(val) - sizeof(ng_ipv6_hdr_t); + + /* calculate checksum of pseudo header */ + res = ng_ipv6_hdr_inet_csum(0, (ng_ipv6_hdr_t *)&val, NG_PROTNUM_ICMPV6, + payload_len); + /* calculate checksum of payload */ + res = ng_inet_csum(res, val + sizeof(ng_ipv6_hdr_t), payload_len); + res = ~res; /* take 1's-complement for correct checksum */ + + TEST_ASSERT_EQUAL_INT(0xab32, res); +} + +static void test_ipv6_hdr_build__wrong_src_len(void) +{ + ng_ipv6_addr_t src = DEFAULT_TEST_SRC; + ng_ipv6_addr_t dst = DEFAULT_TEST_DST; + + TEST_ASSERT_NULL(ng_ipv6_hdr_build(NULL, (uint8_t *)&src, + sizeof(ng_ipv6_addr_t) + TEST_UINT8, + (uint8_t *)&dst, + sizeof(ng_ipv6_addr_t))); + TEST_ASSERT(ng_pktbuf_is_empty()); +} + +static void test_ipv6_hdr_build__wrong_dst_len(void) +{ + ng_ipv6_addr_t src = DEFAULT_TEST_SRC; + ng_ipv6_addr_t dst = DEFAULT_TEST_DST; + + TEST_ASSERT_NULL(ng_ipv6_hdr_build(NULL, (uint8_t *)&src, + sizeof(ng_ipv6_addr_t), + (uint8_t *)&dst, + sizeof(ng_ipv6_addr_t) + TEST_UINT8)); + TEST_ASSERT(ng_pktbuf_is_empty()); +} + +static void test_ipv6_hdr_build__src_NULL(void) +{ + ng_ipv6_addr_t dst = DEFAULT_TEST_DST; + ng_pktsnip_t *pkt; + ng_ipv6_hdr_t *hdr; + + TEST_ASSERT(ng_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = ng_ipv6_hdr_build(NULL, NULL, 0, (uint8_t *)&dst, + sizeof(ng_ipv6_addr_t)))); + hdr = pkt->data; + TEST_ASSERT_NOT_NULL(hdr); + TEST_ASSERT(ng_ipv6_hdr_is_ipv6_hdr(hdr)); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_hdr_get_tc(hdr)); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_hdr_get_fl(hdr)); + TEST_ASSERT_EQUAL_INT(NG_PROTNUM_RESERVED, hdr->nh); + TEST_ASSERT_EQUAL_INT(0, hdr->hl); + TEST_ASSERT(ng_ipv6_addr_equal(&dst, &hdr->dst)); + TEST_ASSERT(!ng_pktbuf_is_empty()); + ng_pktbuf_reset(); +} + +static void test_ipv6_hdr_build__dst_NULL(void) +{ + ng_ipv6_addr_t src = DEFAULT_TEST_SRC; + ng_pktsnip_t *pkt; + ng_ipv6_hdr_t *hdr; + + TEST_ASSERT(ng_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = ng_ipv6_hdr_build(NULL, (uint8_t *)&src, + sizeof(ng_ipv6_addr_t), + NULL, 0))); + hdr = pkt->data; + TEST_ASSERT_NOT_NULL(hdr); + TEST_ASSERT(ng_ipv6_hdr_is_ipv6_hdr(hdr)); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_hdr_get_tc(hdr)); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_hdr_get_fl(hdr)); + TEST_ASSERT_EQUAL_INT(NG_PROTNUM_RESERVED, hdr->nh); + TEST_ASSERT_EQUAL_INT(0, hdr->hl); + TEST_ASSERT(ng_ipv6_addr_equal(&src, &hdr->src)); + TEST_ASSERT(!ng_pktbuf_is_empty()); + ng_pktbuf_reset(); +} + +static void test_ipv6_hdr_build__complete(void) +{ + ng_ipv6_addr_t src = DEFAULT_TEST_SRC; + ng_ipv6_addr_t dst = DEFAULT_TEST_DST; + ng_pktsnip_t *pkt; + ng_ipv6_hdr_t *hdr; + + TEST_ASSERT(ng_pktbuf_is_empty()); + TEST_ASSERT_NOT_NULL((pkt = ng_ipv6_hdr_build(NULL, (uint8_t *)&src, + sizeof(ng_ipv6_addr_t), + (uint8_t *)&dst, + sizeof(ng_ipv6_addr_t)))); + hdr = pkt->data; + TEST_ASSERT_NOT_NULL(hdr); + TEST_ASSERT(ng_ipv6_hdr_is_ipv6_hdr(hdr)); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_hdr_get_tc(hdr)); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_hdr_get_fl(hdr)); + TEST_ASSERT_EQUAL_INT(NG_PROTNUM_RESERVED, hdr->nh); + TEST_ASSERT_EQUAL_INT(0, hdr->hl); + TEST_ASSERT(ng_ipv6_addr_equal(&src, &hdr->src)); + TEST_ASSERT(ng_ipv6_addr_equal(&dst, &hdr->dst)); + TEST_ASSERT(!ng_pktbuf_is_empty()); + ng_pktbuf_reset(); +} + +Test *tests_ipv6_hdr_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_ipv6_hdr_set_version), + new_TestFixture(test_ipv6_hdr_get_version), + new_TestFixture(test_ipv6_hdr_is_ipv6_hdr__false), + new_TestFixture(test_ipv6_hdr_is_ipv6_hdr__true), + new_TestFixture(test_ipv6_hdr_set_tc), + new_TestFixture(test_ipv6_hdr_set_tc_ecn), + new_TestFixture(test_ipv6_hdr_set_tc_dscp), + new_TestFixture(test_ipv6_hdr_get_tc), + new_TestFixture(test_ipv6_hdr_get_tc_ecn), + new_TestFixture(test_ipv6_hdr_get_tc_dscp), + new_TestFixture(test_ipv6_hdr_set_fl), + new_TestFixture(test_ipv6_hdr_get_fl), + new_TestFixture(test_ipv6_hdr_inet_csum), + new_TestFixture(test_ipv6_hdr_build__wrong_src_len), + new_TestFixture(test_ipv6_hdr_build__wrong_dst_len), + new_TestFixture(test_ipv6_hdr_build__src_NULL), + new_TestFixture(test_ipv6_hdr_build__dst_NULL), + new_TestFixture(test_ipv6_hdr_build__complete), + }; + + EMB_UNIT_TESTCALLER(ipv6_hdr_tests, NULL, NULL, fixtures); + + return (Test *)&ipv6_hdr_tests; +} + +void tests_ipv6_hdr(void) +{ + TESTS_RUN(tests_ipv6_hdr_tests()); +} +/** @} */ diff --git a/tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.h b/tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.h new file mode 100644 index 0000000000..1b383cb376 --- /dev/null +++ b/tests/unittests/tests-ipv6_hdr/tests-ipv6_hdr.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file tests-ipv6_hdr.h + * @brief Unittests for the ``ipv6_hdr`` module + * + * @author Martine Lenders + */ +#ifndef TESTS_IPV6_HDR_H_ +#define TESTS_IPV6_HDR_H_ + +#include "embUnit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The entry point of this test suite. + */ +void tests_ipv6_hdr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* TESTS_IPV6_HDR_H_ */ +/** @} */