/* * 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 "byteorder.h" #include "embUnit.h" #include "embUnit/embUnit.h" #include "msg.h" #include "net/gnrc/netapi.h" #include "net/gnrc/netdev.h" #include "net/gnrc/netreg.h" #include "net/gnrc/pktbuf.h" #include "net/icmpv6.h" #include "net/ndp.h" #include "net/netopt.h" #include "sched.h" #include "net/gnrc/ndp2.h" #define TEST_CUR_HL (194U) #define TEST_LTIME (894U) #define TEST_REACH_TIME (1597495062U) #define TEST_RETRANS_TIMER (1819101160U) #define TEST_PFX_LEN (42U) #define TEST_VALID_LTIME (223526372U) #define TEST_PREF_LTIME (2056660713U) #define TEST_NDP_OPT_SIZE (14U) #define TEST_NDP_OPT_TYPE (142U) #define TEST_MTU (669256124U) #define TEST_ASSERT_ALLOCATION(pkt, s, t) \ TEST_ASSERT_NULL((pkt)->next); \ TEST_ASSERT_NOT_NULL((pkt)->data); \ TEST_ASSERT_EQUAL_INT((s), (pkt)->size); \ TEST_ASSERT_EQUAL_INT((t), (pkt)->type) static const ipv6_addr_t test_dst = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x25, 0x22, 0xc6, 0xdf, 0x05, 0xf2, 0x6b } }; static const ipv6_addr_t test_src = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x43, 0xb7, 0x74, 0xd7, 0xa9, 0x30, 0x74 } }; static const ipv6_addr_t test_tgt = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x78, 0x95, 0x84, 0x71, 0x5f, 0x47, 0x53 } }; static const ipv6_addr_t test_pfx = { { 0x47, 0x25, 0xd9, 0x3b, 0x7f, 0xcc, 0x15, 0x6c, 0x64, 0x3e, 0x76, 0x0d, 0x30, 0x10, 0x0d, 0xc8 } }; static const uint8_t test_src_l2[] = { 0xe7, 0x43, 0xb7, 0x74, 0xd7, 0xa9, 0x30, 0x74 }; static kernel_pid_t test_iface = KERNEL_PID_UNDEF; static void init_pkt_handler(void); static inline size_t ceil8(size_t size); static void set_up(void) { gnrc_pktbuf_init(); } static void fill_pktbuf(void) { gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, GNRC_PKTBUF_SIZE - sizeof(gnrc_pktsnip_t), GNRC_NETTYPE_UNDEF); TEST_ASSERT_NOT_NULL(pkt); TEST_ASSERT(gnrc_pktbuf_is_sane()); } static void test_nbr_sol_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_nbr_sol_build(&test_tgt, NULL)); } static void test_nbr_sol_build__success(void) { gnrc_pktsnip_t *pkt; ndp_nbr_sol_t *nbr_sol; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_nbr_sol_build(&test_tgt, NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, sizeof(ndp_nbr_sol_t), GNRC_NETTYPE_ICMPV6); /* check packet content */ nbr_sol = pkt->data; TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_SOL, nbr_sol->type); TEST_ASSERT_EQUAL_INT(0, nbr_sol->code); TEST_ASSERT_EQUAL_INT(0, nbr_sol->resv.u32); TEST_ASSERT_MESSAGE(ipv6_addr_equal(&test_tgt, &nbr_sol->tgt), "nbr_sol->tgt != test_tgt"); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_nbr_adv_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_nbr_adv_build(&test_tgt, 0, NULL)); } static void test_nbr_adv_build__success(uint8_t flags) { gnrc_pktsnip_t *pkt; ndp_nbr_adv_t *nbr_adv; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_nbr_adv_build(&test_tgt, flags, NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, sizeof(ndp_nbr_adv_t), GNRC_NETTYPE_ICMPV6); /* check packet content */ nbr_adv = pkt->data; TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_ADV, nbr_adv->type); TEST_ASSERT_EQUAL_INT(0, nbr_adv->code); TEST_ASSERT_EQUAL_INT(flags, nbr_adv->flags); TEST_ASSERT_EQUAL_INT(0, nbr_adv->resv[0]); TEST_ASSERT_EQUAL_INT(0, nbr_adv->resv[1]); TEST_ASSERT_EQUAL_INT(0, nbr_adv->resv[2]); TEST_ASSERT_MESSAGE(ipv6_addr_equal(&test_tgt, &nbr_adv->tgt), "nbr_adv->tgt != test_tgt"); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_nbr_adv_build__success_without_flags(void) { test_nbr_adv_build__success(0); } static void test_nbr_adv_build__success_with_flags(void) { test_nbr_adv_build__success(NDP_NBR_ADV_FLAGS_S); } static void test_rtr_sol_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_rtr_sol_build(NULL)); } static void test_rtr_sol_build__success(void) { gnrc_pktsnip_t *pkt; ndp_rtr_sol_t *rtr_sol; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_rtr_sol_build(NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, sizeof(ndp_rtr_sol_t), GNRC_NETTYPE_ICMPV6); /* check packet content */ rtr_sol = pkt->data; TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_SOL, rtr_sol->type); TEST_ASSERT_EQUAL_INT(0, rtr_sol->code); TEST_ASSERT_EQUAL_INT(0, rtr_sol->resv.u32); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_rtr_adv_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_rtr_adv_build(TEST_CUR_HL, 0, TEST_LTIME, TEST_REACH_TIME, TEST_RETRANS_TIMER, NULL)); } static void test_rtr_adv_build__success(uint8_t flags) { gnrc_pktsnip_t *pkt; ndp_rtr_adv_t *rtr_adv; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_rtr_adv_build(TEST_CUR_HL, flags, TEST_LTIME, TEST_REACH_TIME, TEST_RETRANS_TIMER, NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, sizeof(ndp_rtr_adv_t), GNRC_NETTYPE_ICMPV6); /* check packet content */ rtr_adv = pkt->data; TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_ADV, rtr_adv->type); TEST_ASSERT_EQUAL_INT(0, rtr_adv->code); TEST_ASSERT_EQUAL_INT(TEST_CUR_HL, rtr_adv->cur_hl); TEST_ASSERT_EQUAL_INT(flags, rtr_adv->flags); TEST_ASSERT_EQUAL_INT(TEST_LTIME, byteorder_ntohs(rtr_adv->ltime)); TEST_ASSERT_EQUAL_INT(TEST_REACH_TIME, byteorder_ntohl(rtr_adv->reach_time)); TEST_ASSERT_EQUAL_INT(TEST_RETRANS_TIMER, byteorder_ntohl(rtr_adv->retrans_timer)); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_rtr_adv_build__success_without_flags(void) { test_rtr_adv_build__success(0); } static void test_rtr_adv_build__success_with_flags(void) { test_rtr_adv_build__success(NDP_RTR_ADV_FLAGS_M); } static void test_opt_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_opt_build(TEST_NDP_OPT_TYPE, TEST_NDP_OPT_SIZE, NULL)); } static void test_opt_build__success(void) { gnrc_pktsnip_t *pkt; ndp_opt_t *opt; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_build(TEST_NDP_OPT_TYPE, TEST_NDP_OPT_SIZE, NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, ceil8(TEST_NDP_OPT_SIZE), GNRC_NETTYPE_UNDEF); /* check packet content */ opt = pkt->data; TEST_ASSERT_EQUAL_INT(TEST_NDP_OPT_TYPE, opt->type); TEST_ASSERT_EQUAL_INT(ceil8(TEST_NDP_OPT_SIZE) / 8, opt->len); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_opt_sl2a_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_opt_sl2a_build(test_src_l2, sizeof(test_src_l2), NULL)); } static void test_opt_sl2a_build__success(void) { gnrc_pktsnip_t *pkt; ndp_opt_t *opt; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_sl2a_build(test_src_l2, sizeof(test_src_l2), NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)), GNRC_NETTYPE_UNDEF); /* check packet content */ opt = pkt->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)) / 8, opt->len); TEST_ASSERT_MESSAGE(memcmp(test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, "opt->l2addr != test_src_l2"); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_opt_tl2a_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_opt_tl2a_build(test_src_l2, sizeof(test_src_l2), NULL)); } static void test_opt_tl2a_build__success(void) { gnrc_pktsnip_t *pkt; ndp_opt_t *opt; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_tl2a_build(test_src_l2, sizeof(test_src_l2), NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)), GNRC_NETTYPE_UNDEF); /* check packet content */ opt = pkt->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_TL2A, opt->type); TEST_ASSERT_EQUAL_INT(ceil8(sizeof(ndp_opt_t) + sizeof(test_src_l2)) / 8, opt->len); TEST_ASSERT_MESSAGE(memcmp(test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, "opt->l2addr != test_src_l2"); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_opt_pi_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_opt_pi_build(&test_pfx, TEST_PFX_LEN, TEST_VALID_LTIME, TEST_PREF_LTIME, 0, NULL)); } static void test_opt_pi_build__success(uint8_t flags) { gnrc_pktsnip_t *pkt; ndp_opt_pi_t *opt; ipv6_addr_t exp_pfx = IPV6_ADDR_UNSPECIFIED; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_pi_build(&test_pfx, TEST_PFX_LEN, TEST_VALID_LTIME, TEST_PREF_LTIME, flags, NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, ceil8(sizeof(ndp_opt_pi_t)), GNRC_NETTYPE_UNDEF); /* check packet content */ /* prepare expected prefix (the function MUST remove all the garbage after * the prefix) */ ipv6_addr_init_prefix(&exp_pfx, &test_pfx, TEST_PFX_LEN); opt = pkt->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_PI, opt->type); TEST_ASSERT_EQUAL_INT(NDP_OPT_PI_LEN, opt->len); TEST_ASSERT_EQUAL_INT(TEST_PFX_LEN, opt->prefix_len); TEST_ASSERT_EQUAL_INT(flags, opt->flags); TEST_ASSERT_EQUAL_INT(TEST_VALID_LTIME, byteorder_ntohl(opt->valid_ltime)); TEST_ASSERT_EQUAL_INT(TEST_PREF_LTIME, byteorder_ntohl(opt->pref_ltime)); TEST_ASSERT_EQUAL_INT(0, opt->resv.u32); TEST_ASSERT_MESSAGE(ipv6_addr_equal(&exp_pfx, &opt->prefix), "opt->prefix != exp_pfx"); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_opt_pi_build__success_without_flags(void) { test_opt_pi_build__success(0); } static void test_opt_pi_build__success_with_flags(void) { test_opt_pi_build__success(NDP_OPT_PI_FLAGS_L); } static void test_opt_mtu_build__pktbuf_full(void) { fill_pktbuf(); TEST_ASSERT_NULL(gnrc_ndp2_opt_mtu_build(TEST_MTU, NULL)); } static void test_opt_mtu_build__success(void) { gnrc_pktsnip_t *pkt; ndp_opt_mtu_t *opt; TEST_ASSERT(gnrc_pktbuf_is_empty()); TEST_ASSERT_NOT_NULL((pkt = gnrc_ndp2_opt_mtu_build(TEST_MTU, NULL))); TEST_ASSERT(gnrc_pktbuf_is_sane()); /* check packet meta-data */ TEST_ASSERT_ALLOCATION(pkt, ceil8(sizeof(ndp_opt_mtu_t)), GNRC_NETTYPE_UNDEF); /* check packet content */ opt = pkt->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_MTU, opt->type); TEST_ASSERT_EQUAL_INT(NDP_OPT_MTU_LEN, opt->len); TEST_ASSERT_EQUAL_INT(0, opt->resv.u16); TEST_ASSERT_EQUAL_INT(TEST_MTU, byteorder_ntohl(opt->mtu)); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static inline kernel_pid_t _get_iface(gnrc_netif_hdr_t *hdr) { return hdr->if_pid; } static inline ipv6_addr_t *_get_ipv6_src(ipv6_hdr_t *hdr) { return &hdr->src; } static inline ipv6_addr_t *_get_ipv6_dst(ipv6_hdr_t *hdr) { return &hdr->dst; } #define ASSERT_NETIF_HDR(iface, pkt) \ TEST_ASSERT_NOT_NULL(pkt); \ TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_NETIF, pkt->type); \ TEST_ASSERT_NOT_NULL(pkt->data); \ TEST_ASSERT_EQUAL_INT(iface, _get_iface(pkt->data)) #define ASSERT_IPV6_HDR(src, dst, pkt) \ TEST_ASSERT_NOT_NULL(pkt); \ TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_IPV6, pkt->type); \ TEST_ASSERT_NOT_NULL(pkt->data); \ TEST_ASSERT_MESSAGE(memcmp(src, _get_ipv6_src(pkt->data), \ sizeof(ipv6_addr_t)) == 0, "src != pkt->src"); \ TEST_ASSERT_MESSAGE(memcmp(dst, _get_ipv6_dst(pkt->data), \ sizeof(ipv6_addr_t)) == 0, "dst != pkt->dst") #define ASSERT_ICMPV6_HDR(pkt) \ TEST_ASSERT_NOT_NULL(pkt); \ TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_ICMPV6, pkt->type); \ TEST_ASSERT_NOT_NULL(pkt->data) static void test_nbr_sol_send(const ipv6_addr_t *src) { msg_t msg; gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); gnrc_pktsnip_t *pkt; ndp_nbr_sol_t *nbr_sol; TEST_ASSERT_NOT_NULL(test_netif); gnrc_ndp2_nbr_sol_send(&test_tgt, test_netif, src, &test_dst, NULL); msg_receive(&msg); TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); pkt = msg.content.ptr; /* check packet */ ASSERT_NETIF_HDR(test_iface, pkt); if ((src != NULL) && ipv6_addr_is_unspecified(src)) { ASSERT_IPV6_HDR(&ipv6_addr_unspecified, &test_dst, pkt->next); } else { ASSERT_IPV6_HDR(&test_src, &test_dst, pkt->next); } ASSERT_ICMPV6_HDR(pkt->next->next); TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_sol_t), pkt->next->next->size); nbr_sol = pkt->next->next->data; TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_SOL, nbr_sol->type); TEST_ASSERT_MESSAGE(memcmp(&test_tgt, &nbr_sol->tgt, sizeof(ipv6_addr_t)) == 0, "tgt != nbr_sol->tgt"); if ((src != NULL) && ipv6_addr_is_unspecified(src)) { TEST_ASSERT_NULL(pkt->next->next->next); } else { TEST_ASSERT_NOT_NULL(pkt->next->next->next); TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); ndp_opt_t *opt = pkt->next->next->next->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, "src_l2 != pkt->l2"); TEST_ASSERT_NULL(pkt->next->next->next->next); } gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_sane()); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_nbr_sol_send__src_NULL(void) { test_nbr_sol_send(NULL); } static void test_nbr_sol_send__src_unspecified(void) { test_nbr_sol_send(&ipv6_addr_unspecified); } static void test_nbr_sol_send__src_NOT_NULL(void) { test_nbr_sol_send(&test_src); } static void test_nbr_adv_send(const ipv6_addr_t *tgt, const ipv6_addr_t *dst, bool supply_tl2a, gnrc_pktsnip_t *exp_ext_opts) { msg_t msg; gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); gnrc_pktsnip_t *pkt; ndp_nbr_adv_t *nbr_adv; TEST_ASSERT_NOT_NULL(test_netif); gnrc_ndp2_nbr_adv_send(tgt, test_netif, dst, supply_tl2a, exp_ext_opts); msg_receive(&msg); TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); pkt = msg.content.ptr; /* check packet */ ASSERT_NETIF_HDR(test_iface, pkt); if (ipv6_addr_is_unspecified(dst)) { ASSERT_IPV6_HDR(&ipv6_addr_unspecified, &ipv6_addr_all_nodes_link_local, pkt->next); } else { ASSERT_IPV6_HDR(&ipv6_addr_unspecified, &test_dst, pkt->next); } ASSERT_ICMPV6_HDR(pkt->next->next); TEST_ASSERT_EQUAL_INT(sizeof(ndp_nbr_adv_t), pkt->next->next->size); nbr_adv = pkt->next->next->data; TEST_ASSERT_EQUAL_INT(ICMPV6_NBR_ADV, nbr_adv->type); TEST_ASSERT_MESSAGE(memcmp(tgt, &nbr_adv->tgt, sizeof(ipv6_addr_t)) == 0, "tgt != nbr_adv->tgt"); if (supply_tl2a || ipv6_addr_is_unspecified(dst) || (exp_ext_opts != NULL)) { gnrc_pktsnip_t *ext_opts = NULL; TEST_ASSERT_NOT_NULL(pkt->next->next->next); TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); /* implicitly this is the same */ if (supply_tl2a || ipv6_addr_is_unspecified(dst)) { ndp_opt_t *opt = pkt->next->next->next->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_TL2A, opt->type); TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, "src_l2 != pkt->l2"); if (exp_ext_opts == NULL) { TEST_ASSERT_NULL(pkt->next->next->next->next); } else { /* extra option comes after TL2AO */ ext_opts = pkt->next->next->next->next; } } else { /* extra option comes directly after neighbor advertisement */ ext_opts = pkt->next->next->next; } TEST_ASSERT(exp_ext_opts == ext_opts); } else { TEST_ASSERT_NULL(pkt->next->next->next); } gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_sane()); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, false, NULL); } static void test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, false, ext_opts); } static void test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, true, NULL); } static void test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_tgt, &ipv6_addr_unspecified, true, ext_opts); } static void test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_tgt, &test_dst, false, NULL); } static void test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_tgt, &test_dst, false, ext_opts); } static void test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_tgt, &test_dst, true, NULL); } static void test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_tgt, &test_dst, true, ext_opts); } static void test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, false, NULL); } static void test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, false, ext_opts); } static void test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, true, NULL); } static void test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_src, &ipv6_addr_unspecified, true, ext_opts); } static void test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_src, &test_dst, false, NULL); } static void test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_src, &test_dst, false, ext_opts); } static void test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_no_ext_opts(void) { test_nbr_adv_send(&test_src, &test_dst, true, NULL); } static void test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_nbr_adv_send(&test_src, &test_dst, true, ext_opts); } static void test_rtr_sol_send(const ipv6_addr_t *dst) { msg_t msg; gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); gnrc_pktsnip_t *pkt; ndp_rtr_sol_t *rtr_sol; TEST_ASSERT_NOT_NULL(test_netif); gnrc_ndp2_rtr_sol_send(test_netif, dst); msg_receive(&msg); TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); pkt = msg.content.ptr; /* check packet */ ASSERT_NETIF_HDR(test_iface, pkt); if (dst != NULL) { ASSERT_IPV6_HDR(&test_src, dst, pkt->next); } else { ASSERT_IPV6_HDR(&test_src, &ipv6_addr_all_routers_link_local, pkt->next); } ASSERT_ICMPV6_HDR(pkt->next->next); TEST_ASSERT_EQUAL_INT(sizeof(ndp_rtr_sol_t), pkt->next->next->size); rtr_sol = pkt->next->next->data; TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_SOL, rtr_sol->type); if ((dst == NULL) || ipv6_addr_is_link_local(dst)) { TEST_ASSERT_NOT_NULL(pkt->next->next->next); TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); ndp_opt_t *opt = pkt->next->next->next->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, "src_l2 != pkt->l2"); TEST_ASSERT_NULL(pkt->next->next->next->next); } else { TEST_ASSERT_NULL(pkt->next->next->next); } gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_sane()); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_rtr_sol_send__dst_NULL(void) { test_rtr_sol_send(NULL); } static void test_rtr_sol_send__dst_local(void) { test_rtr_sol_send(&test_dst); } static void test_rtr_sol_send__dst_global(void) { ipv6_addr_t dst; memcpy(&dst, &test_dst, sizeof(dst)); ipv6_addr_init_prefix(&dst, &test_pfx, 64); test_rtr_sol_send(&test_dst); } #if GNRC_IPV6_NIB_CONF_ROUTER static void test_rtr_adv_send(const ipv6_addr_t *src, const ipv6_addr_t *dst, bool fin, gnrc_pktsnip_t *exp_ext_opts) { msg_t msg; gnrc_ipv6_netif_t *test_netif = gnrc_ipv6_netif_get(test_iface); gnrc_pktsnip_t *pkt; ndp_rtr_adv_t *rtr_adv; TEST_ASSERT_NOT_NULL(test_netif); gnrc_ndp2_rtr_adv_send(test_netif, src, dst, fin, exp_ext_opts); msg_receive(&msg); TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_SND, msg.type); pkt = msg.content.ptr; /* check packet */ ASSERT_NETIF_HDR(test_iface, pkt); /* testing for unspecified source is complicated so we skip it here and * do it in later integration tests */ if (dst != NULL) { ASSERT_IPV6_HDR(&test_src, dst, pkt->next); } else { ASSERT_IPV6_HDR(&test_src, &ipv6_addr_all_nodes_link_local, pkt->next); } ASSERT_ICMPV6_HDR(pkt->next->next); TEST_ASSERT_EQUAL_INT(sizeof(ndp_rtr_adv_t), pkt->next->next->size); rtr_adv = pkt->next->next->data; TEST_ASSERT_EQUAL_INT(ICMPV6_RTR_ADV, rtr_adv->type); if (fin) { TEST_ASSERT_EQUAL_INT(0, rtr_adv->ltime.u16); } else { TEST_ASSERT_MESSAGE(rtr_adv->ltime.u16 != 0, "rtr_adv->ltime == 0"); } /* check for SLLAO */ TEST_ASSERT_NOT_NULL(pkt->next->next->next); TEST_ASSERT_EQUAL_INT(GNRC_NETTYPE_UNDEF, pkt->next->next->next->type); TEST_ASSERT_NOT_NULL(pkt->next->next->next->data); ndp_opt_t *opt = pkt->next->next->next->data; TEST_ASSERT_EQUAL_INT(NDP_OPT_SL2A, opt->type); TEST_ASSERT_MESSAGE(memcmp(&test_src_l2, opt + 1, sizeof(test_src_l2)) == 0, "src_l2 != pkt->l2"); TEST_ASSERT_MESSAGE(pkt->next->next->next->next == exp_ext_opts, "ext_opts set wrong"); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_sane()); TEST_ASSERT(gnrc_pktbuf_is_empty()); } static void test_rtr_adv_send__src_NULL_dst_NULL_no_fin_no_ext_opts(void) { test_rtr_adv_send(NULL, NULL, false, NULL); } static void test_rtr_adv_send__src_NULL_dst_NULL_no_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(NULL, NULL, false, ext_opts); } static void test_rtr_adv_send__src_NULL_dst_NULL_fin_no_ext_opts(void) { test_rtr_adv_send(NULL, NULL, true, NULL); } static void test_rtr_adv_send__src_NULL_dst_NULL_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(NULL, NULL, true, ext_opts); } static void test_rtr_adv_send__src_NULL_dst_no_fin_no_ext_opts(void) { test_rtr_adv_send(NULL, &test_dst, false, NULL); } static void test_rtr_adv_send__src_NULL_dst_no_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(NULL, &test_dst, false, ext_opts); } static void test_rtr_adv_send__src_NULL_dst_fin_no_ext_opts(void) { test_rtr_adv_send(NULL, &test_dst, true, NULL); } static void test_rtr_adv_send__src_NULL_dst_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(NULL, &test_dst, true, ext_opts); } static void test_rtr_adv_send__src_dst_NULL_no_fin_no_ext_opts(void) { test_rtr_adv_send(&test_src, NULL, false, NULL); } static void test_rtr_adv_send__src_dst_NULL_no_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(&test_src, NULL, false, ext_opts); } static void test_rtr_adv_send__src_dst_NULL_fin_no_ext_opts(void) { test_rtr_adv_send(&test_src, NULL, true, NULL); } static void test_rtr_adv_send__src_dst_NULL_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(&test_src, NULL, true, ext_opts); } static void test_rtr_adv_send__src_dst_no_fin_no_ext_opts(void) { test_rtr_adv_send(&test_src, &test_dst, false, NULL); } static void test_rtr_adv_send__src_dst_no_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(&test_src, &test_dst, false, ext_opts); } static void test_rtr_adv_send__src_dst_fin_no_ext_opts(void) { test_rtr_adv_send(&test_src, &test_dst, true, NULL); } static void test_rtr_adv_send__src_dst_fin_ext_opts(void) { gnrc_pktsnip_t *ext_opts = gnrc_pktbuf_add(NULL, NULL, 8U, GNRC_NETTYPE_UNDEF); test_rtr_adv_send(&test_src, &test_dst, true, ext_opts); } #endif static Test *tests_gnrc_ndp2_build(void) { EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(test_nbr_sol_build__pktbuf_full), new_TestFixture(test_nbr_sol_build__success), new_TestFixture(test_nbr_adv_build__pktbuf_full), new_TestFixture(test_nbr_adv_build__success_without_flags), new_TestFixture(test_nbr_adv_build__success_with_flags), new_TestFixture(test_rtr_sol_build__pktbuf_full), new_TestFixture(test_rtr_sol_build__success), new_TestFixture(test_rtr_adv_build__pktbuf_full), new_TestFixture(test_rtr_adv_build__success_without_flags), new_TestFixture(test_rtr_adv_build__success_with_flags), new_TestFixture(test_opt_build__pktbuf_full), new_TestFixture(test_opt_build__success), new_TestFixture(test_opt_sl2a_build__pktbuf_full), new_TestFixture(test_opt_sl2a_build__success), new_TestFixture(test_opt_tl2a_build__pktbuf_full), new_TestFixture(test_opt_tl2a_build__success), new_TestFixture(test_opt_pi_build__pktbuf_full), new_TestFixture(test_opt_pi_build__success_without_flags), new_TestFixture(test_opt_pi_build__success_with_flags), new_TestFixture(test_opt_mtu_build__pktbuf_full), new_TestFixture(test_opt_mtu_build__success), }; EMB_UNIT_TESTCALLER(tests, set_up, NULL, fixtures); return (Test *)&tests; } static Test *tests_gnrc_ndp2_send(void) { EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(test_nbr_sol_send__src_NULL), new_TestFixture(test_nbr_sol_send__src_unspecified), new_TestFixture(test_nbr_sol_send__src_NOT_NULL), new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_no_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_unspecified_dst_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_no_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__foreign_tgt_specified_dst_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_no_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_unspecified_dst_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_no_supply_tl2a_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_no_ext_opts), new_TestFixture(test_nbr_adv_send__src_tgt_specified_dst_supply_tl2a_ext_opts), new_TestFixture(test_rtr_sol_send__dst_NULL), new_TestFixture(test_rtr_sol_send__dst_local), new_TestFixture(test_rtr_sol_send__dst_global), #if GNRC_IPV6_NIB_CONF_ROUTER new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_no_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_no_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_NULL_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_no_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_no_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_NULL_dst_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_NULL_no_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_NULL_no_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_NULL_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_NULL_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_no_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_no_fin_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_fin_no_ext_opts), new_TestFixture(test_rtr_adv_send__src_dst_fin_ext_opts), #endif }; EMB_UNIT_TESTCALLER(tests, set_up, NULL, fixtures); return (Test *)&tests; } int main(void) { TESTS_START(); TESTS_RUN(tests_gnrc_ndp2_build()); init_pkt_handler(); TESTS_RUN(tests_gnrc_ndp2_send()); TESTS_END(); return 0; } #define MSG_QUEUE_SIZE (2) static char test_netif_stack[THREAD_STACKSIZE_DEFAULT]; static msg_t msg_queue_main[MSG_QUEUE_SIZE]; static msg_t msg_queue_netif[MSG_QUEUE_SIZE]; static gnrc_netreg_entry_t netreg_entry; int test_iface_get(gnrc_netapi_opt_t *opt) { switch (opt->opt) { case NETOPT_ADDRESS_LONG: if (opt->data_len < sizeof(test_src_l2)) { return -EOVERFLOW; } memcpy(opt->data, test_src_l2, sizeof(test_src_l2)); return sizeof(test_src_l2); case NETOPT_SRC_LEN: { uint16_t *val = opt->data; if (opt->data_len != sizeof(uint16_t)) { return -EOVERFLOW; } *val = sizeof(test_src_l2); return sizeof(uint16_t); } case NETOPT_IPV6_IID: if (opt->data_len < sizeof(uint64_t)) { return -EOVERFLOW; } memcpy(opt->data, &test_src.u64[1], sizeof(uint64_t)); return sizeof(uint64_t); case NETOPT_IS_WIRED: return 1; case NETOPT_MAX_PACKET_SIZE: { uint16_t *val = opt->data; if (opt->data_len != sizeof(uint16_t)) { return -EOVERFLOW; } *val = 100U; return sizeof(uint16_t); } default: return -ENOTSUP; } } static void *test_iface_thread(void *args) { msg_t msg, reply = { .type = GNRC_NETAPI_MSG_TYPE_ACK }; (void)args; msg_init_queue(msg_queue_netif, MSG_QUEUE_SIZE); while (1) { msg_receive(&msg); switch (msg.type) { case GNRC_NETAPI_MSG_TYPE_SND: case GNRC_NETAPI_MSG_TYPE_RCV: gnrc_pktbuf_release(msg.content.ptr); continue; case GNRC_NETAPI_MSG_TYPE_GET: reply.content.value = (uint32_t)test_iface_get(msg.content.ptr); break; case GNRC_NETAPI_MSG_TYPE_SET: reply.content.value = (uint32_t)(-ENOTSUP); break; } msg_reply(&msg, &reply); } return NULL; } static void init_pkt_handler(void) { msg_init_queue(msg_queue_main, MSG_QUEUE_SIZE); gnrc_netreg_entry_init_pid(&netreg_entry, GNRC_NETREG_DEMUX_CTX_ALL, sched_active_pid); gnrc_netreg_register(GNRC_NETTYPE_NDP2, &netreg_entry); test_iface = thread_create(test_netif_stack, sizeof(test_netif_stack), GNRC_NETDEV_MAC_PRIO, THREAD_CREATE_STACKTEST, test_iface_thread, NULL, "test-iface"); TEST_ASSERT_MESSAGE(test_iface > KERNEL_PID_UNDEF, "Unable to start test interface"); gnrc_netif_add(test_iface); gnrc_ipv6_netif_init_by_dev(); } static inline size_t ceil8(size_t size) { if (size % 8) { return ((size / 8) + 1) * 8; } else { return size; } }