tests: net: ipv6: Add more test cases involving iface state changes
Add tests verifying valid IPv6 ND behaviors on interface state changes, specifically: * Verify RS is sent, and upon RA reception prefix and autoconf address added accordingly. * DAD is triggered for autoconf, static and LL IPv6 addresses. * IPv6 address is not used upon DAD conflict. * IPv6 neighbor discovery works as expected. * Multicast transmission/reception is functional after interface state changes. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
b9f7ffe79d
commit
9c8ed2dca7
1 changed files with 505 additions and 15 deletions
|
@ -43,13 +43,28 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL);
|
|||
#endif
|
||||
|
||||
#define TEST_NET_IF net_if_lookup_by_dev(DEVICE_GET(eth_ipv6_net))
|
||||
#define TEST_MSG_SIZE 128
|
||||
|
||||
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 multicast_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
|
||||
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
|
||||
static struct in6_addr all_nodes_mcast = { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
|
||||
|
||||
/* Below should match prefix/addr distributed in RA message. */
|
||||
static struct in6_addr test_router_addr = { { {
|
||||
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x2, 0x60,
|
||||
0x97, 0xff, 0xfe, 0x07, 0x69, 0xea
|
||||
} } };
|
||||
static struct in6_addr test_ra_prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0 } } };
|
||||
static struct in6_addr test_ra_autoconf_addr = { { {
|
||||
0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01,
|
||||
0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x53, 0x00
|
||||
} } };
|
||||
|
||||
/* ICMPv6 NS frame (74 bytes) */
|
||||
static const unsigned char icmpv6_ns_invalid[] = {
|
||||
|
@ -141,12 +156,22 @@ static const unsigned char ipv6_hbho[] = {
|
|||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* ...... */
|
||||
};
|
||||
|
||||
static int send_msg(struct in6_addr *src, struct in6_addr *dst);
|
||||
|
||||
typedef void (*ns_callback)(struct net_pkt *pkt, void *user_data);
|
||||
|
||||
struct test_ns_handler {
|
||||
ns_callback fn;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static bool expecting_ra;
|
||||
static uint32_t dad_time[3];
|
||||
static bool test_failed;
|
||||
static struct k_sem wait_data;
|
||||
static bool recv_cb_called;
|
||||
struct net_if_addr *ifaddr_record;
|
||||
static struct test_ns_handler *ns_handler;
|
||||
|
||||
#define WAIT_TIME 250
|
||||
#define WAIT_TIME_LONG MSEC_PER_SEC
|
||||
|
@ -221,6 +246,55 @@ static void prepare_ra_message(struct net_pkt *pkt)
|
|||
net_pkt_cursor_init(pkt);
|
||||
}
|
||||
|
||||
static void inject_na_message(struct net_if *iface, struct in6_addr *src,
|
||||
struct in6_addr *dst, struct in6_addr *target,
|
||||
uint8_t flags)
|
||||
{
|
||||
struct net_eth_hdr hdr;
|
||||
struct net_pkt *pkt;
|
||||
uint8_t na_flags[] = { flags, 0, 0, 0 };
|
||||
uint8_t na_tlla_opt[] = { 0x02, 0x01, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||
|
||||
pkt = net_pkt_alloc_with_buffer(iface, TEST_MSG_SIZE, AF_INET6,
|
||||
IPPROTO_ICMPV6, K_NO_WAIT);
|
||||
zassert_not_null(pkt, "Failed to allocate packet");
|
||||
|
||||
net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_ND_HOP_LIMIT);
|
||||
|
||||
hdr.type = htons(NET_ETH_PTYPE_IPV6);
|
||||
memset(&hdr.src, 0xaa, sizeof(struct net_eth_addr));
|
||||
memcpy(&hdr.dst, net_pkt_iface(pkt)->if_dev->link_addr.addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
|
||||
/* Reserve space for the L2 header. */
|
||||
net_buf_reserve(pkt->frags, sizeof(struct net_eth_hdr));
|
||||
net_pkt_cursor_init(pkt);
|
||||
net_pkt_set_overwrite(pkt, false);
|
||||
|
||||
zassert_ok(net_ipv6_create(pkt, src, dst));
|
||||
zassert_ok(net_icmpv6_create(pkt, NET_ICMPV6_NA, 0));
|
||||
zassert_ok(net_pkt_write(pkt, na_flags, sizeof(na_flags)));
|
||||
zassert_ok(net_pkt_write(pkt, target, sizeof(struct in6_addr)));
|
||||
zassert_ok(net_pkt_write(pkt, na_tlla_opt, sizeof(na_tlla_opt)));
|
||||
|
||||
net_pkt_cursor_init(pkt);
|
||||
net_ipv6_finalize(pkt, IPPROTO_ICMPV6);
|
||||
|
||||
/* Fill L2 header. */
|
||||
net_buf_push_mem(pkt->frags, &hdr, sizeof(struct net_eth_hdr));
|
||||
|
||||
net_pkt_cursor_init(pkt);
|
||||
zassert_ok((net_recv_data(iface, pkt)), "Data receive for NA failed.");
|
||||
}
|
||||
|
||||
static void skip_headers(struct net_pkt *pkt)
|
||||
{
|
||||
net_pkt_cursor_init(pkt);
|
||||
net_pkt_skip(pkt, sizeof(struct net_eth_hdr));
|
||||
net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt));
|
||||
net_pkt_skip(pkt, sizeof(struct net_icmp_hdr));
|
||||
}
|
||||
|
||||
static struct net_icmp_hdr *get_icmp_hdr(struct net_pkt *pkt)
|
||||
{
|
||||
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, struct net_icmp_hdr);
|
||||
|
@ -272,6 +346,10 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
|
|||
}
|
||||
|
||||
if (icmp->type == NET_ICMPV6_NS) {
|
||||
if (ns_handler != NULL) {
|
||||
ns_handler->fn(pkt, ns_handler->user_data);
|
||||
}
|
||||
|
||||
if (dad_time[0] == 0U) {
|
||||
dad_time[0] = k_uptime_get_32();
|
||||
} else if (dad_time[1] == 0U) {
|
||||
|
@ -315,6 +393,30 @@ NET_DEVICE_INIT(eth_ipv6_net, "eth_ipv6_net",
|
|||
&net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE,
|
||||
NET_ETH_MTU);
|
||||
|
||||
static void test_iface_down_up(void)
|
||||
{
|
||||
zassert_ok(net_if_down(TEST_NET_IF), "Failed to bring iface down");
|
||||
k_msleep(10);
|
||||
zassert_ok(net_if_up(TEST_NET_IF), "Failed to bring iface up");
|
||||
}
|
||||
|
||||
static void test_iface_down_up_delayed_carrier(void)
|
||||
{
|
||||
zassert_ok(net_if_down(TEST_NET_IF), "Failed to bring iface down");
|
||||
k_msleep(10);
|
||||
net_if_carrier_off(TEST_NET_IF);
|
||||
zassert_ok(net_if_up(TEST_NET_IF), "Failed to bring iface up");
|
||||
k_msleep(10);
|
||||
net_if_carrier_on(TEST_NET_IF);
|
||||
}
|
||||
|
||||
static void test_iface_carrier_off_on(void)
|
||||
{
|
||||
net_if_carrier_off(TEST_NET_IF);
|
||||
k_msleep(10);
|
||||
net_if_carrier_on(TEST_NET_IF);
|
||||
}
|
||||
|
||||
/* dummy interface for multi-interface tests */
|
||||
static int dummy_send(const struct device *dev, struct net_pkt *pkt)
|
||||
{
|
||||
|
@ -520,9 +622,20 @@ static void *ipv6_setup(void)
|
|||
nbr_lookup_ok();
|
||||
k_sleep(K_MSEC(50));
|
||||
|
||||
/* Last, randomized MAC byte needs to be copied to the expected autoconf
|
||||
* address.
|
||||
*/
|
||||
test_ra_autoconf_addr.s6_addr[15] = net_if_get_link_addr(iface)->addr[5];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ipv6_before(void *fixture)
|
||||
{
|
||||
ARG_UNUSED(fixture);
|
||||
|
||||
ns_handler = NULL;
|
||||
}
|
||||
|
||||
static void ipv6_teardown(void *dummy)
|
||||
{
|
||||
|
@ -629,6 +742,73 @@ ZTEST(net_ipv6, test_send_ns_no_options)
|
|||
"Data receive for invalid NS failed.");
|
||||
}
|
||||
|
||||
struct test_nd_context {
|
||||
struct k_sem wait_ns;
|
||||
struct in6_addr *exp_ns_addr;
|
||||
bool reply;
|
||||
};
|
||||
|
||||
static void expect_nd_ns(struct net_pkt *pkt, void *user_data)
|
||||
{
|
||||
uint32_t res_bytes;
|
||||
struct in6_addr target;
|
||||
struct test_nd_context *ctx = user_data;
|
||||
|
||||
skip_headers(pkt);
|
||||
|
||||
zassert_ok(net_pkt_read_be32(pkt, &res_bytes), "Failed to read reserved bytes");
|
||||
zassert_equal(0, res_bytes, "Reserved bytes must be zeroed");
|
||||
zassert_ok(net_pkt_read(pkt, &target, sizeof(struct in6_addr)),
|
||||
"Failed to read target address");
|
||||
|
||||
if (net_ipv6_addr_cmp(ctx->exp_ns_addr, &target)) {
|
||||
if (ctx->reply) {
|
||||
inject_na_message(net_pkt_iface(pkt), &target, &my_addr,
|
||||
&target, NET_ICMPV6_NA_FLAG_SOLICITED);
|
||||
}
|
||||
|
||||
k_sem_give(&ctx->wait_ns);
|
||||
}
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_send_neighbor_discovery)
|
||||
{
|
||||
struct test_nd_context ctx = {
|
||||
.exp_ns_addr = &test_router_addr,
|
||||
.reply = true
|
||||
};
|
||||
struct test_ns_handler handler = {
|
||||
.fn = expect_nd_ns,
|
||||
.user_data = &ctx
|
||||
};
|
||||
enum net_verdict verdict;
|
||||
struct net_nbr *nbr;
|
||||
|
||||
k_sem_init(&ctx.wait_ns, 0, 1);
|
||||
ns_handler = &handler;
|
||||
|
||||
(void)net_ipv6_nbr_rm(TEST_NET_IF, &test_router_addr);
|
||||
|
||||
verdict = send_msg(&my_addr, &test_router_addr);
|
||||
zassert_equal(verdict, NET_OK, "Packet was dropped (%d)", verdict);
|
||||
zassert_ok(k_sem_take(&ctx.wait_ns, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for expected NS");
|
||||
|
||||
k_sleep(K_MSEC(10));
|
||||
|
||||
/* Neighbor should be here now. */
|
||||
nbr = net_ipv6_nbr_lookup(TEST_NET_IF, &test_router_addr);
|
||||
zassert_not_null(nbr, "Neighbor not found.");
|
||||
zassert_equal(net_ipv6_nbr_data(nbr)->state, NET_IPV6_NBR_STATE_REACHABLE,
|
||||
"Neighbor should be reachable at this point.");
|
||||
|
||||
/* Second attempt (neighbor valid) should give no NS. */
|
||||
verdict = send_msg(&my_addr, &test_router_addr);
|
||||
zassert_equal(verdict, NET_OK, "Packet was dropped (%d)", verdict);
|
||||
zassert_equal(k_sem_take(&ctx.wait_ns, K_MSEC(10)), -EAGAIN,
|
||||
"Should not get NS");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IPv6 prefix timeout
|
||||
*/
|
||||
|
@ -701,10 +881,6 @@ static void rs_message(void)
|
|||
|
||||
static void 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 } } };
|
||||
struct in6_addr route_prefix = { { { 0x20, 0x01, 0x0d, 0xb0, 0x0f, 0xff } } };
|
||||
struct sockaddr_in6 dns_addr = {
|
||||
.sin6_family = AF_INET6,
|
||||
|
@ -715,6 +891,7 @@ static void ra_message(void)
|
|||
struct net_route_entry *route;
|
||||
struct dns_resolve_context *ctx;
|
||||
struct sockaddr_in6 *dns_server;
|
||||
struct net_if_addr *ifaddr;
|
||||
|
||||
/* We received RA message earlier, make sure that the information
|
||||
* in that message is placed to proper prefix and lookup info.
|
||||
|
@ -722,13 +899,21 @@ static void ra_message(void)
|
|||
|
||||
expecting_ra = false;
|
||||
|
||||
zassert_false(!net_if_ipv6_prefix_lookup(TEST_NET_IF, &prefix, 32),
|
||||
zassert_false(!net_if_ipv6_prefix_lookup(TEST_NET_IF, &test_ra_prefix, 64),
|
||||
"Prefix %s should be here\n",
|
||||
net_sprint_ipv6_addr(&prefix));
|
||||
net_sprint_ipv6_addr(&test_ra_prefix));
|
||||
|
||||
zassert_false(!net_if_ipv6_router_lookup(TEST_NET_IF, &addr),
|
||||
zassert_false(!net_if_ipv6_router_lookup(TEST_NET_IF, &test_router_addr),
|
||||
"Router %s should be here\n",
|
||||
net_sprint_ipv6_addr(&addr));
|
||||
net_sprint_ipv6_addr(&test_router_addr));
|
||||
|
||||
/* Check if autoconf address was added correctly. */
|
||||
ifaddr = net_if_ipv6_addr_lookup_by_iface(TEST_NET_IF,
|
||||
&test_ra_autoconf_addr);
|
||||
zassert_not_null(ifaddr, "Autoconf address %s missing",
|
||||
net_sprint_ipv6_addr(&test_ra_autoconf_addr));
|
||||
zassert_equal(ifaddr->addr_type, NET_ADDR_AUTOCONF,
|
||||
"Address type should be autoconf");
|
||||
|
||||
/* Check if route was added correctly. */
|
||||
route = net_route_lookup(TEST_NET_IF, &route_prefix);
|
||||
|
@ -759,6 +944,86 @@ ZTEST(net_ipv6, test_rs_ra_message)
|
|||
ra_message();
|
||||
}
|
||||
|
||||
struct test_dad_context {
|
||||
struct k_sem wait_dad;
|
||||
struct in6_addr *exp_dad_addr;
|
||||
bool reply;
|
||||
};
|
||||
|
||||
static void expect_dad_ns(struct net_pkt *pkt, void *user_data)
|
||||
{
|
||||
uint32_t res_bytes;
|
||||
struct in6_addr target;
|
||||
struct test_dad_context *ctx = user_data;
|
||||
|
||||
skip_headers(pkt);
|
||||
|
||||
zassert_ok(net_pkt_read_be32(pkt, &res_bytes), "Failed to read reserved bytes");
|
||||
zassert_equal(0, res_bytes, "Reserved bytes must be zeroed");
|
||||
zassert_ok(net_pkt_read(pkt, &target, sizeof(struct in6_addr)),
|
||||
"Failed to read target address");
|
||||
|
||||
if (net_ipv6_addr_cmp(ctx->exp_dad_addr, &target)) {
|
||||
if (ctx->reply) {
|
||||
inject_na_message(net_pkt_iface(pkt), &target,
|
||||
&all_nodes_mcast, &target, 0);
|
||||
}
|
||||
|
||||
k_sem_give(&ctx->wait_dad);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that RS is sent after interface state change, RA processed,
|
||||
* prefix added and autoconf address configured.
|
||||
*/
|
||||
static void verify_rs_on_iface_event(void (*action)(void))
|
||||
{
|
||||
struct net_if_router *router;
|
||||
struct test_dad_context ctx = {
|
||||
.exp_dad_addr = &test_ra_autoconf_addr
|
||||
};
|
||||
struct test_ns_handler handler = {
|
||||
.fn = expect_dad_ns,
|
||||
.user_data = &ctx
|
||||
};
|
||||
|
||||
(void)net_if_ipv6_prefix_rm(TEST_NET_IF, &test_ra_prefix, 64);
|
||||
|
||||
router = net_if_ipv6_router_lookup(TEST_NET_IF, &test_router_addr);
|
||||
if (router) {
|
||||
(void)net_if_ipv6_router_rm(router);
|
||||
}
|
||||
|
||||
k_sem_init(&ctx.wait_dad, 0, 1);
|
||||
|
||||
ns_handler = &handler;
|
||||
expecting_ra = true;
|
||||
|
||||
action();
|
||||
|
||||
k_sleep(K_MSEC(10));
|
||||
|
||||
ra_message();
|
||||
|
||||
zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for DAD NS");
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_rs_after_iface_up)
|
||||
{
|
||||
verify_rs_on_iface_event(test_iface_down_up);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_rs_after_iface_up_carrier_delayed)
|
||||
{
|
||||
verify_rs_on_iface_event(test_iface_down_up_delayed_carrier);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_rs_after_carrier_toggle)
|
||||
{
|
||||
verify_rs_on_iface_event(test_iface_carrier_off_on);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IPv6 parse Hop-By-Hop Option
|
||||
*/
|
||||
|
@ -1136,20 +1401,17 @@ ZTEST(net_ipv6, test_change_ll_addr)
|
|||
static uint8_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;
|
||||
uint32_t flags;
|
||||
int ret;
|
||||
|
||||
net_ipv6_addr_create(&dst, 0xff02, 0, 0, 0, 0, 0, 0, 1);
|
||||
|
||||
iface = TEST_NET_IF;
|
||||
|
||||
flags = NET_ICMPV6_NA_FLAG_ROUTER |
|
||||
NET_ICMPV6_NA_FLAG_OVERRIDE;
|
||||
|
||||
ret = net_ipv6_send_na(iface, &peer_addr, &dst,
|
||||
ret = net_ipv6_send_na(iface, &peer_addr, &all_nodes_mcast,
|
||||
&peer_addr, flags);
|
||||
zassert_false(ret < 0, "Cannot send NA 1");
|
||||
|
||||
|
@ -1168,7 +1430,7 @@ ZTEST(net_ipv6, test_change_ll_addr)
|
|||
*/
|
||||
ll_iface->addr = new_mac;
|
||||
|
||||
ret = net_ipv6_send_na(iface, &peer_addr, &dst,
|
||||
ret = net_ipv6_send_na(iface, &peer_addr, &all_nodes_mcast,
|
||||
&peer_addr, flags);
|
||||
zassert_false(ret < 0, "Cannot send NA 2");
|
||||
|
||||
|
@ -1223,6 +1485,118 @@ ZTEST(net_ipv6, test_dad_timeout)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Verify that DAD NS is sent after interface state change, for static address
|
||||
* (added to the interface in ipv6_setup()).
|
||||
*/
|
||||
static void verify_dad_on_static_addr_on_iface_event(void (*action)(void))
|
||||
{
|
||||
struct test_dad_context ctx = {
|
||||
.exp_dad_addr = &my_addr
|
||||
};
|
||||
struct test_ns_handler handler = {
|
||||
.fn = expect_dad_ns,
|
||||
.user_data = &ctx
|
||||
};
|
||||
|
||||
k_sem_init(&ctx.wait_dad, 0, 1);
|
||||
|
||||
ns_handler = &handler;
|
||||
|
||||
action();
|
||||
|
||||
zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for DAD NS");
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_dad_on_static_addr_after_iface_up)
|
||||
{
|
||||
verify_dad_on_static_addr_on_iface_event(test_iface_down_up);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_dad_on_static_addr_after_iface_up_carrier_delayed)
|
||||
{
|
||||
verify_dad_on_static_addr_on_iface_event(test_iface_down_up_delayed_carrier);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_dad_on_static_addr_after_carrier_toggle)
|
||||
{
|
||||
verify_dad_on_static_addr_on_iface_event(test_iface_carrier_off_on);
|
||||
}
|
||||
|
||||
/* Verify that DAD NS is sent after interface state change, for link-local
|
||||
* address.
|
||||
*/
|
||||
static void verify_dad_on_ll_addr_on_iface_event(void (*action)(void))
|
||||
{
|
||||
struct in6_addr link_local_addr;
|
||||
struct test_dad_context ctx = {
|
||||
.exp_dad_addr = &link_local_addr
|
||||
};
|
||||
struct test_ns_handler handler = {
|
||||
.fn = expect_dad_ns,
|
||||
.user_data = &ctx
|
||||
};
|
||||
|
||||
net_ipv6_addr_create_iid(&link_local_addr,
|
||||
net_if_get_link_addr(TEST_NET_IF));
|
||||
k_sem_init(&ctx.wait_dad, 0, 1);
|
||||
|
||||
ns_handler = &handler;
|
||||
|
||||
action();
|
||||
|
||||
zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for DAD NS");
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_dad_on_ll_addr_after_iface_up)
|
||||
{
|
||||
verify_dad_on_ll_addr_on_iface_event(test_iface_down_up);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_dad_on_ll_addr_after_iface_up_carrier_delayed)
|
||||
{
|
||||
verify_dad_on_ll_addr_on_iface_event(test_iface_down_up_delayed_carrier);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_dad_on_ll_addr_after_carrier_toggle)
|
||||
{
|
||||
verify_dad_on_ll_addr_on_iface_event(test_iface_carrier_off_on);
|
||||
}
|
||||
|
||||
/* Verify that in case of DAD conflict, address is not used on the interface. */
|
||||
ZTEST(net_ipv6, test_dad_conflict)
|
||||
{
|
||||
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0x99, 0x4 } } };
|
||||
struct test_dad_context ctx = {
|
||||
.exp_dad_addr = &addr,
|
||||
.reply = true
|
||||
};
|
||||
struct test_ns_handler handler = {
|
||||
.fn = expect_dad_ns,
|
||||
.user_data = &ctx
|
||||
};
|
||||
struct net_if_addr *ifaddr;
|
||||
|
||||
k_sem_init(&ctx.wait_dad, 0, 1);
|
||||
|
||||
ns_handler = &handler;
|
||||
|
||||
ifaddr = net_if_ipv6_addr_add(TEST_NET_IF, &addr, NET_ADDR_AUTOCONF, 0xffff);
|
||||
zassert_not_null(ifaddr, "Address cannot be added");
|
||||
|
||||
zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for DAD NS");
|
||||
|
||||
/* Small delay to let the stack process NA response. */
|
||||
k_sleep(K_MSEC(100));
|
||||
|
||||
ifaddr = net_if_ipv6_addr_lookup_by_iface(TEST_NET_IF, &addr);
|
||||
zassert_is_null(ifaddr, "Address should not be present on the interface");
|
||||
}
|
||||
|
||||
#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,
|
||||
|
@ -1632,6 +2006,122 @@ ZTEST(net_ipv6, test_dst_is_other_iface_mcast_recv)
|
|||
net_context_put(ctx);
|
||||
}
|
||||
|
||||
/* Verify that after interface state change it's possible to transmit mcast
|
||||
* packets to theoretically joined groups.
|
||||
*/
|
||||
static void verify_iface_mcast_send_on_iface_event(void (*action)(void))
|
||||
{
|
||||
enum net_verdict verdict;
|
||||
struct net_context *ctx;
|
||||
struct in6_addr solicited_node_mcast;
|
||||
|
||||
action();
|
||||
|
||||
/* All nodes */
|
||||
net_ctx_create(&ctx);
|
||||
net_ctx_bind_mcast(ctx, &all_nodes_mcast);
|
||||
net_ctx_listen(ctx);
|
||||
net_ctx_recv(ctx);
|
||||
|
||||
verdict = send_msg(&my_addr, &all_nodes_mcast);
|
||||
zassert_equal(verdict, NET_OK,
|
||||
"All nodes multicast packet was dropped (%d)",
|
||||
verdict);
|
||||
|
||||
net_context_put(ctx);
|
||||
|
||||
/* Solicited node */
|
||||
net_ipv6_addr_create_solicited_node(&my_addr, &solicited_node_mcast);
|
||||
|
||||
net_ctx_create(&ctx);
|
||||
net_ctx_bind_mcast(ctx, &solicited_node_mcast);
|
||||
net_ctx_listen(ctx);
|
||||
net_ctx_recv(ctx);
|
||||
|
||||
verdict = send_msg(&my_addr, &solicited_node_mcast);
|
||||
zassert_equal(verdict, NET_OK,
|
||||
"Solicited node multicast packet was dropped (%d)",
|
||||
verdict);
|
||||
|
||||
net_context_put(ctx);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_iface_mcast_send_after_iface_up)
|
||||
{
|
||||
verify_iface_mcast_send_on_iface_event(test_iface_down_up);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_iface_mcast_send_after_iface_up_carrier_delayed)
|
||||
{
|
||||
verify_iface_mcast_send_on_iface_event(test_iface_down_up_delayed_carrier);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_iface_mcast_send_after_carrier_toggle)
|
||||
{
|
||||
verify_iface_mcast_send_on_iface_event(test_iface_carrier_off_on);
|
||||
}
|
||||
|
||||
/* Verify that after interface state change it's possible to receive mcast
|
||||
* packets on theoretically joined groups.
|
||||
*/
|
||||
static void verify_iface_mcast_recv_on_iface_event(void (*action)(void))
|
||||
{
|
||||
enum net_verdict verdict;
|
||||
struct net_context *ctx;
|
||||
struct in6_addr solicited_node_mcast;
|
||||
|
||||
action();
|
||||
|
||||
k_sem_reset(&wait_data);
|
||||
|
||||
/* All nodes */
|
||||
net_ctx_create(&ctx);
|
||||
net_ctx_bind_mcast(ctx, &all_nodes_mcast);
|
||||
net_ctx_listen(ctx);
|
||||
net_ctx_recv(ctx);
|
||||
|
||||
verdict = recv_msg(&peer_addr, &all_nodes_mcast);
|
||||
zassert_equal(verdict, NET_OK,
|
||||
"All nodes multicast packet was dropped (%d)",
|
||||
verdict);
|
||||
zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for mcast packet");
|
||||
|
||||
net_context_put(ctx);
|
||||
|
||||
/* Solicited node */
|
||||
net_ipv6_addr_create_solicited_node(&my_addr, &solicited_node_mcast);
|
||||
|
||||
net_ctx_create(&ctx);
|
||||
net_ctx_bind_mcast(ctx, &solicited_node_mcast);
|
||||
net_ctx_listen(ctx);
|
||||
net_ctx_recv(ctx);
|
||||
|
||||
verdict = recv_msg(&peer_addr, &solicited_node_mcast);
|
||||
zassert_equal(verdict, NET_OK,
|
||||
"Solicited node multicast packet was dropped (%d)",
|
||||
verdict);
|
||||
zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)),
|
||||
"Timeout while waiting for mcast packet");
|
||||
|
||||
net_context_put(ctx);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_iface_mcast_recv_after_iface_up)
|
||||
{
|
||||
verify_iface_mcast_recv_on_iface_event(test_iface_down_up);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_iface_mcast_recv_after_iface_up_carrier_delayed)
|
||||
{
|
||||
verify_iface_mcast_recv_on_iface_event(test_iface_down_up_delayed_carrier);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_iface_mcast_recv_after_carrier_toggle)
|
||||
{
|
||||
verify_iface_mcast_recv_on_iface_event(test_iface_carrier_off_on);
|
||||
}
|
||||
|
||||
ZTEST(net_ipv6, test_no_nd_flag)
|
||||
{
|
||||
bool ret;
|
||||
|
@ -1891,4 +2381,4 @@ ZTEST(net_ipv6, test_z_privacy_extension_03_get_addr)
|
|||
}
|
||||
}
|
||||
|
||||
ZTEST_SUITE(net_ipv6, NULL, ipv6_setup, NULL, NULL, ipv6_teardown);
|
||||
ZTEST_SUITE(net_ipv6, NULL, ipv6_setup, ipv6_before, NULL, ipv6_teardown);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue