/* main.c - Application main entry point */ /* * Copyright (c) 2015 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL); #include #include #include #include #include #include #include #include #include #include #include #include #include "icmpv6.h" #include "ipv6.h" #include "udp_internal.h" #define NET_LOG_ENABLED 1 #include "net_private.h" static struct in6_addr my_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct in6_addr peer_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2 } } }; static struct in6_addr mcast_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; /* ICMPv6 NS frame (74 bytes) */ static const unsigned char icmpv6_ns_invalid[] = { /* IPv6 header starts here */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3A, 0xFF, 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* ICMPv6 NS header starts here */ 0x87, 0x00, 0x7B, 0x9C, 0x60, 0x00, 0x00, 0x00, /* Target Address */ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, /* Source link layer address */ 0x01, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD8, /* Target link layer address */ 0x02, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD7, /* Source link layer address */ 0x01, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD6, /* MTU option */ 0x05, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD5, }; /* ICMPv6 NS frame (64 bytes) */ static const unsigned char icmpv6_ns_no_sllao[] = { /* IPv6 header starts here */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3A, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* ICMPv6 NS header starts here */ 0x87, 0x00, 0x7B, 0x9C, 0x60, 0x00, 0x00, 0x00, /* Target Address */ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, }; /* */ static const unsigned char icmpv6_ra[] = { /* IPv6 header starts here */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* ICMPv6 RA header starts here */ 0x86, 0x00, 0x8b, 0xaa, 0x40, 0x00, 0x07, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* SLLAO */ 0x01, 0x01, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, /* MTU */ 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, /* Prefix info*/ 0x03, 0x04, 0x40, 0xc0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* IPv6 hop-by-hop option in the message */ static const unsigned char ipv6_hbho[] = { /* IPv6 header starts here (IPv6 addresses are wrong) */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x3f, /* `....6.? */ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Hop-by-hop option starts here */ 0x11, 0x00, /* RPL sub-option starts here */ 0x63, 0x04, 0x80, 0x1e, 0x01, 0x00, /* ..c..... */ /* UDP header starts here (checksum is "fixed" in this example) */ 0xaa, 0xdc, 0xbf, 0xd7, 0x00, 0x2e, 0xa2, 0x55, /* ......M. */ /* User data starts here (38 bytes) */ 0x10, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* ........ */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x02, /* ........ */ 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x03, /* ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xc9, /* ........ */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* ...... */ }; static bool expecting_ra; static u32_t dad_time[3]; static bool test_failed; static struct k_sem wait_data; static bool recv_cb_called; #define WAIT_TIME 250 #define WAIT_TIME_LONG MSEC_PER_SEC #define SENDING 93244 #define MY_PORT 1969 #define PEER_PORT 16233 struct net_test_ipv6 { u8_t mac_addr[sizeof(struct net_eth_addr)]; struct net_linkaddr ll_addr; }; int net_test_dev_init(struct device *dev) { return 0; } static u8_t *net_test_get_mac(struct device *dev) { struct net_test_ipv6 *context = dev->driver_data; if (context->mac_addr[2] == 0x00) { /* 00-00-5E-00-53-xx Documentation RFC 7042 */ context->mac_addr[0] = 0x00; context->mac_addr[1] = 0x00; context->mac_addr[2] = 0x5E; context->mac_addr[3] = 0x00; context->mac_addr[4] = 0x53; context->mac_addr[5] = sys_rand32_get(); } return context->mac_addr; } static void net_test_iface_init(struct net_if *iface) { u8_t *mac = net_test_get_mac(net_if_get_device(iface)); net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr), NET_LINK_ETHERNET); } /** * @brief IPv6 handle RA message */ static void prepare_ra_message(struct net_pkt *pkt) { struct net_eth_hdr hdr; net_buf_unref(pkt->buffer); pkt->buffer = NULL; net_pkt_alloc_buffer(pkt, sizeof(struct net_eth_hdr) + sizeof(icmpv6_ra), AF_UNSPEC, 0); net_pkt_cursor_init(pkt); hdr.type = htons(NET_ETH_PTYPE_IPV6); memset(&hdr.src, 0, sizeof(struct net_eth_addr)); memcpy(&hdr.dst, net_pkt_iface(pkt)->if_dev->link_addr.addr, sizeof(struct net_eth_addr)); net_pkt_set_overwrite(pkt, false); net_pkt_write(pkt, &hdr, sizeof(struct net_eth_hdr)); net_pkt_write(pkt, icmpv6_ra, sizeof(icmpv6_ra)); net_pkt_cursor_init(pkt); } static struct net_icmp_hdr *get_icmp_hdr(struct net_pkt *pkt) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, struct net_icmp_hdr); /* First frag is the ll header */ struct net_buf *bak = pkt->buffer; struct net_pkt_cursor backup; struct net_icmp_hdr *hdr; pkt->buffer = bak->frags; net_pkt_cursor_backup(pkt, &backup); net_pkt_cursor_init(pkt); if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt))) { hdr = NULL; goto out; } hdr = (struct net_icmp_hdr *)net_pkt_get_data(pkt, &icmp_access); out: pkt->buffer = bak; net_pkt_cursor_restore(pkt, &backup); return hdr; } static int tester_send(struct device *dev, struct net_pkt *pkt) { struct net_icmp_hdr *icmp; if (!pkt->buffer) { TC_ERROR("No data to send!\n"); return -ENODATA; } icmp = get_icmp_hdr(pkt); /* Reply with RA messge */ if (icmp->type == NET_ICMPV6_RS) { if (expecting_ra) { prepare_ra_message(pkt); } else { goto out; } } if (icmp->type == NET_ICMPV6_NS) { if (dad_time[0] == 0U) { dad_time[0] = k_uptime_get_32(); } else if (dad_time[1] == 0U) { dad_time[1] = k_uptime_get_32(); } else if (dad_time[2] == 0U) { dad_time[2] = k_uptime_get_32(); } goto out; } /* Feed this data back to us */ if (net_recv_data(net_pkt_iface(pkt), net_pkt_clone(pkt, K_NO_WAIT)) < 0) { TC_ERROR("Data receive failed."); goto out; } return 0; out: test_failed = true; return 0; } struct net_test_ipv6 net_test_data; static const struct ethernet_api net_test_if_api = { .iface_api.init = net_test_iface_init, .send = tester_send, }; #define _ETH_L2_LAYER ETHERNET_L2 #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(ETHERNET_L2) NET_DEVICE_INIT(net_test_ipv6, "net_test_ipv6", net_test_dev_init, device_pm_control_nop, &net_test_data, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127); /** * @brief IPv6 Init */ static void test_init(void) { struct net_if_addr *ifaddr = NULL, *ifaddr2; struct net_if_mcast_addr *maddr; struct net_if *iface = net_if_get_default(); struct net_if *iface2 = NULL; struct net_if_ipv6 *ipv6; int i; zassert_not_null(iface, "Interface is NULL"); /* We cannot use net_if_ipv6_addr_add() to add the address to * network interface in this case as that would trigger DAD which * we are not prepared to handle here. So instead add the address * manually in this special case so that subsequent tests can * pass. */ zassert_false(net_if_config_ipv6_get(iface, &ipv6) < 0, "IPv6 config is not valid"); for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { if (iface->config.ip.ipv6->unicast[i].is_used) { continue; } ifaddr = &iface->config.ip.ipv6->unicast[i]; ifaddr->is_used = true; ifaddr->address.family = AF_INET6; ifaddr->addr_type = NET_ADDR_MANUAL; ifaddr->addr_state = NET_ADDR_PREFERRED; net_ipaddr_copy(&ifaddr->address.in6_addr, &my_addr); break; } ifaddr2 = net_if_ipv6_addr_lookup(&my_addr, &iface2); zassert_true(ifaddr2 == ifaddr, "Invalid ifaddr (%p vs %p)\n", ifaddr, ifaddr2); net_ipv6_addr_create(&mcast_addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001); maddr = net_if_ipv6_maddr_add(iface, &mcast_addr); zassert_not_null(maddr, "Cannot add multicast IPv6 address %s\n", net_sprint_ipv6_addr(&mcast_addr)); /* The semaphore is there to wait the data to be received. */ k_sem_init(&wait_data, 0, UINT_MAX); } /** * @brief IPv6 compare prefix * */ static void test_cmp_prefix(void) { bool st; struct in6_addr prefix1 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct in6_addr prefix2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2 } } }; st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 64); zassert_true(st, "Prefix /64 compare failed"); st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 65); zassert_true(st, "Prefix /65 compare failed"); /* Set one extra bit in the other prefix for testing /65 */ prefix1.s6_addr[8] = 0x80; st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 65); zassert_false(st, "Prefix /65 compare should have failed"); /* Set two bits in prefix2, it is now /66 */ prefix2.s6_addr[8] = 0xc0; st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 65); zassert_true(st, "Prefix /65 compare failed"); /* Set all remaining bits in prefix2, it is now /128 */ (void)memset(&prefix2.s6_addr[8], 0xff, 8); st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 65); zassert_true(st, "Prefix /65 compare failed"); /* Comparing /64 should be still ok */ st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 64); zassert_true(st, "Prefix /64 compare failed"); /* But comparing /66 should should fail */ st = net_ipv6_is_prefix((u8_t *)&prefix1, (u8_t *)&prefix2, 66); zassert_false(st, "Prefix /66 compare should have failed"); } /** * @brief IPv6 add neighbor */ static void test_add_neighbor(void) { struct net_nbr *nbr; struct net_linkaddr_storage llstorage; struct net_linkaddr lladdr; llstorage.addr[0] = 0x01; llstorage.addr[1] = 0x02; llstorage.addr[2] = 0x33; llstorage.addr[3] = 0x44; llstorage.addr[4] = 0x05; llstorage.addr[5] = 0x06; lladdr.len = 6U; lladdr.addr = llstorage.addr; lladdr.type = NET_LINK_ETHERNET; nbr = net_ipv6_nbr_add(net_if_get_default(), &peer_addr, &lladdr, false, NET_IPV6_NBR_STATE_REACHABLE); zassert_not_null(nbr, "Cannot add peer %s to neighbor cache\n", net_sprint_ipv6_addr(&peer_addr)); } /** * @brief IPv6 add more than max neighbors */ static void test_add_max_neighbors(void) { struct in6_addr dst_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3 } } }; struct net_nbr *nbr; struct net_linkaddr_storage llstorage; struct net_linkaddr lladdr; u8_t i; llstorage.addr[0] = 0x01; llstorage.addr[1] = 0x02; llstorage.addr[2] = 0x33; llstorage.addr[3] = 0x44; llstorage.addr[4] = 0x05; llstorage.addr[5] = 0x07; lladdr.len = 6U; lladdr.addr = llstorage.addr; lladdr.type = NET_LINK_ETHERNET; for (i = 0U; i < CONFIG_NET_IPV6_MAX_NEIGHBORS + 1; i++) { llstorage.addr[5] += i; dst_addr.s6_addr[15] += i; nbr = net_ipv6_nbr_add(net_if_get_default(), &dst_addr, &lladdr, false, NET_IPV6_NBR_STATE_STALE); zassert_not_null(nbr, "Cannot add peer %s to neighbor cache\n", net_sprint_ipv6_addr(&dst_addr)); } } /** * @brief IPv6 neighbor lookup fail */ static void test_nbr_lookup_fail(void) { struct net_nbr *nbr; nbr = net_ipv6_nbr_lookup(net_if_get_default(), &peer_addr); zassert_is_null(nbr, "Neighbor %s found in cache\n", net_sprint_ipv6_addr(&peer_addr)); } /** * @brief IPv6 neighbor lookup ok */ static void test_nbr_lookup_ok(void) { struct net_nbr *nbr; nbr = net_ipv6_nbr_lookup(net_if_get_default(), &peer_addr); zassert_not_null(nbr, "Neighbor %s not found in cache\n", net_sprint_ipv6_addr(&peer_addr)); } /** * @brief IPv6 send NS extra options */ static void test_send_ns_extra_options(void) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv6_ns_invalid), AF_UNSPEC, 0, K_FOREVER); NET_ASSERT(pkt, "Out of TX packets"); net_pkt_write(pkt, icmpv6_ns_invalid, sizeof(icmpv6_ns_invalid)); net_pkt_lladdr_clear(pkt); zassert_false((net_recv_data(iface, pkt) < 0), "Data receive for invalid NS failed."); } /** * @brief IPv6 send NS no option */ static void test_send_ns_no_options(void) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv6_ns_no_sllao), AF_UNSPEC, 0, K_FOREVER); NET_ASSERT(pkt, "Out of TX packets"); net_pkt_write(pkt, icmpv6_ns_no_sllao, sizeof(icmpv6_ns_no_sllao)); net_pkt_lladdr_clear(pkt); zassert_false((net_recv_data(iface, pkt) < 0), "Data receive for invalid NS failed."); } /** * @brief IPv6 prefix timeout */ static void test_prefix_timeout(void) { struct net_if_ipv6_prefix *prefix; struct in6_addr addr = { { { 0x20, 1, 0x0d, 0xb8, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; u32_t lifetime = 1U; int len = 64; prefix = net_if_ipv6_prefix_add(net_if_get_default(), &addr, len, lifetime); zassert_not_null(prefix, "Cannot get prefix"); net_if_ipv6_prefix_set_lf(prefix, false); net_if_ipv6_prefix_set_timer(prefix, lifetime); k_sleep(K_SECONDS(lifetime * 2U)); prefix = net_if_ipv6_prefix_lookup(net_if_get_default(), &addr, len); zassert_is_null(prefix, "Prefix %s/%d should have expired", net_sprint_ipv6_addr(&addr), len); } static void test_prefix_timeout_long(void) { struct net_if_ipv6_prefix *ifprefix; struct in6_addr prefix = { { { 0x20, 1, 0x0d, 0xb8, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; u32_t lifetime = 0xfffffffe; int len = 64; u64_t remaining; int ret; ifprefix = net_if_ipv6_prefix_add(net_if_get_default(), &prefix, len, lifetime); net_if_ipv6_prefix_set_lf(ifprefix, false); net_if_ipv6_prefix_set_timer(ifprefix, lifetime); zassert_equal(ifprefix->lifetime.wrap_counter, 2000, "Wrap counter wrong (%d)", ifprefix->lifetime.wrap_counter); remaining = K_SECONDS((u64_t)lifetime) - NET_TIMEOUT_MAX_VALUE * (u64_t)ifprefix->lifetime.wrap_counter; zassert_equal(remaining, ifprefix->lifetime.timer_timeout, "Remaining time wrong (%llu vs %d)", remaining, ifprefix->lifetime.timer_timeout); ret = net_if_ipv6_prefix_rm(net_if_get_default(), &prefix, len); zassert_equal(ret, true, "Prefix %s/%d should have been removed", net_sprint_ipv6_addr(&prefix), len); } static void test_rs_message(void) { struct net_if *iface; int ret; iface = net_if_get_default(); expecting_ra = true; ret = net_ipv6_send_rs(iface); zassert_equal(ret, 0, "RS sending failed (%d)", ret); } static void test_ra_message(void) { struct in6_addr addr = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x2, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea } } }; struct in6_addr prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 } } }; /* We received RA message earlier, make sure that the information * in that message is placed to proper prefix and lookup info. */ expecting_ra = false; zassert_false(!net_if_ipv6_prefix_lookup(net_if_get_default(), &prefix, 32), "Prefix %s should be here\n", net_sprint_ipv6_addr(&prefix)); zassert_false(!net_if_ipv6_router_lookup(net_if_get_default(), &addr), "Router %s should be here\n", net_sprint_ipv6_addr(&addr)); } /** * @brief IPv6 parse Hop-By-Hop Option */ static void test_hbho_message(void) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = net_pkt_alloc_with_buffer(iface, sizeof(ipv6_hbho), AF_UNSPEC, 0, K_FOREVER); NET_ASSERT(pkt, "Out of TX packets"); net_pkt_write(pkt, ipv6_hbho, sizeof(ipv6_hbho)); net_pkt_lladdr_clear(pkt); zassert_false(net_recv_data(iface, pkt) < 0, "Data receive for HBHO failed."); } /* IPv6 hop-by-hop option in the message HBHO (72 Bytes) */ static const unsigned char ipv6_hbho_1[] = { /* IPv6 header starts here */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0xff, 0xfe, 0x9b, 0xb4, 0x47, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Hop-by-hop option starts here */ 0x11, 0x08, /* Padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* UDP header starts here (8 bytes) */ 0x4e, 0x20, 0x10, 0x92, 0x00, 0x30, 0xa1, 0xc5, /* User data starts here (40 bytes) */ 0x30, 0x26, 0x02, 0x01, 0x00, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa0, 0x19, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x05, 0x00, 0x05, 0x00 }; /** * @brief IPv6 parse Hop-By-Hop Option */ static void test_hbho_message_1(void) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = net_pkt_alloc_with_buffer(iface, sizeof(ipv6_hbho_1), AF_UNSPEC, 0, K_FOREVER); NET_ASSERT(pkt, "Out of TX packets"); net_pkt_write(pkt, ipv6_hbho_1, sizeof(ipv6_hbho_1)); net_pkt_lladdr_clear(pkt); zassert_false(net_recv_data(iface, pkt) < 0, "Data receive for HBHO failed."); /* Verify IPv6 Ext hdr length */ zassert_false(net_pkt_ipv6_ext_len(pkt) == 72U, "IPv6 mismatch ext hdr length"); } /* IPv6 hop-by-hop option in the message HBHO (104 Bytes) */ static const unsigned char ipv6_hbho_2[] = { /* IPv6 header starts here */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0xff, 0xfe, 0x9b, 0xb4, 0x47, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Hop-by-hop option starts here */ 0x11, 0x0c, /* padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, /* udp header starts here (8 bytes) */ 0x4e, 0x20, 0x10, 0x92, 0x00, 0x30, 0xa1, 0xc5, /* User data starts here (40 bytes) */ 0x30, 0x26, 0x02, 0x01, 0x00, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa0, 0x19, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x05, 0x00, 0x05, 0x00 }; /** * @brief IPv6 parse Hop-By-Hop Option */ static void test_hbho_message_2(void) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = net_pkt_alloc_with_buffer(iface, sizeof(ipv6_hbho_2), AF_UNSPEC, 0, K_FOREVER); NET_ASSERT(pkt, "Out of TX packets"); net_pkt_write(pkt, ipv6_hbho_2, sizeof(ipv6_hbho_2)); net_pkt_lladdr_clear(pkt); zassert_false(net_recv_data(iface, pkt) < 0, "Data receive for HBHO failed."); /* Verify IPv6 Ext hdr length */ zassert_false(net_pkt_ipv6_ext_len(pkt) == 104U, "IPv6 mismatch ext hdr length"); } /* IPv6 hop-by-hop option in the message HBHO (920 bytes) */ static const unsigned char ipv6_hbho_3[] = { /* IPv6 header starts here */ 0x60, 0x00, 0x00, 0x00, 0x03, 0xc8, 0x00, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0xff, 0xfe, 0x9b, 0xb4, 0x47, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Hop-by-hop option starts here */ 0x11, 0x72, /* padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, /* udp header starts here (8 bytes) */ 0x4e, 0x20, 0x10, 0x92, 0x00, 0x30, 0xa1, 0xc5, /* User data starts here (40 bytes) */ 0x30, 0x26, 0x02, 0x01, 0x00, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa0, 0x19, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x05, 0x00, 0x05, 0x00 }; /** * @brief IPv6 parse Hop-By-Hop Option */ static void test_hbho_message_3(void) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = net_pkt_alloc_with_buffer(iface, sizeof(ipv6_hbho_3), AF_UNSPEC, 0, K_FOREVER); NET_ASSERT(pkt, "Out of TX packets"); net_pkt_write(pkt, ipv6_hbho_3, sizeof(ipv6_hbho_3)); net_pkt_lladdr_clear(pkt); zassert_false(net_recv_data(iface, pkt) < 0, "Data receive for HBHO failed."); /* Verify IPv6 Ext hdr length */ zassert_false(net_pkt_ipv6_ext_len(pkt) == 920U, "IPv6 mismatch ext hdr length"); } #define FIFTY_DAYS (60 * 60 * 24 * 50) /* Implemented in subsys/net/ip/net_if.c */ extern void net_address_lifetime_timeout(void); static void test_address_lifetime(void) { struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0x1 } } }; struct net_if *iface = net_if_get_default(); u32_t vlifetime = 0xffff; u64_t timeout = K_SECONDS((u64_t)vlifetime); struct net_if_addr *ifaddr; u64_t remaining; bool ret; ifaddr = net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, vlifetime); zassert_not_null(ifaddr, "Address with lifetime cannot be added"); /* Make sure DAD gets some time to run */ k_sleep(K_MSEC(200)); /* Then check that the timeout values in net_if_addr are set correctly. * Start first with smaller timeout values. */ zassert_equal(ifaddr->lifetime.timer_timeout, timeout, "Timer timeout set wrong (%d vs %llu)", ifaddr->lifetime.timer_timeout, timeout); zassert_equal(ifaddr->lifetime.wrap_counter, 0, "Wrap counter wrong (%d)", ifaddr->lifetime.wrap_counter); /* Then update the lifetime and check that timeout values are correct */ vlifetime = FIFTY_DAYS; net_if_ipv6_addr_update_lifetime(ifaddr, vlifetime); zassert_equal(ifaddr->lifetime.wrap_counter, 2, "Wrap counter wrong (%d)", ifaddr->lifetime.wrap_counter); remaining = K_SECONDS((u64_t)vlifetime) - NET_TIMEOUT_MAX_VALUE * (u64_t)ifaddr->lifetime.wrap_counter; zassert_equal(remaining, ifaddr->lifetime.timer_timeout, "Remaining time wrong (%llu vs %d)", remaining, ifaddr->lifetime.timer_timeout); /* The address should not expire */ net_address_lifetime_timeout(); zassert_equal(ifaddr->lifetime.wrap_counter, 2, "Wrap counter wrong (%d)", ifaddr->lifetime.wrap_counter); ifaddr->lifetime.timer_timeout = K_MSEC(10); ifaddr->lifetime.timer_start = k_uptime_get_32() - K_MSEC(10); ifaddr->lifetime.wrap_counter = 0; net_address_lifetime_timeout(); /* The address should be expired now */ zassert_equal(ifaddr->lifetime.timer_timeout, 0, "Timer timeout set wrong (%llu vs %llu)", ifaddr->lifetime.timer_timeout, 0); zassert_equal(ifaddr->lifetime.wrap_counter, 0, "Wrap counter wrong (%d)", ifaddr->lifetime.wrap_counter); ret = net_if_ipv6_addr_rm(iface, &addr); zassert_true(ret, "Address with lifetime cannot be removed"); } /** * @brief IPv6 change ll address */ static void test_change_ll_addr(void) { static u8_t new_mac[] = { 00, 01, 02, 03, 04, 05 }; struct net_linkaddr_storage *ll; struct net_linkaddr *ll_iface; struct in6_addr dst; struct net_if *iface; struct net_nbr *nbr; u32_t flags; int ret; net_ipv6_addr_create(&dst, 0xff02, 0, 0, 0, 0, 0, 0, 1); iface = net_if_get_default(); flags = NET_ICMPV6_NA_FLAG_ROUTER | NET_ICMPV6_NA_FLAG_OVERRIDE; ret = net_ipv6_send_na(iface, &peer_addr, &dst, &peer_addr, flags); zassert_false(ret < 0, "Cannot send NA 1"); nbr = net_ipv6_nbr_lookup(iface, &peer_addr); ll = net_nbr_get_lladdr(nbr->idx); ll_iface = net_if_get_link_addr(iface); zassert_true(memcmp(ll->addr, ll_iface->addr, ll->len) != 0, "Wrong link address 1"); /* As the net_ipv6_send_na() uses interface link address to * greate tllao, change the interface ll address here. */ ll_iface->addr = new_mac; ret = net_ipv6_send_na(iface, &peer_addr, &dst, &peer_addr, flags); zassert_false(ret < 0, "Cannot send NA 2"); nbr = net_ipv6_nbr_lookup(iface, &peer_addr); ll = net_nbr_get_lladdr(nbr->idx); zassert_true(memcmp(ll->addr, ll_iface->addr, ll->len) != 0, "Wrong link address 2"); } static void test_dad_timeout(void) { #if defined(CONFIG_NET_IPV6_DAD) struct in6_addr addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x99, 0x1 } } }; struct in6_addr addr2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x99, 0x2 } } }; struct in6_addr addr3 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x99, 0x3 } } }; struct net_if *iface = net_if_get_default(); struct net_if_addr *ifaddr; dad_time[0] = dad_time[1] = dad_time[2] = 0U; ifaddr = net_if_ipv6_addr_add(iface, &addr1, NET_ADDR_AUTOCONF, 0xffff); zassert_not_null(ifaddr, "Address 1 cannot be added"); k_sleep(K_MSEC(10)); ifaddr = net_if_ipv6_addr_add(iface, &addr2, NET_ADDR_AUTOCONF, 0xffff); zassert_not_null(ifaddr, "Address 2 cannot be added"); k_sleep(K_MSEC(10)); ifaddr = net_if_ipv6_addr_add(iface, &addr3, NET_ADDR_AUTOCONF, 0xffff); zassert_not_null(ifaddr, "Address 3 cannot be added"); k_sleep(K_MSEC(200)); /* We should have received three DAD queries, make sure they are in * proper order. */ zassert_true(dad_time[0] < dad_time[1], "DAD timer 1+2 failure"); zassert_true(dad_time[1] < dad_time[2], "DAD timer 2+3 failure"); zassert_true((dad_time[2] - dad_time[0]) < 100, "DAD timers took too long time [%u] [%u] [%u]", dad_time[0], dad_time[1], dad_time[2]); #endif } #define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_udp_get_hdr(pkt, NULL))) static struct net_pkt *setup_ipv6_udp(struct net_if *iface, struct in6_addr *local_addr, struct in6_addr *remote_addr, u16_t local_port, u16_t remote_port) { static const char payload[] = "foobar"; struct net_pkt *pkt; pkt = net_pkt_alloc_with_buffer(iface, strlen(payload), AF_INET6, IPPROTO_UDP, K_FOREVER); if (!pkt) { return NULL; } if (net_ipv6_create(pkt, local_addr, remote_addr)) { printk("Cannot create IPv6 pkt %p", pkt); zassert_true(0, "exiting"); } if (net_udp_create(pkt, htons(local_port), htons(remote_port))) { printk("Cannot create IPv6 pkt %p", pkt); zassert_true(0, "exiting"); } if (net_pkt_write(pkt, (u8_t *)payload, strlen(payload))) { printk("Cannot write IPv6 ext header pkt %p", pkt); zassert_true(0, "exiting"); } net_pkt_cursor_init(pkt); net_ipv6_finalize(pkt, IPPROTO_UDP); net_pkt_cursor_init(pkt); return pkt; } static enum net_verdict recv_msg(struct in6_addr *src, struct in6_addr *dst) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = setup_ipv6_udp(iface, src, dst, 4242, 4321); /* We by-pass the normal packet receiving flow in this case in order * to simplify the testing. */ return net_ipv6_input(pkt, false); } static int send_msg(struct in6_addr *src, struct in6_addr *dst) { struct net_pkt *pkt; struct net_if *iface; iface = net_if_get_default(); pkt = setup_ipv6_udp(iface, src, dst, 4242, 4321); return net_send_data(pkt); } static void test_src_localaddr_recv(void) { struct in6_addr localaddr = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; verdict = recv_msg(&localaddr, &addr); zassert_equal(verdict, NET_DROP, "Local address packet was not dropped"); } static void test_dst_localaddr_recv(void) { struct in6_addr localaddr = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &localaddr); zassert_equal(verdict, NET_DROP, "Local address packet was not dropped"); } static void test_dst_iface_scope_mcast_recv(void) { struct in6_addr mcast_iface = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_iface); zassert_equal(verdict, NET_DROP, "Interface scope multicast packet was not dropped"); } static void test_dst_zero_scope_mcast_recv(void) { struct in6_addr mcast_zero = { { { 0xff, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_zero); zassert_equal(verdict, NET_DROP, "Zero scope multicast packet was not dropped"); } static void test_dst_site_scope_mcast_recv_drop(void) { struct in6_addr mcast_site = { { { 0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_site); zassert_equal(verdict, NET_DROP, "Site scope multicast packet was not dropped"); } static void net_ctx_create(struct net_context **ctx) { int ret; ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, ctx); zassert_equal(ret, 0, "Context create IPv6 UDP test failed"); } static void net_ctx_bind_mcast(struct net_context *ctx, struct in6_addr *maddr) { struct sockaddr_in6 addr = { .sin6_family = AF_INET6, .sin6_port = htons(4321), .sin6_addr = { { { 0 } } }, }; int ret; net_ipaddr_copy(&addr.sin6_addr, maddr); ret = net_context_bind(ctx, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)); zassert_equal(ret, 0, "Context bind test failed (%d)", ret); } static void net_ctx_listen(struct net_context *ctx) { zassert_true(net_context_listen(ctx, 0), "Context listen IPv6 UDP test failed"); } static void recv_cb(struct net_context *context, struct net_pkt *pkt, union net_ip_header *ip_hdr, union net_proto_header *proto_hdr, int status, void *user_data) { ARG_UNUSED(context); ARG_UNUSED(pkt); ARG_UNUSED(ip_hdr); ARG_UNUSED(proto_hdr); ARG_UNUSED(status); ARG_UNUSED(user_data); recv_cb_called = true; k_sem_give(&wait_data); } static void net_ctx_recv(struct net_context *ctx) { int ret; ret = net_context_recv(ctx, recv_cb, 0, NULL); zassert_equal(ret, 0, "Context recv IPv6 UDP failed"); } static void join_group(struct in6_addr *mcast_addr) { int ret; ret = net_ipv6_mld_join(net_if_get_default(), mcast_addr); zassert_equal(ret, 0, "Cannot join IPv6 multicast group"); } static void test_dst_site_scope_mcast_recv_ok(void) { struct in6_addr mcast_all_dhcp = { { { 0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0x03 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; struct net_context *ctx; /* The packet will be dropped unless we have a listener and joined the * group. */ join_group(&mcast_all_dhcp); net_ctx_create(&ctx); net_ctx_bind_mcast(ctx, &mcast_all_dhcp); net_ctx_listen(ctx); net_ctx_recv(ctx); verdict = recv_msg(&addr, &mcast_all_dhcp); zassert_equal(verdict, NET_OK, "All DHCP site scope multicast packet was dropped (%d)", verdict); net_context_put(ctx); } static void test_dst_org_scope_mcast_recv(void) { struct in6_addr mcast_org = { { { 0xff, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_org); zassert_equal(verdict, NET_DROP, "Organisation scope multicast packet was not dropped"); } static void test_dst_iface_scope_mcast_send(void) { struct in6_addr mcast_iface = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct net_if_mcast_addr *maddr; struct net_context *ctx; int ret; /* Note that there is no need to join the multicast group as the * interface local scope multicast address packet will not leave the * device. But we will still need to add proper multicast address to * the network interface. */ maddr = net_if_ipv6_maddr_add(net_if_get_default(), &mcast_iface); zassert_not_null(maddr, "Cannot add multicast address to interface"); net_ctx_create(&ctx); net_ctx_bind_mcast(ctx, &mcast_iface); net_ctx_listen(ctx); net_ctx_recv(ctx); ret = send_msg(&addr, &mcast_iface); zassert_equal(ret, 0, "Interface local scope multicast packet was dropped (%d)", ret); k_sem_take(&wait_data, K_MSEC(WAIT_TIME)); zassert_true(recv_cb_called, "No data received on time, " "IPv6 recv test failed"); recv_cb_called = false; net_context_put(ctx); } void test_main(void) { ztest_test_suite(test_ipv6_fn, ztest_unit_test(test_init), ztest_unit_test(test_cmp_prefix), ztest_unit_test(test_nbr_lookup_fail), ztest_unit_test(test_add_neighbor), ztest_unit_test(test_add_max_neighbors), ztest_unit_test(test_nbr_lookup_ok), ztest_unit_test(test_send_ns_extra_options), ztest_unit_test(test_send_ns_no_options), ztest_unit_test(test_rs_message), ztest_unit_test(test_ra_message), ztest_unit_test(test_hbho_message), ztest_unit_test(test_hbho_message_1), ztest_unit_test(test_hbho_message_2), ztest_unit_test(test_hbho_message_3), ztest_unit_test(test_address_lifetime), ztest_unit_test(test_change_ll_addr), ztest_unit_test(test_prefix_timeout), ztest_unit_test(test_prefix_timeout_long), ztest_unit_test(test_dad_timeout), ztest_unit_test(test_src_localaddr_recv), ztest_unit_test(test_dst_localaddr_recv), ztest_unit_test(test_dst_iface_scope_mcast_recv), ztest_unit_test(test_dst_iface_scope_mcast_send), ztest_unit_test(test_dst_zero_scope_mcast_recv), ztest_unit_test(test_dst_site_scope_mcast_recv_drop), ztest_unit_test(test_dst_site_scope_mcast_recv_ok), ztest_unit_test(test_dst_org_scope_mcast_recv) ); ztest_run_test_suite(test_ipv6_fn); }