/* * Copyright (C) 2015 Freie Universität Berlin * * 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. */ /** * @ingroup tests * @{ * * @file * @brief Tests extension header handling of gnrc stack. * * @author Hauke Petersen * @author Takuo Yonezawa * * @} */ #include #include #include #include "embUnit.h" #include "shell.h" #include "net/ipv6/addr.h" #include "net/ipv6/ext.h" #include "net/ipv6/hdr.h" #include "net/gnrc/pktbuf.h" #include "net/gnrc/pktdump.h" #include "net/gnrc/netreg.h" #include "net/gnrc/rpl/srh.h" #include "net/gnrc/ipv6/ext/rh.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_MCAST_ADDR {{ 0xff, 0x05, 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) #define MAX_BUF_SIZE ((sizeof(gnrc_rpl_srh_t) + 2) + sizeof(ipv6_addr_t)) static ipv6_hdr_t hdr; static uint8_t buf[MAX_BUF_SIZE]; static char line_buf[SHELL_DEFAULT_BUFSIZE]; static gnrc_netreg_entry_t ip_entry = GNRC_NETREG_ENTRY_INIT_PID( 0, KERNEL_PID_UNDEF ); static void set_up_tests(void) { memset(&hdr, 0, sizeof(hdr)); memset(buf, 0, sizeof(buf)); } static inline void _init_hdrs(gnrc_rpl_srh_t **srh, uint8_t **vec, const ipv6_addr_t *dst) { *srh = (gnrc_rpl_srh_t *)buf; *vec = (uint8_t *)(*srh + 1); memcpy(&hdr.dst, dst, sizeof(hdr.dst)); } static void test_rpl_srh_dst_multicast(void) { static const ipv6_addr_t a1 = IPV6_ADDR1, a2 = IPV6_ADDR2; static const ipv6_addr_t mcast = IPV6_MCAST_ADDR; gnrc_rpl_srh_t *srh; uint8_t *vec; void *err_ptr = NULL; int res; _init_hdrs(&srh, &vec, &mcast); 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)); res = gnrc_rpl_srh_process(&hdr, srh, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_ERROR); TEST_ASSERT_NULL(err_ptr); } static void test_rpl_srh_route_multicast(void) { static const ipv6_addr_t a1 = IPV6_ADDR1; static const ipv6_addr_t mcast = IPV6_MCAST_ADDR; static const ipv6_addr_t dst = IPV6_DST; gnrc_rpl_srh_t *srh; uint8_t *vec; void *err_ptr = NULL; int res; _init_hdrs(&srh, &vec, &dst); srh->len = (2 * sizeof(ipv6_addr_t)) / 8; srh->seg_left = SRH_SEG_LEFT; memcpy(vec, &mcast, sizeof(mcast)); memcpy(vec + sizeof(mcast), &a1, sizeof(a1)); res = gnrc_rpl_srh_process(&hdr, srh, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_ERROR); TEST_ASSERT_NULL(err_ptr); } static void test_rpl_srh_too_many_seg_left(void) { static const ipv6_addr_t a1 = IPV6_ADDR1; static const ipv6_addr_t dst = IPV6_DST; gnrc_rpl_srh_t *srh; uint8_t *vec; void *err_ptr; int res; _init_hdrs(&srh, &vec, &dst); srh->len = sizeof(ipv6_addr_t) / 8; srh->seg_left = SRH_SEG_LEFT; memcpy(vec, &a1, sizeof(a1)); res = gnrc_rpl_srh_process(&hdr, srh, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_ERROR); TEST_ASSERT((&srh->seg_left) == err_ptr); } static void test_rpl_srh_nexthop_no_prefix_elided(void) { static const ipv6_addr_t a1 = IPV6_ADDR1, a2 = IPV6_ADDR2, dst = IPV6_DST; static const ipv6_addr_t expected1 = IPV6_ADDR1, expected2 = IPV6_ADDR2; gnrc_rpl_srh_t *srh; uint8_t *vec; void *err_ptr; int res; _init_hdrs(&srh, &vec, &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, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_FORWARDED); 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, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_FORWARDED); 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) { static const ipv6_addr_t dst = IPV6_DST; static const ipv6_addr_t expected1 = IPV6_ADDR1, expected2 = IPV6_ADDR2; gnrc_rpl_srh_t *srh; uint8_t *vec; void *err_ptr; int res; static const uint8_t a1[3] = IPV6_ADDR1_ELIDED; static const uint8_t a2[3] = IPV6_ADDR2_ELIDED; _init_hdrs(&srh, &vec, &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, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_FORWARDED); 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, &err_ptr); TEST_ASSERT_EQUAL_INT(res, GNRC_IPV6_EXT_RH_FORWARDED); TEST_ASSERT_EQUAL_INT(SRH_SEG_LEFT - 2, srh->seg_left); TEST_ASSERT(ipv6_addr_equal(&hdr.dst, &expected2)); } /* tools for external interaction */ static inline void _ipreg_usage(char *cmd) { printf("Usage: %s {reg|unreg}", cmd); } static int _ipreg(int argc, char **argv) { if (argc < 2) { _ipreg_usage(argv[0]); return 1; } else if (strcmp("reg", argv[1]) == 0) { if (ip_entry.target.pid != KERNEL_PID_UNDEF) { puts("Already registered to protocol number 59"); return 1; } gnrc_netreg_entry_init_pid(&ip_entry, PROTNUM_IPV6_NONXT, gnrc_pktdump_pid); gnrc_netreg_register(GNRC_NETTYPE_IPV6, &ip_entry); puts("Registered to protocol number 59"); } else if (strcmp("unreg", argv[1]) == 0) { puts("Unregistered from protocol number 59"); gnrc_netreg_unregister(GNRC_NETTYPE_IPV6, &ip_entry); gnrc_netreg_entry_init_pid(&ip_entry, 0, KERNEL_PID_UNDEF); } else { _ipreg_usage(argv[0]); return 1; } return 0; } static void run_unittests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(test_rpl_srh_dst_multicast), new_TestFixture(test_rpl_srh_route_multicast), new_TestFixture(test_rpl_srh_too_many_seg_left), new_TestFixture(test_rpl_srh_nexthop_no_prefix_elided), new_TestFixture(test_rpl_srh_nexthop_prefix_elided), }; EMB_UNIT_TESTCALLER(rpl_srh_tests, set_up_tests, NULL, fixtures); TESTS_START(); TESTS_RUN((Test *)&rpl_srh_tests); TESTS_END(); } static int _unittests(int argc, char** argv) { (void) argc; (void) argv; run_unittests(); return 0; } static const shell_command_t shell_commands[] = { { "ip", "Registers pktdump to protocol number 59 (no next header)", _ipreg }, { "unittests", "Runs unitest", _unittests}, { NULL, NULL, NULL } }; int main(void) { shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); return 0; }