/* main.c - Application main entry point */ /* * Copyright (c) 2020 Lemonbeat GmbH * * SPDX-License-Identifier: Apache-2.0 */ #include LOG_MODULE_REGISTER(net_test, CONFIG_NET_ROUTE_LOG_LEVEL); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NET_LOG_ENABLED 1 #include "net_private.h" #include "icmpv6.h" #include "ipv6.h" #include #include "udp_internal.h" #include "nbr.h" #include "route.h" #if defined(CONFIG_NET_ROUTE_LOG_LEVEL_DBG) #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) #else #define DBG(fmt, ...) #endif static struct in6_addr iface_1_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct in6_addr iface_2_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x0e, 0x0e, 0x3 } } }; static struct in6_addr iface_3_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0x0e, 0x0e, 0x0e, 0x4 } } }; /* Extra address is assigned to ll_addr */ static struct in6_addr ll_addr_1 = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02, 0x04 } } }; static struct in6_addr ll_addr_2 = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0xf2, 0xaa, 0x29, 0x05, 0x06 } } }; static struct in6_addr ll_addr_3 = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0xf2, 0xaa, 0x29, 0x07, 0x08 } } }; static struct in6_addr in6addr_mcast = { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct net_if *iface_1; static struct net_if *iface_2; static struct net_if *iface_3; #define WAIT_TIME K_MSEC(50) struct net_route_mcast_iface_cfg { uint8_t mac_addr[sizeof(struct net_eth_addr)]; struct net_linkaddr ll_addr; }; #define MAX_MCAST_ROUTES CONFIG_NET_MAX_MCAST_ROUTES static struct net_route_entry_mcast *test_mcast_routes[MAX_MCAST_ROUTES]; static struct in6_addr mcast_prefix_iflocal = { { { 0xFF, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; static struct in6_addr mcast_prefix_llocal = { { { 0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; static struct in6_addr mcast_prefix_admin = { { { 0xFF, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; static struct in6_addr mcast_prefix_site_local = { { { 0xFF, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; static struct in6_addr mcast_prefix_orga = { { { 0xFF, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; static struct in6_addr mcast_prefix_global = { { { 0xFF, 0x0E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; /* * full network prefix based address, * see RFC-3306 for details * FF3F:40:FD01:101:: \128 * network prefix FD01:101::\64 */ static struct in6_addr mcast_prefix_nw_based = { { { 0xFF, 0x3F, 0, 0x40, 0xFD, 0x01, 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0, 0 } } }; static uint8_t forwarding_counter; static bool iface_1_forwarded; static bool iface_2_forwarded; static bool iface_3_forwarded; struct net_route_mcast_scenario_cfg { struct in6_addr src; struct in6_addr mcast; bool is_active; }; static struct net_route_mcast_scenario_cfg active_scenario; int net_route_mcast_dev_init(const struct device *dev) { return 0; } static uint8_t *net_route_mcast_get_mac(const struct device *dev) { struct net_route_mcast_iface_cfg *cfg = dev->data; if (cfg->mac_addr[2] == 0x00) { /* 00-00-5E-00-53-xx Documentation RFC 7042 */ cfg->mac_addr[0] = 0x00; cfg->mac_addr[1] = 0x00; cfg->mac_addr[2] = 0x5E; cfg->mac_addr[3] = 0x00; cfg->mac_addr[4] = 0x53; cfg->mac_addr[5] = sys_rand32_get(); } cfg->ll_addr.addr = cfg->mac_addr; cfg->ll_addr.len = 6U; return cfg->mac_addr; } static void net_route_mcast_add_addresses(struct net_if *iface, struct in6_addr *ipv6, struct in6_addr *ll_addr) { struct net_if_mcast_addr *maddr; struct net_if_addr *ifaddr; uint8_t *mac = net_route_mcast_get_mac(net_if_get_device(iface)); net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr), NET_LINK_ETHERNET); ifaddr = net_if_ipv6_addr_add(iface, ipv6, NET_ADDR_MANUAL, 0); zassert_not_null(ifaddr, "Cannot add global IPv6 address"); ifaddr->addr_state = NET_ADDR_PREFERRED; ifaddr = net_if_ipv6_addr_add(iface, ll_addr, NET_ADDR_MANUAL, 0); zassert_not_null(ifaddr, "Cannot add ll IPv6 address"); ifaddr->addr_state = NET_ADDR_PREFERRED; maddr = net_if_ipv6_maddr_add(iface, &in6addr_mcast); zassert_not_null(maddr, "Cannot add multicast IPv6 address"); } static void net_route_mcast_iface_init1(struct net_if *iface) { iface_1 = iface; net_route_mcast_add_addresses(iface, &iface_1_addr, &ll_addr_1); } static void net_route_mcast_iface_init2(struct net_if *iface) { iface_2 = iface; net_route_mcast_add_addresses(iface, &iface_2_addr, &ll_addr_2); } static void net_route_mcast_iface_init3(struct net_if *iface) { iface_3 = iface; net_route_mcast_add_addresses(iface, &iface_3_addr, &ll_addr_3); } static bool check_packet_addresses(struct net_pkt *pkt) { struct net_ipv6_hdr *ipv6_hdr = NET_IPV6_HDR(pkt); if ((memcmp(&active_scenario.src, &ipv6_hdr->src, sizeof(struct in6_addr)) != 0) || (memcmp(&active_scenario.mcast, &ipv6_hdr->dst, sizeof(struct in6_addr)) != 0)) { return false; } return true; } static int iface_send(const struct device *dev, struct net_pkt *pkt) { if (!active_scenario.is_active) { return 0; } if (!check_packet_addresses(pkt)) { return 0; } forwarding_counter++; if (net_pkt_iface(pkt) == iface_1) { iface_1_forwarded = true; } else if (net_pkt_iface(pkt) == iface_2) { iface_2_forwarded = true; } else if (net_pkt_iface(pkt) == iface_3) { iface_3_forwarded = true; } return 0; } struct net_route_mcast_iface_cfg net_route_data_if1; struct net_route_mcast_iface_cfg net_route_data_if2; struct net_route_mcast_iface_cfg net_route_data_if3; static struct dummy_api net_route_mcast_if_api_1 = { .iface_api.init = net_route_mcast_iface_init1, .send = iface_send, }; static struct dummy_api net_route_mcast_if_api_2 = { .iface_api.init = net_route_mcast_iface_init2, .send = iface_send, }; static struct dummy_api net_route_mcast_if_api_3 = { .iface_api.init = net_route_mcast_iface_init3, .send = iface_send, }; #define _ETH_L2_LAYER DUMMY_L2 #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2) NET_DEVICE_INIT_INSTANCE(mcast_iface_1, "mcast_iface_1", iface_1, net_route_mcast_dev_init, NULL, &net_route_data_if1, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_route_mcast_if_api_1, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127); NET_DEVICE_INIT_INSTANCE(mcast_iface_2, "mcast_iface_2", iface_2, net_route_mcast_dev_init, NULL, &net_route_data_if2, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_route_mcast_if_api_2, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127); NET_DEVICE_INIT_INSTANCE(mcast_iface_3, "mcast_iface_3", iface_3, net_route_mcast_dev_init, NULL, &net_route_data_if3, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_route_mcast_if_api_3, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127); static struct net_pkt *setup_ipv6_udp(struct net_if *iface, struct in6_addr *src_addr, struct in6_addr *remote_addr, uint16_t src_port, uint16_t remote_port) { static const char payload[] = "foobar"; struct net_pkt *pkt; int res; pkt = net_pkt_alloc_with_buffer(iface, strlen(payload), AF_INET6, IPPROTO_UDP, K_FOREVER); if (!pkt) { return NULL; } net_pkt_set_ipv6_hop_limit(pkt, 2); res = net_ipv6_create(pkt, src_addr, remote_addr); zassert_equal(0, res, "ipv6 create failed"); res = net_udp_create(pkt, htons(src_port), htons(remote_port)); zassert_equal(0, res, "udp create failed"); res = net_pkt_write(pkt, (uint8_t *) payload, strlen(payload)); zassert_equal(0, res, "pkt write failed"); net_pkt_cursor_init(pkt); net_ipv6_finalize(pkt, IPPROTO_UDP); net_pkt_cursor_init(pkt); return pkt; } static void test_route_mcast_init(void) { zassert_not_null(iface_1, "Interface is NULL"); zassert_not_null(iface_2, "Interface is NULL"); zassert_not_null(iface_3, "Interface is NULL"); net_if_flag_set(iface_1, NET_IF_FORWARD_MULTICASTS); net_if_flag_set(iface_2, NET_IF_FORWARD_MULTICASTS); /* iface_3 should not forward multicasts */ } static void test_route_mcast_route_add(void) { struct in6_addr nw_prefix_based_all_nodes; struct net_route_entry_mcast *entry; entry = net_route_mcast_add(iface_1, &mcast_prefix_iflocal, 16); zassert_is_null(entry, "add iface local should fail"); entry = net_route_mcast_add(iface_1, &mcast_prefix_llocal, 16); zassert_is_null(entry, "add link local should fail"); test_mcast_routes[0] = net_route_mcast_add(iface_1, &mcast_prefix_admin, 16); zassert_not_null(test_mcast_routes[0], "mcast route add failed"); test_mcast_routes[1] = net_route_mcast_add(iface_2, &mcast_prefix_site_local, 16); zassert_not_null(test_mcast_routes[1], "mcast route add failed"); test_mcast_routes[2] = net_route_mcast_add(iface_1, &mcast_prefix_orga, 16); zassert_not_null(test_mcast_routes[2], "mcast route add failed"); test_mcast_routes[3] = net_route_mcast_add(iface_2, &mcast_prefix_global, 16); zassert_not_null(test_mcast_routes[3], "mcast route add failed"); /* check if route can be added * if forwarding flag not set on iface */ test_mcast_routes[4] = net_route_mcast_add(iface_3, &mcast_prefix_global, 16); zassert_is_null(test_mcast_routes[4], "mcast route add should fail"); test_mcast_routes[4] = net_route_mcast_add(iface_1, &mcast_prefix_nw_based, 96); zassert_not_null(test_mcast_routes[4], "add for nw prefix based failed"); memcpy(&nw_prefix_based_all_nodes, &mcast_prefix_nw_based, sizeof(struct in6_addr)); nw_prefix_based_all_nodes.s6_addr[15] = 0x01; test_mcast_routes[5] = net_route_mcast_add(iface_2, &nw_prefix_based_all_nodes, 128); zassert_not_null(test_mcast_routes[5], "add for nw prefix based failed"); } static void mcast_foreach_cb(struct net_route_entry_mcast *entry, void *user_data) { zassert_equal_ptr(user_data, &mcast_prefix_global, "foreach failed, wrong user_data"); } static void test_route_mcast_foreach(void) { int executed_first = net_route_mcast_foreach(mcast_foreach_cb, NULL, &mcast_prefix_global); int executed_skip = net_route_mcast_foreach(mcast_foreach_cb, &mcast_prefix_admin, &mcast_prefix_global); zassert_true(executed_skip == (executed_first - 1), "mcast foreach skip did not skip"); } static void test_route_mcast_lookup(void) { struct net_route_entry_mcast *route = net_route_mcast_lookup(&mcast_prefix_admin); zassert_equal_ptr(test_mcast_routes[0], route, "mcast lookup failed"); route = net_route_mcast_lookup(&mcast_prefix_site_local); zassert_equal_ptr(test_mcast_routes[1], route, "mcast lookup failed"); route = net_route_mcast_lookup(&mcast_prefix_global); zassert_equal_ptr(test_mcast_routes[3], route, "mcast lookup failed"); } static void test_route_mcast_route_del(void) { struct net_route_entry_mcast *route; bool success = net_route_mcast_del(test_mcast_routes[0]); zassert_true(success, "failed to delete mcast route"); route = net_route_mcast_lookup(&mcast_prefix_admin); zassert_is_null(route, "lookup found deleted route"); success = net_route_mcast_del(test_mcast_routes[1]); zassert_true(success, "failed to delete mcast route"); route = net_route_mcast_lookup(&mcast_prefix_site_local); zassert_is_null(route, "lookup found deleted route"); success = net_route_mcast_del(test_mcast_routes[2]); zassert_true(success, "failed to delete mcast route"); success = net_route_mcast_del(test_mcast_routes[3]); zassert_true(success, "failed to delete mcast route"); success = net_route_mcast_del(test_mcast_routes[4]); zassert_true(success, "failed to delete mcast route"); success = net_route_mcast_del(test_mcast_routes[5]); zassert_true(success, "failed to delete mcast route"); } static void reset_counters(void) { iface_1_forwarded = false; iface_2_forwarded = false; iface_3_forwarded = false; forwarding_counter = 0; } static void test_route_mcast_scenario1(void) { /* scenario 1 site local: * 1. iface_1 receives site local * only iface_2 forwards * 2. iface_3 receives site_local * only iface_2 forwards */ reset_counters(); memcpy(&active_scenario.src, &iface_1_addr, sizeof(struct in6_addr)); active_scenario.src.s6_addr[15] = 0x02; memcpy(&active_scenario.mcast, &mcast_prefix_site_local, sizeof(struct in6_addr)); active_scenario.mcast.s6_addr[15] = 0x01; struct net_pkt *pkt1 = setup_ipv6_udp(iface_1, &active_scenario.src, &active_scenario.mcast, 20015, 20001); active_scenario.is_active = true; if (net_recv_data(iface_1, pkt1) < 0) { net_pkt_unref(pkt1); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); net_pkt_unref(pkt1); zassert_true(iface_2_forwarded, "iface_2 did not forward"); zassert_false(iface_1_forwarded, "iface_1 forwarded"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 1, "unexpected forwarded packet count"); reset_counters(); memcpy(&active_scenario.src, &iface_3_addr, sizeof(struct in6_addr)); active_scenario.src.s6_addr[15] = 0x09; struct net_pkt *pkt2 = setup_ipv6_udp(iface_3, &active_scenario.src, &active_scenario.mcast, 20015, 20001); if (net_recv_data(iface_3, pkt2) < 0) { net_pkt_unref(pkt2); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); net_pkt_unref(pkt2); active_scenario.is_active = false; zassert_true(iface_2_forwarded, "iface_2 did not forward"); zassert_false(iface_1_forwarded, "iface_1 forwarded"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 1, "unexpected forwarded packet count"); reset_counters(); } static void test_route_mcast_scenario2(void) { /* * scenario 2 admin local: * 1. iface_1 receives * iface_2 must not forward due to missing routing entry. * iface_3 must not forward due to missing * routing entry and missing flag. * iface_1 must not forward because itself * received the packet! * * 2. iface_3 receives * now iface_1 must forward due to routing entry */ reset_counters(); memcpy(&active_scenario.src, &iface_1_addr, sizeof(struct in6_addr)); active_scenario.src.s6_addr[15] = 0x08; memcpy(&active_scenario.mcast, &mcast_prefix_admin, sizeof(struct in6_addr)); active_scenario.mcast.s6_addr[15] = 0x01; struct net_pkt *pkt = setup_ipv6_udp(iface_1, &active_scenario.src, &active_scenario.mcast, 215, 201); active_scenario.is_active = true; if (net_recv_data(iface_1, pkt) < 0) { net_pkt_unref(pkt); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); net_pkt_unref(pkt); zassert_false(iface_1_forwarded, "iface_1 forwarded"); zassert_false(iface_2_forwarded, "iface_2 forwarded"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 0, "wrong count forwarded packets"); reset_counters(); memcpy(&active_scenario.src, &iface_3_addr, sizeof(struct in6_addr)); active_scenario.src.s6_addr[15] = 0x08; struct net_pkt *pkt2 = setup_ipv6_udp(iface_3, &active_scenario.src, &active_scenario.mcast, 215, 201); if (net_recv_data(iface_3, pkt2) < 0) { net_pkt_unref(pkt2); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); active_scenario.is_active = false; net_pkt_unref(pkt2); zassert_true(iface_1_forwarded, "iface_1 did not forward"); zassert_false(iface_2_forwarded, "iface_2 forwarded"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 1, "wrong count forwarded packets"); } static void test_route_mcast_scenario3(void) { /* * scenario 3: network prefix based forwarding * 1. iface 3 receives nw prefix based all nodes * iface 1 + 2 forwarding because all nodes group * 2. iface 3 receives nw prefix based custom group * only iface 1 forwards * iface 3 route is set to all nodes * 3. iface 3 receives all nodes group with different prefix * no iface forwards */ reset_counters(); memcpy(&active_scenario.src, &iface_3_addr, sizeof(struct in6_addr)); active_scenario.src.s6_addr[15] = 0x08; memcpy(&active_scenario.mcast, &mcast_prefix_nw_based, sizeof(struct in6_addr)); active_scenario.mcast.s6_addr[15] = 0x01; struct net_pkt *pkt = setup_ipv6_udp(iface_3, &active_scenario.src, &active_scenario.mcast, 215, 201); active_scenario.is_active = true; if (net_recv_data(iface_3, pkt) < 0) { net_pkt_unref(pkt); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); net_pkt_unref(pkt); active_scenario.is_active = false; zassert_true(iface_1_forwarded, "iface_1 did not forward"); zassert_true(iface_2_forwarded, "iface_2 did not forward"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 2, "wrong count forwarded packets"); reset_counters(); /* set to custom group id */ active_scenario.mcast.s6_addr[15] = 0x0F; struct net_pkt *pkt2 = setup_ipv6_udp(iface_3, &active_scenario.src, &active_scenario.mcast, 215, 201); active_scenario.is_active = true; if (net_recv_data(iface_3, pkt2) < 0) { net_pkt_unref(pkt2); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); net_pkt_unref(pkt2); active_scenario.is_active = false; zassert_true(iface_1_forwarded, "iface_1 did not forward"); zassert_false(iface_2_forwarded, "iface_2 forwarded"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 1, "wrong count forwarded packets"); reset_counters(); /* set to all nodes but different prefix */ active_scenario.mcast.s6_addr[11] = 0x0F; active_scenario.mcast.s6_addr[15] = 0x01; struct net_pkt *pkt3 = setup_ipv6_udp(iface_3, &active_scenario.src, &active_scenario.mcast, 215, 201); active_scenario.is_active = true; if (net_recv_data(iface_3, pkt3) < 0) { net_pkt_unref(pkt3); zassert_true(0, "failed to receive initial packet!"); } k_sleep(WAIT_TIME); net_pkt_unref(pkt3); active_scenario.is_active = false; zassert_false(iface_1_forwarded, "iface_1 forwarded"); zassert_false(iface_2_forwarded, "iface_2 forwarded"); zassert_false(iface_3_forwarded, "iface_3 forwarded"); zassert_equal(forwarding_counter, 0, "wrong count forwarded packets"); } /*test case main entry*/ void test_main(void) { ztest_test_suite(test_route_mcast, ztest_unit_test(test_route_mcast_init), ztest_unit_test(test_route_mcast_route_add), ztest_unit_test(test_route_mcast_foreach), ztest_unit_test(test_route_mcast_scenario1), ztest_unit_test(test_route_mcast_scenario2), ztest_unit_test(test_route_mcast_scenario3), ztest_unit_test(test_route_mcast_lookup), ztest_unit_test(test_route_mcast_route_del) ); ztest_run_test_suite(test_route_mcast); }