diff --git a/sys/include/net/gnrc/ipv6/ext.h b/sys/include/net/gnrc/ipv6/ext.h index 6f38fc23c29b..985eded734ee 100644 --- a/sys/include/net/gnrc/ipv6/ext.h +++ b/sys/include/net/gnrc/ipv6/ext.h @@ -46,8 +46,8 @@ extern "C" { * @param[in] pkt A packet. * @param[in] nh A protocol number (see @ref net_protnum). * - * @return true, on success. - * @return false, on failure. + * @return true, on success - continue packet processing. + * @return false, on failure - stop packet processing. */ bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh); diff --git a/sys/include/net/gnrc/rpl/srh.h b/sys/include/net/gnrc/rpl/srh.h index 892685782eea..6a772922e6e4 100644 --- a/sys/include/net/gnrc/rpl/srh.h +++ b/sys/include/net/gnrc/rpl/srh.h @@ -23,6 +23,7 @@ #ifndef GNRC_RPL_SRH_H_ #define GNRC_RPL_SRH_H_ +#include "net/ipv6/hdr.h" #include "net/ipv6/addr.h" #ifdef __cplusplus @@ -48,17 +49,22 @@ typedef struct __attribute__((packed)) { uint8_t len; /**< length in 8 octets without first octet */ uint8_t type; /**< identifier of a particular routing header type */ uint8_t seg_left; /**< number of route segments remaining */ + uint8_t compr; /**< number of prefix octets (comprI and comprE) */ + uint8_t pad_resv; /**< padding and reserved */ + uint16_t resv; /**< reserved */ } gnrc_rpl_srh_t; /** - * @brief Extract next hop from the RPL source routing header. + * @brief Process the RPL source routing header. * + * @param[in,out] ipv6 The IPv6 header of the incoming packet. * @param[in] rh A RPL source routing header. * - * @return next hop, on success - * @return NULL, if not found. + * @return EXT_RH_CODE_ERROR + * @return EXT_RH_CODE_FORWARD + * @return EXT_RH_CODE_OK */ -ipv6_addr_t *gnrc_rpl_srh_next_hop(gnrc_rpl_srh_t *rh); +int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh); #ifdef __cplusplus } diff --git a/sys/include/net/ipv6/ext/rh.h b/sys/include/net/ipv6/ext/rh.h index a752e2134ce3..b26b97cc4ff8 100644 --- a/sys/include/net/ipv6/ext/rh.h +++ b/sys/include/net/ipv6/ext/rh.h @@ -23,12 +23,24 @@ #include #include "net/ipv6/addr.h" +#include "net/ipv6/ext.h" #include "net/ipv6/hdr.h" #ifdef __cplusplus extern "C" { #endif +/** + * @name Return codes for routing header processing + * @{ + */ +#define EXT_RH_CODE_ERROR (-1) +#define EXT_RH_CODE_FORWARD (0) +#define EXT_RH_CODE_OK (1) +/** + * @} + */ + /** * @brief IPv6 routing extension header. * @@ -46,14 +58,16 @@ typedef struct __attribute__((packed)) { } ipv6_ext_rh_t; /** - * @brief Extract next hop from the routing header of an IPv6 packet. + * @brief Process the routing header of an IPv6 packet. * - * @param[in] ipv6 An IPv6 packet. + * @param[in, out] ipv6 An IPv6 packet. + * @param[in] ext A routing header of @ipv6. * - * @return next hop on success, on success - * @return NULL, if not found. + * @return EXT_RH_CODE_ERROR + * @return EXT_RH_CODE_FORWARD + * @return EXT_RH_CODE_OK */ -ipv6_addr_t *ipv6_ext_rh_next_hop(ipv6_hdr_t *ipv6); +int ipv6_ext_rh_process(ipv6_hdr_t *ipv6, ipv6_ext_rh_t *ext); #ifdef __cplusplus } diff --git a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c index b2a057f7c7ea..64dd90ca71a7 100644 --- a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c +++ b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c @@ -20,12 +20,17 @@ #include "net/gnrc/ipv6/ext.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh) { - gnrc_pktsnip_t *ext_snip; + gnrc_pktsnip_t *ext_snip, *tmp; ipv6_ext_t *ext; unsigned int offset = 0; + ipv6_hdr_t *hdr; + int res; ext = ((ipv6_ext_t *)(((uint8_t *)pkt->data) + sizeof(ipv6_hdr_t))); @@ -36,6 +41,35 @@ bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, case PROTNUM_IPV6_EXT_HOPOPT: case PROTNUM_IPV6_EXT_DST: case PROTNUM_IPV6_EXT_RH: + if ((tmp = gnrc_pktbuf_start_write(pkt)) == NULL) { + DEBUG("ipv6: could not get a copy of pkt\n"); + gnrc_pktbuf_release(pkt); + return false; + } + pkt = tmp; + hdr = pkt->data; + ext = (ipv6_ext_t *) (((uint8_t *) pkt->data) + sizeof(ipv6_hdr_t) + offset); + res = ipv6_ext_rh_process(hdr, (ipv6_ext_rh_t *)ext); + if (res == EXT_RH_CODE_ERROR) { + /* TODO: send ICMPv6 error codes */ + gnrc_pktbuf_release(pkt); + return false; + } + else if (res == EXT_RH_CODE_FORWARD) { + /* forward packet */ + if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, + pkt)) { + DEBUG("ipv6: could not dispatch packet to the ipv6 thread\n"); + gnrc_pktbuf_release(pkt); + } + return false; + } + else if (res == EXT_RH_CODE_OK) { + nh = ext->nh; + offset += ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); + ext = ipv6_ext_get_next((ipv6_ext_t *)ext); + } + break; case PROTNUM_IPV6_EXT_FRAG: case PROTNUM_IPV6_EXT_AH: case PROTNUM_IPV6_EXT_ESP: @@ -57,6 +91,7 @@ bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ext_snip = gnrc_pktbuf_mark(pkt, offset, GNRC_NETTYPE_IPV6); if (ext_snip == NULL) { + gnrc_pktbuf_release(pkt); return false; } diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index 2283c4cbd377..2cf446889a80 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -123,8 +123,7 @@ void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh) case PROTNUM_IPV6_EXT_MOB: DEBUG("ipv6: handle extension header (nh = %u)\n", nh); if (!gnrc_ipv6_ext_demux(iface, pkt, nh)) { - DEBUG("ipv6: unable to parse extension headers.\n"); - gnrc_pktbuf_release(pkt); + DEBUG("ipv6: stop packet processing.\n"); return; } #endif diff --git a/sys/net/gnrc/network_layer/ndp/node/gnrc_ndp_node.c b/sys/net/gnrc/network_layer/ndp/node/gnrc_ndp_node.c index facab339eb3f..bb9ed06b4478 100644 --- a/sys/net/gnrc/network_layer/ndp/node/gnrc_ndp_node.c +++ b/sys/net/gnrc/network_layer/ndp/node/gnrc_ndp_node.c @@ -63,14 +63,6 @@ kernel_pid_t gnrc_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL; bool dst_link_local = ipv6_addr_is_link_local(dst); -#ifdef MODULE_GNRC_IPV6_EXT_RH - ipv6_hdr_t *hdr; - gnrc_pktsnip_t *ipv6; - ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); - assert(ipv6); - hdr = ipv6->data; - next_hop_ip = ipv6_ext_rh_next_hop(hdr); -#endif #ifdef MODULE_FIB ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ /* don't look-up link local addresses in FIB */ diff --git a/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c b/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c index a8653dd1e583..f3a7f7e33d2e 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c +++ b/sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c @@ -124,14 +124,6 @@ kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_ ipv6_addr_t *next_hop = NULL; gnrc_ipv6_nc_t *nc_entry = NULL; -#ifdef MODULE_GNRC_IPV6_EXT_RH - ipv6_hdr_t *hdr; - gnrc_pktsnip_t *ipv6; - ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); - assert(ipv6); - hdr = ipv6->data; - next_hop = ipv6_ext_rh_next_hop(hdr); -#endif #ifdef MODULE_FIB kernel_pid_t fib_iface; ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ diff --git a/sys/net/gnrc/routing/rpl/srh/Makefile b/sys/net/gnrc/routing/rpl/srh/Makefile new file mode 100644 index 000000000000..316990c41891 --- /dev/null +++ b/sys/net/gnrc/routing/rpl/srh/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_rpl_srh + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c b/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c index b28b9dfd9bb1..0e09ff4ae2b0 100644 --- a/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c +++ b/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c @@ -12,13 +12,86 @@ * @file */ +#include +#include "net/gnrc/ipv6/netif.h" #include "net/gnrc/rpl/srh.h" -ipv6_addr_t *gnrc_rpl_srh_next_hop(gnrc_rpl_srh_t *rh) +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if ENABLE_DEBUG +static char addr_str[IPV6_ADDR_MAX_STR_LEN]; +#endif + +#define GNRC_RPL_SRH_PADDING(X) ((X & 0xF0) >> 4) +#define GNRC_RPL_SRH_COMPRE(X) (X & 0x0F) +#define GNRC_RPL_SRH_COMPRI(X) ((X & 0xF0) >> 4) + +int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) { - /* TODO */ + if (rh->seg_left == 0) { + return EXT_RH_CODE_OK; + } + + uint8_t n = (((rh->len * 8) - GNRC_RPL_SRH_PADDING(rh->pad_resv) - + (16 - GNRC_RPL_SRH_COMPRE(rh->compr))) / + (16 - GNRC_RPL_SRH_COMPRI(rh->compr))) + 1; + ipv6_addr_t addr = ipv6->dst, tmp; + uint8_t i, pref_elided, tmp_pref_elided, addr_len, compri_addr_len, tmp_addr_len, found_pos = 0; + uint8_t *addr_vec = (uint8_t *) (rh + 1); + bool found = false; + + DEBUG("RPL SRH: %" PRIu8 " addresses in the routing header\n", n); + + if (rh->seg_left > n) { + DEBUG("RPL SRH: number of segments left > number of addresses - discard\n"); + /* TODO ICMP Parameter Problem - Code 0 */ + return EXT_RH_CODE_ERROR; + } + + rh->seg_left--; + i = n - rh->seg_left; + pref_elided = rh->seg_left ? GNRC_RPL_SRH_COMPRI(rh->compr) : GNRC_RPL_SRH_COMPRE(rh->compr); + compri_addr_len = sizeof(ipv6_addr_t) - GNRC_RPL_SRH_COMPRI(rh->compr); + addr_len = sizeof(ipv6_addr_t) - pref_elided; + memcpy(&addr.u8[pref_elided], &addr_vec[(i - 1) * compri_addr_len], addr_len); + + if (ipv6_addr_is_multicast(&ipv6->dst) || ipv6_addr_is_multicast(&addr)) { + DEBUG("RPL SRH: found a multicast address - discard\n"); + /* TODO discard the packet */ + return EXT_RH_CODE_ERROR; + } + + /* check if multiple addresses of my interface exist */ + tmp_pref_elided = GNRC_RPL_SRH_COMPRI(rh->compr); + tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided; + tmp = ipv6->dst; + for (uint8_t k = 0; k < n; k++) { + if (k == n - 1) { + tmp_pref_elided = GNRC_RPL_SRH_COMPRE(rh->compr); + tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided; + tmp = ipv6->dst; + } + memcpy(&tmp.u8[tmp_pref_elided], &addr_vec[k * compri_addr_len], tmp_addr_len); + if (gnrc_ipv6_netif_find_by_addr(NULL, &tmp) != KERNEL_PID_UNDEF) { + if (found && ((k - found_pos) > 1)) { + DEBUG("RPL SRH: found multiple addresses that belong to me - discard\n"); + /* TODO send an ICMP Parameter Problem (Code 0) and discard the packet */ + return EXT_RH_CODE_ERROR; + } + found_pos = k; + found = true; + } + } + + memcpy(&addr_vec[(i - 1) * compri_addr_len], &ipv6->dst.u8[pref_elided], addr_len); + + DEBUG("RPL SRH: Next hop: %s at position %d\n", + ipv6_addr_to_str(addr_str, &addr, sizeof(addr_str)), i); + + ipv6->dst = addr; - return NULL; + return EXT_RH_CODE_FORWARD; } /** @} */ diff --git a/sys/net/network_layer/ipv6/ext/Makefile b/sys/net/network_layer/ipv6/ext/Makefile new file mode 100644 index 000000000000..35b590050ef6 --- /dev/null +++ b/sys/net/network_layer/ipv6/ext/Makefile @@ -0,0 +1,3 @@ +MODULE = ipv6_ext + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ipv6/ext/rh/ipv6_ext_rh.c b/sys/net/network_layer/ipv6/ext/rh/ipv6_ext_rh.c index 341f624077c0..187a5c8056f4 100644 --- a/sys/net/network_layer/ipv6/ext/rh/ipv6_ext_rh.c +++ b/sys/net/network_layer/ipv6/ext/rh/ipv6_ext_rh.c @@ -15,48 +15,24 @@ #include #include "net/protnum.h" +#include "net/ipv6/ext.h" #include "net/ipv6/ext/rh.h" #include "net/gnrc/rpl/srh.h" -ipv6_addr_t *ipv6_ext_rh_next_hop(ipv6_hdr_t *ipv6) +int ipv6_ext_rh_process(ipv6_hdr_t *hdr, ipv6_ext_rh_t *ext) { - ipv6_ext_rh_t *ext = (ipv6_ext_rh_t *)(ipv6 + 1); - bool c = true; + (void) hdr; - while (c) { - switch (ext->type) { - case PROTNUM_IPV6_EXT_HOPOPT: - case PROTNUM_IPV6_EXT_DST: - case PROTNUM_IPV6_EXT_FRAG: - case PROTNUM_IPV6_EXT_AH: - case PROTNUM_IPV6_EXT_ESP: - case PROTNUM_IPV6_EXT_MOB: - ext = (ipv6_ext_rh_t *)ipv6_ext_get_next((ipv6_ext_t *)ext); - break; - - case PROTNUM_IPV6_EXT_RH: - c = false; - break; - - default: - c = false; - break; - } - } - - if (ipv6->nh == PROTNUM_IPV6_EXT_RH) { - switch (ext->type) { + switch (ext->type) { #ifdef MODULE_GNRC_RPL_SRH - case GNRC_RPL_SRH_TYPE: - return gnrc_rpl_srh_next_hop((gnrc_rpl_srh_t *)ext); + case GNRC_RPL_SRH_TYPE: + return gnrc_rpl_srh_process(hdr, (gnrc_rpl_srh_t *)ext); #endif - default: - break; - } + default: + break; } - - return NULL; + return EXT_RH_CODE_ERROR; } /** @} */ diff --git a/tests/unittests/tests-rpl_srh/Makefile b/tests/unittests/tests-rpl_srh/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/tests/unittests/tests-rpl_srh/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-rpl_srh/Makefile.include b/tests/unittests/tests-rpl_srh/Makefile.include new file mode 100644 index 000000000000..4aa358aa3cfb --- /dev/null +++ b/tests/unittests/tests-rpl_srh/Makefile.include @@ -0,0 +1,3 @@ +USEMODULE += gnrc_ipv6 +USEMODULE += ipv6_addr +USEMODULE += gnrc_rpl_srh diff --git a/tests/unittests/tests-rpl_srh/tests-rpl_srh.c b/tests/unittests/tests-rpl_srh/tests-rpl_srh.c new file mode 100644 index 000000000000..5bc75a28c163 --- /dev/null +++ b/tests/unittests/tests-rpl_srh/tests-rpl_srh.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 Cenk Gündoğan + * + * 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/ipv6/addr.h" +#include "net/ipv6/ext.h" +#include "net/ipv6/hdr.h" +#include "net/gnrc/rpl/srh.h" + +#include "unittests-constants.h" +#include "tests-rpl_srh.h" + +#define IPV6_DST {{ 0x20, 0x01, 0xab, 0xcd, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x01 }} +#define IPV6_ADDR1 {{ 0x20, 0x01, 0xab, 0xcd, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x02 }} +#define IPV6_ADDR2 {{ 0x20, 0x01, 0xab, 0xcd, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x03 }} + +#define IPV6_ADDR1_ELIDED { 0x00, 0x00, 0x02 } +#define IPV6_ADDR2_ELIDED { 0x00, 0x00, 0x03 } +#define IPV6_ELIDED_PREFIX (13) + +#define SRH_SEG_LEFT (2) + +static void test_rpl_srh_nexthop_no_prefix_elided(void) +{ + ipv6_hdr_t hdr; + uint8_t buf[sizeof(gnrc_rpl_srh_t) + 2 * sizeof(ipv6_addr_t)] = { 0 }; + int res; + gnrc_rpl_srh_t *srh = (gnrc_rpl_srh_t *) buf; + uint8_t *vec = (uint8_t *) (srh + 1); + ipv6_addr_t a1 = IPV6_ADDR1, a2 = IPV6_ADDR2, dst = IPV6_DST, + expected1 = IPV6_ADDR1, expected2 = IPV6_ADDR2; + + hdr.dst = dst; + + srh->len = (2 * sizeof(ipv6_addr_t)) / 8; + srh->seg_left = SRH_SEG_LEFT; + memcpy(vec, &a1, sizeof(a1)); + memcpy(vec + sizeof(a1), &a2, sizeof(a2)); + + /* first hop */ + res = gnrc_rpl_srh_process(&hdr, srh); + TEST_ASSERT_EQUAL_INT(res, EXT_RH_CODE_FORWARD); + TEST_ASSERT_EQUAL_INT(SRH_SEG_LEFT - 1, srh->seg_left); + TEST_ASSERT(ipv6_addr_equal(&hdr.dst, &expected1)); + + /* second hop */ + res = gnrc_rpl_srh_process(&hdr, srh); + TEST_ASSERT_EQUAL_INT(res, EXT_RH_CODE_FORWARD); + TEST_ASSERT_EQUAL_INT(SRH_SEG_LEFT - 2, srh->seg_left); + TEST_ASSERT(ipv6_addr_equal(&hdr.dst, &expected2)); +} + +static void test_rpl_srh_nexthop_prefix_elided(void) +{ + ipv6_hdr_t hdr; + uint8_t a1[3] = IPV6_ADDR1_ELIDED; + uint8_t a2[3] = IPV6_ADDR2_ELIDED; + uint8_t buf[sizeof(gnrc_rpl_srh_t) + sizeof(a1) + sizeof(a2)] = { 0 }; + int res; + gnrc_rpl_srh_t *srh = (gnrc_rpl_srh_t *) buf; + uint8_t *vec = (uint8_t *) (srh + 1); + ipv6_addr_t dst = IPV6_DST, expected1 = IPV6_ADDR1, expected2 = IPV6_ADDR2; + + hdr.dst = dst; + + srh->len = (sizeof(a1) + sizeof(a2) + 2) / 8; + srh->seg_left = SRH_SEG_LEFT; + srh->compr = (IPV6_ELIDED_PREFIX << 4) | IPV6_ELIDED_PREFIX; + srh->pad_resv = 2 << 4; + memcpy(vec, &a1, sizeof(a1)); + memcpy(vec + sizeof(a1), &a2, sizeof(a2)); + + /* first hop */ + res = gnrc_rpl_srh_process(&hdr, srh); + TEST_ASSERT_EQUAL_INT(res, EXT_RH_CODE_FORWARD); + TEST_ASSERT_EQUAL_INT(SRH_SEG_LEFT - 1, srh->seg_left); + TEST_ASSERT(ipv6_addr_equal(&hdr.dst, &expected1)); + + /* second hop */ + res = gnrc_rpl_srh_process(&hdr, srh); + TEST_ASSERT_EQUAL_INT(res, EXT_RH_CODE_FORWARD); + TEST_ASSERT_EQUAL_INT(SRH_SEG_LEFT - 2, srh->seg_left); + TEST_ASSERT(ipv6_addr_equal(&hdr.dst, &expected2)); +} + +Test *tests_rpl_srh_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_rpl_srh_nexthop_no_prefix_elided), + new_TestFixture(test_rpl_srh_nexthop_prefix_elided), + }; + + EMB_UNIT_TESTCALLER(rpl_srh_tests, NULL, NULL, fixtures); + + return (Test *)&rpl_srh_tests; +} + +void tests_rpl_srh(void) +{ + TESTS_RUN(tests_rpl_srh_tests()); +} +/** @} */ diff --git a/tests/unittests/tests-rpl_srh/tests-rpl_srh.h b/tests/unittests/tests-rpl_srh/tests-rpl_srh.h new file mode 100644 index 000000000000..180ea81322a0 --- /dev/null +++ b/tests/unittests/tests-rpl_srh/tests-rpl_srh.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 Cenk Gündoğan + * + * 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 + * @brief Unittests for the ``gnrc_rpl_srh`` module + * + * @author Cenk Gündoğan + */ +#ifndef TESTS_RPL_SRH_H_ +#define TESTS_RPL_SRH_H_ + +#include "embUnit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The entry point of this test suite. + */ +void tests_rpl_srh(void); + +#ifdef __cplusplus +} +#endif + +#endif /* TESTS_RPL_SRH_H_ */ +/** @} */