/* main.c - Application main entry point */ /* * Copyright (c) 2021 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #define NET_LOG_LEVEL CONFIG_NET_L2_VIRTUAL_LOG_LEVEL #include LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipv4.h" #include "ipv6.h" #include "udp_internal.h" bool arp_add(struct net_if *iface, struct in_addr *src, struct net_eth_addr *hwaddr); #define NET_LOG_ENABLED 1 #include "net_private.h" #if NET_LOG_LEVEL >= LOG_LEVEL_DBG #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) #else #define DBG(fmt, ...) #endif #define PKT_ALLOC_TIME K_MSEC(50) #define TEST_PORT 9999 static char *test_data = "Test data to be sent"; /* Interface 1 addresses */ static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct in_addr my_addr = { { { 192, 0, 2, 1 } } }; /* Interface 2 addresses */ static struct in6_addr my_addr2 = { { { 0x20, 0x01, 0x0d, 0xb8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; /* Interface 3 addresses */ static struct in6_addr my_addr3 = { { { 0x20, 0x01, 0x0d, 0xb8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; /* Extra address is assigned to ll_addr */ static struct in6_addr ll_addr = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02, 0x04 } } }; struct sockaddr virtual_addr; struct sockaddr peer_addr; #define MTU 1024 /* Keep track of all virtual interfaces */ static struct net_if *virtual_interfaces[1]; static struct net_if *eth_interfaces[2]; static struct net_if *dummy_interfaces[2]; static struct net_context *udp_ctx; static bool test_failed; static bool test_started; static bool data_received; static K_SEM_DEFINE(wait_data, 0, UINT_MAX); #define WAIT_TIME K_SECONDS(1) struct eth_context { struct net_if *iface; uint8_t mac_addr[6]; }; static struct eth_context eth_context; static uint8_t expecting_outer; static uint8_t expecting_inner; static int header_len; static void eth_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct eth_context *context = dev->data; net_if_set_link_addr(iface, context->mac_addr, sizeof(context->mac_addr), NET_LINK_ETHERNET); ethernet_init(iface); } static int eth_tx(const struct device *dev, struct net_pkt *pkt) { struct eth_context *context = dev->data; zassert_equal_ptr(ð_context, context, "Context pointers do not match (%p vs %p)", eth_context, context); if (!pkt->buffer) { DBG("No data to send!\n"); return -ENODATA; } if (test_started) { uint8_t outer, inner; int ret; net_pkt_set_overwrite(pkt, true); net_pkt_hexdump(pkt, "pkt"); net_pkt_skip(pkt, sizeof(struct net_eth_hdr)); ret = net_pkt_read_u8(pkt, &outer); zassert_equal(ret, 0, "Cannot read outer protocol type"); zassert_equal(outer, expecting_outer, "Unexpected outer protocol 0x%02x, " "expecting 0x%02x", outer, expecting_outer); net_pkt_skip(pkt, header_len - 1); ret = net_pkt_read_u8(pkt, &inner); zassert_equal(ret, 0, "Cannot read inner protocol type"); zassert_equal(inner, expecting_inner, "Unexpected inner protocol 0x%02x, " "expecting 0x%02x", inner, expecting_inner); k_sem_give(&wait_data); } net_pkt_unref(pkt); return 0; } static enum ethernet_hw_caps eth_capabilities(const struct device *dev) { return 0; } static struct ethernet_api api_funcs = { .iface_api.init = eth_iface_init, .get_capabilities = eth_capabilities, .send = eth_tx, }; static void generate_mac(uint8_t *mac_addr) { /* 00-00-5E-00-53-xx Documentation RFC 7042 */ mac_addr[0] = 0x00; mac_addr[1] = 0x00; mac_addr[2] = 0x5E; mac_addr[3] = 0x00; mac_addr[4] = 0x53; mac_addr[5] = sys_rand32_get(); } static int eth_init(const struct device *dev) { struct eth_context *context = dev->data; generate_mac(context->mac_addr); return 0; } ETH_NET_DEVICE_INIT(eth_test, "eth_test", eth_init, NULL, ð_context, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU); struct net_if_test { uint8_t idx; /* not used for anything, just a dummy value */ uint8_t mac_addr[sizeof(struct net_eth_addr)]; struct net_linkaddr ll_addr; }; static int net_iface_dev_init(const struct device *dev) { return 0; } static uint8_t *net_iface_get_mac(const struct device *dev) { struct net_if_test *data = dev->data; if (data->mac_addr[2] == 0x00) { /* 00-00-5E-00-53-xx Documentation RFC 7042 */ data->mac_addr[0] = 0x00; data->mac_addr[1] = 0x00; data->mac_addr[2] = 0x5E; data->mac_addr[3] = 0x00; data->mac_addr[4] = 0x53; data->mac_addr[5] = sys_rand32_get(); } data->ll_addr.addr = data->mac_addr; data->ll_addr.len = 6U; return data->mac_addr; } static void net_iface_init(struct net_if *iface) { uint8_t *mac = net_iface_get_mac(net_if_get_device(iface)); net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr), NET_LINK_ETHERNET); } static int sender_iface(const struct device *dev, struct net_pkt *pkt) { return 0; } struct net_if_test net_iface1_data; struct net_if_test net_iface2_data; static struct dummy_api net_iface_api = { .iface_api.init = net_iface_init, .send = sender_iface, }; /* For testing purposes, create two dummy network interfaces so we can check * that attaching virtual interface work ok. */ NET_DEVICE_INIT_INSTANCE(eth_test_dummy1, "iface1", iface1, net_iface_dev_init, NULL, &net_iface1_data, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_iface_api, DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), 127); NET_DEVICE_INIT_INSTANCE(eth_test_dummy2, "iface2", iface2, net_iface_dev_init, NULL, &net_iface2_data, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_iface_api, DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), 127); struct user_data { int eth_if_count; int dummy_if_count; int virtual_if_count; int total_if_count; }; #if NET_LOG_LEVEL >= LOG_LEVEL_DBG static const char *iface2str(struct net_if *iface) { if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) { return "Ethernet"; } if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) { return "Dummy"; } if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) { return "Virtual"; } return ""; } #endif static void iface_cb(struct net_if *iface, void *user_data) { struct user_data *ud = user_data; static int starting_eth_idx = 1; /* * The below code is to only use struct net_if devices defined in this * test as board on which it is run can have its own set of interfaces. * * As a result one will not rely on linker's specific 'net_if_area' * placement. */ if ((iface != net_if_lookup_by_dev(DEVICE_GET(eth_test_dummy1))) && (iface != net_if_lookup_by_dev(DEVICE_GET(eth_test_dummy2))) && (iface != net_if_lookup_by_dev(DEVICE_GET(eth_test))) && (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL))) return; DBG("Interface %p (%s) [%d]\n", iface, iface2str(iface), net_if_get_by_iface(iface)); if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) { if (PART_OF_ARRAY(NET_IF_GET_NAME(eth_test, 0), iface)) { if (!eth_interfaces[0]) { /* Just use the first interface */ eth_interfaces[0] = iface; ud->eth_if_count++; } } else { if (ud->eth_if_count > ARRAY_SIZE(eth_interfaces)) { goto out; } eth_interfaces[starting_eth_idx++] = iface; ud->eth_if_count++; } } if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) { dummy_interfaces[ud->dummy_if_count++] = iface; zassert_true(ud->dummy_if_count <= 2, "Too many dummy interfaces"); } if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) { virtual_interfaces[ud->virtual_if_count++] = iface; zassert_true(ud->virtual_if_count <= 3, "Too many virtual interfaces"); } else { /* By default all interfaces are down initially */ /* Virtual interfaces are down initially */ net_if_down(iface); } out: ud->total_if_count++; } static void test_virtual_setup(void) { struct user_data ud = { 0 }; /* Make sure we have enough virtual interfaces */ net_if_foreach(iface_cb, &ud); zassert_equal(ud.virtual_if_count, ARRAY_SIZE(virtual_interfaces), "Invalid number of virtual interfaces, " "was %d should be %zu", ud.virtual_if_count, ARRAY_SIZE(virtual_interfaces)); zassert_true(ud.eth_if_count <= ARRAY_SIZE(eth_interfaces), "Invalid number of eth interfaces, " "was %d should be %zu", ud.eth_if_count, ARRAY_SIZE(eth_interfaces)); zassert_equal(ud.dummy_if_count, ARRAY_SIZE(dummy_interfaces), "Invalid number of dummy interfaces, " "was %d should be %zu", ud.dummy_if_count, ARRAY_SIZE(dummy_interfaces)); } static void test_address_setup(void) { struct net_if_addr *ifaddr; struct net_if *eth, *virt, *dummy1, *dummy2; int ret; eth = eth_interfaces[0]; virt = virtual_interfaces[0]; dummy1 = dummy_interfaces[0]; dummy2 = dummy_interfaces[1]; zassert_not_null(eth, "Eth Interface"); zassert_not_null(virt, "Virtual Interface"); zassert_not_null(dummy1, "Dummy Interface 1"); zassert_not_null(dummy2, "Dummy Interface 2"); ifaddr = net_if_ipv6_addr_add(eth, &my_addr1, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv6 address %s\n", net_sprint_ipv6_addr(&my_addr1)); zassert_not_null(ifaddr, "eth addr"); } /* For testing purposes we need to set the addresses preferred */ ifaddr->addr_state = NET_ADDR_PREFERRED; ifaddr = net_if_ipv4_addr_add(eth, &my_addr, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv4 address %s\n", net_sprint_ipv4_addr(&my_addr)); zassert_not_null(ifaddr, "eth addr"); } ifaddr->addr_state = NET_ADDR_PREFERRED; ifaddr = net_if_ipv6_addr_add(eth, &ll_addr, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv6 address %s\n", net_sprint_ipv6_addr(&ll_addr)); zassert_not_null(ifaddr, "ll_addr"); } ifaddr->addr_state = NET_ADDR_PREFERRED; ifaddr = net_if_ipv6_addr_add(virt, &my_addr2, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv6 address %s\n", net_sprint_ipv6_addr(&my_addr2)); zassert_not_null(ifaddr, "virt addr"); } ifaddr->addr_state = NET_ADDR_PREFERRED; ifaddr = net_if_ipv6_addr_add(dummy1, &my_addr3, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv6 address %s\n", net_sprint_ipv6_addr(&my_addr3)); zassert_not_null(ifaddr, "dummy1 addr"); } net_if_up(eth); net_if_up(dummy1); net_if_up(dummy2); /* Set the virtual interface addresses */ ret = net_ipaddr_parse(CONFIG_NET_TEST_TUNNEL_MY_ADDR, strlen(CONFIG_NET_TEST_TUNNEL_MY_ADDR), &virtual_addr); zassert_equal(ret, 1, "Cannot parse \"%s\"", CONFIG_NET_TEST_TUNNEL_MY_ADDR); if (virtual_addr.sa_family == AF_INET) { ifaddr = net_if_ipv4_addr_add(virt, &net_sin(&virtual_addr)->sin_addr, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv4 address %s\n", net_sprint_ipv4_addr( &net_sin(&virtual_addr)->sin_addr)); zassert_not_null(ifaddr, "virt addr"); } net_sin(&virtual_addr)->sin_port = htons(4242); } else if (virtual_addr.sa_family == AF_INET6) { ifaddr = net_if_ipv6_addr_add(virt, &net_sin6(&virtual_addr)->sin6_addr, NET_ADDR_MANUAL, 0); if (!ifaddr) { DBG("Cannot add IPv6 address %s\n", net_sprint_ipv6_addr( &net_sin6(&virtual_addr)->sin6_addr)); zassert_not_null(ifaddr, "virt addr"); } net_sin6(&virtual_addr)->sin6_port = htons(4242); } else { zassert_not_null(NULL, "Invalid address family (%d)", virtual_addr.sa_family); } ifaddr->addr_state = NET_ADDR_PREFERRED; ret = net_ipaddr_parse(CONFIG_NET_TEST_TUNNEL_PEER_ADDR, strlen(CONFIG_NET_TEST_TUNNEL_PEER_ADDR), &peer_addr); zassert_equal(ret, 1, "Cannot parse \"%s\"", CONFIG_NET_TEST_TUNNEL_PEER_ADDR); /* The interface might receive data which might fail the checks * in the iface sending function, so we need to reset the failure * flag. */ test_failed = false; } static bool add_neighbor(struct net_if *iface, struct in6_addr *addr) { struct net_linkaddr_storage llstorage; struct net_linkaddr lladdr; struct net_nbr *nbr; 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(iface, addr, &lladdr, false, NET_IPV6_NBR_STATE_REACHABLE); if (!nbr) { DBG("Cannot add dst %s to neighbor cache\n", net_sprint_ipv6_addr(addr)); return false; } return true; } static bool add_to_arp(struct net_if *iface, struct in_addr *addr) { #if defined(CONFIG_NET_ARP) struct net_eth_addr lladdr; lladdr.addr[0] = sys_rand32_get(); lladdr.addr[1] = 0x08; lladdr.addr[2] = 0x09; lladdr.addr[3] = 0x10; lladdr.addr[4] = 0x11; lladdr.addr[5] = sys_rand32_get(); return arp_add(iface, addr, &lladdr); #else ARG_UNUSED(iface); ARG_UNUSED(addr); return true; #endif } static void test_virtual_attach_and_detach(void) { struct net_if *iface = virtual_interfaces[0]; int ret; /* Attach virtual interface on top of Ethernet */ ret = net_virtual_interface_attach(iface, eth_interfaces[0]); zassert_equal(ret, 0, "Cannot attach %d on top of %d (%d)", net_if_get_by_iface(iface), net_if_get_by_iface(eth_interfaces[0]), ret); zassert_false(net_if_is_up(iface), "Virtual interface %d should be down", net_if_get_by_iface(iface)); ret = net_if_up(iface); zassert_equal(ret, 0, "Cannot take virtual interface %d up (%d)", net_if_get_by_iface(iface), ret); ret = net_virtual_interface_attach(iface, NULL); zassert_equal(ret, 0, "Cannot deattach %d from %d (%d)", net_if_get_by_iface(iface), net_if_get_by_iface(eth_interfaces[0]), ret); zassert_false(net_if_is_up(iface), "Virtual interface %d is still up", net_if_get_by_iface(iface)); } static void test_virtual_set_mtu(void) { struct virtual_interface_req_params params = { 0 }; struct net_if *iface = virtual_interfaces[0]; int ret; ret = net_if_up(iface); zassert_equal(ret, 0, "Cannot take virtual interface %d up (%d)", net_if_get_by_iface(iface), ret); params.mtu = MTU; ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_MTU, iface, ¶ms, sizeof(params)); zassert_equal(ret, -EACCES, "Could set interface %d MTU to %d (%d)", net_if_get_by_iface(iface), params.mtu, ret); ret = net_if_down(iface); zassert_equal(ret, 0, "Cannot take virtual interface %d down (%d)", net_if_get_by_iface(iface), ret); ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_MTU, iface, ¶ms, sizeof(params)); zassert_equal(ret, 0, "Cannot set interface %d MTU to %d (%d)", net_if_get_by_iface(iface), params.mtu, ret); } static void test_virtual_get_mtu(void) { struct virtual_interface_req_params params = { 0 }; struct net_if *iface = virtual_interfaces[0]; int ret; params.mtu = 0; ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_GET_MTU, iface, ¶ms, sizeof(params)); zassert_equal(ret, 0, "Cannot get interface %d MTU (%d)", net_if_get_by_iface(iface), params.mtu, ret); zassert_equal(params.mtu, MTU, "MTU mismatch from interface %d, got %d should be %d", net_if_get_by_iface(iface), params.mtu, MTU); } static void test_virtual_set_peer(void) { struct virtual_interface_req_params params = { 0 }; struct net_if *iface = virtual_interfaces[0]; int ret; ret = net_if_up(iface); zassert_equal(ret, 0, "Cannot take virtual interface %d up (%d)", net_if_get_by_iface(iface), ret); params.family = peer_addr.sa_family; if (params.family == AF_INET) { net_ipaddr_copy(¶ms.peer4addr, &net_sin(&peer_addr)->sin_addr); } else if (params.family == AF_INET6) { net_ipaddr_copy(¶ms.peer6addr, &net_sin6(&peer_addr)->sin6_addr); } else { zassert_true(false, "Invalid family (%d)", params.family); } ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PEER_ADDRESS, iface, ¶ms, sizeof(params)); zassert_equal(ret, -EACCES, "Could set interface %d peer to %s (%d)", net_if_get_by_iface(iface), CONFIG_NET_TEST_TUNNEL_PEER_ADDR, ret); ret = net_if_down(iface); zassert_equal(ret, 0, "Cannot take virtual interface %d down (%d)", net_if_get_by_iface(iface), ret); ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PEER_ADDRESS, iface, ¶ms, sizeof(params)); zassert_equal(ret, 0, "Cannot set interface %d peer to %s (%d)", net_if_get_by_iface(iface), CONFIG_NET_TEST_TUNNEL_PEER_ADDR, ret); /* We should be attached now */ ret = net_virtual_interface_attach(iface, dummy_interfaces[0]); zassert_equal(ret, -EALREADY, "Could attach %d on top of %d (%d)", net_if_get_by_iface(iface), net_if_get_by_iface(dummy_interfaces[0]), ret); } static void test_virtual_get_peer(void) { struct virtual_interface_req_params params = { 0 }; struct net_if *iface = virtual_interfaces[0]; int ret; ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_GET_PEER_ADDRESS, iface, ¶ms, sizeof(params)); zassert_equal(ret, 0, "Cannot get interface %d peer (%d)", net_if_get_by_iface(iface), ret); zassert_equal(params.family, peer_addr.sa_family, "Invalid family, should be %d was %d", peer_addr.sa_family, params.family); if (params.family == AF_INET) { zassert_mem_equal(¶ms.peer4addr, &net_sin(&peer_addr)->sin_addr, sizeof(struct in_addr), "Peer IPv4 address invalid"); } else if (params.family == AF_INET6) { zassert_mem_equal(¶ms.peer6addr, &net_sin6(&peer_addr)->sin6_addr, sizeof(struct in6_addr), "Peer IPv6 address invalid"); } else { zassert_true(false, "Invalid family (%d)", params.family); } } static void test_virtual_verify_name(void) { #define NAME "foobar" #define NAME2 "123456789" struct net_if *iface = virtual_interfaces[0]; char *tmp = NAME; char buf[sizeof(NAME2)]; char *name; net_virtual_set_name(iface, NAME); name = net_virtual_get_name(iface, buf, sizeof(buf)); zassert_mem_equal(name, tmp, strlen(name), "Cannot get name"); /* Check that the string is truncated */ tmp = NAME2; net_virtual_set_name(iface, tmp); name = net_virtual_get_name(iface, buf, sizeof(buf)); zassert_mem_equal(name, tmp, strlen(name), "Cannot get name"); zassert_mem_equal(name, tmp, strlen(tmp) - (sizeof(NAME2) - CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN), "Cannot get name"); } static void test_virtual_send_data_to_tunnel(void) { struct virtual_interface_req_params params = { 0 }; struct net_if *iface = virtual_interfaces[0]; struct net_if *attached; struct sockaddr dst_addr, src_addr; struct in_addr netmask = {{{ 255, 255, 255, 0 }}}; void *addr; int addrlen; int ret; params.family = peer_addr.sa_family; if (params.family == AF_INET) { net_ipaddr_copy(¶ms.peer4addr, &net_sin(&peer_addr)->sin_addr); expecting_outer = 0x45; header_len = sizeof(struct net_ipv4_hdr); ret = add_to_arp(eth_interfaces[0], &net_sin(&peer_addr)->sin_addr); zassert_true(ret, "Cannot add to arp"); } else if (params.family == AF_INET6) { net_ipaddr_copy(¶ms.peer6addr, &net_sin6(&peer_addr)->sin6_addr); expecting_outer = 0x60; header_len = sizeof(struct net_ipv6_hdr); ret = add_neighbor(eth_interfaces[0], &net_sin6(&peer_addr)->sin6_addr); zassert_true(ret, "Cannot add neighbor"); } else { zassert_true(false, "Invalid family (%d)", params.family); } net_if_ipv4_set_netmask(iface, &netmask); net_if_ipv4_set_netmask(eth_interfaces[0], &netmask); ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PEER_ADDRESS, iface, ¶ms, sizeof(params)); zassert_equal(ret, 0, "Cannot set interface %d peer to %s (%d)", net_if_get_by_iface(iface), CONFIG_NET_TEST_TUNNEL_PEER_ADDR, ret); net_virtual_set_name(iface, CONFIG_NET_TEST_TUNNEL_NAME); attached = net_virtual_get_iface(iface); zassert_equal(eth_interfaces[0], attached, "Not attached to Ethernet interface"); ret = net_if_up(iface); zassert_equal(ret, 0, "Cannot take virtual interface %d up (%d)", net_if_get_by_iface(iface), ret); memcpy(&dst_addr, &virtual_addr, sizeof(dst_addr)); memcpy(&src_addr, &virtual_addr, sizeof(src_addr)); if (dst_addr.sa_family == AF_INET) { net_sin(&dst_addr)->sin_addr.s4_addr[3] = 2; addr = &src_addr; addrlen = sizeof(struct sockaddr_in); expecting_inner = 0x45; /* IPv4 */ } else if (dst_addr.sa_family == AF_INET6) { net_sin6(&dst_addr)->sin6_addr.s6_addr[15] = 2; addr = &src_addr; addrlen = sizeof(struct sockaddr_in6); expecting_inner = 0x60; /* IPv6 */ } else { zassert_true(false, "Invalid family (%d)", dst_addr.sa_family); addrlen = 0; } ret = net_context_get(virtual_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP, &udp_ctx); zassert_equal(ret, 0, "Create IP UDP context failed"); ret = net_context_bind(udp_ctx, (struct sockaddr *)addr, addrlen); zassert_equal(ret, 0, "Context bind failure test failed"); test_started = true; ret = net_context_sendto(udp_ctx, test_data, strlen(test_data), &dst_addr, addrlen, NULL, K_NO_WAIT, NULL); zassert_true(ret > 0, "Send UDP pkt failed"); if (k_sem_take(&wait_data, WAIT_TIME)) { DBG("Timeout while waiting interface data\n"); zassert_false(true, "Timeout"); } net_context_unref(udp_ctx); } static struct net_pkt *create_outer(struct net_if *iface, sa_family_t family, enum net_ip_protocol proto, size_t inner_len, size_t outer_len) { return net_pkt_alloc_with_buffer(iface, inner_len + outer_len, family, proto, PKT_ALLOC_TIME); } static struct net_pkt *create_inner(struct net_if *iface, sa_family_t family, enum net_ip_protocol proto, size_t inner_len, size_t data_len) { return net_pkt_alloc_with_buffer(iface, inner_len + data_len, family, proto, PKT_ALLOC_TIME); } static void recv_data(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) { data_received = true; } static void test_virtual_recv_data_from_tunnel(int remote_ip, bool expected_ok) { struct net_if *iface = virtual_interfaces[0]; struct net_if *attached = eth_interfaces[0]; struct sockaddr dst_addr, src_addr, inner_src; struct in_addr *outerv4, *innerv4; struct in6_addr *outerv6, *innerv6; size_t inner_len = sizeof(struct net_udp_hdr) + strlen(test_data); struct net_pkt *outer, *inner; enum net_verdict verdict; uint16_t src_port = 4242, dst_port = 4242; uint8_t next_header; size_t addrlen; int ret; memcpy(&dst_addr, &peer_addr, sizeof(dst_addr)); memcpy(&src_addr, &peer_addr, sizeof(src_addr)); memcpy(&inner_src, &virtual_addr, sizeof(inner_src)); if (peer_addr.sa_family == AF_INET) { net_sin(&dst_addr)->sin_addr.s4_addr[3] = 1; net_sin(&src_addr)->sin_addr.s4_addr[3] = remote_ip; outerv4 = &net_sin(&peer_addr)->sin_addr; } else { net_sin6(&dst_addr)->sin6_addr.s6_addr[15] = 1; net_sin6(&src_addr)->sin6_addr.s6_addr[15] = remote_ip; outerv6 = &net_sin6(&peer_addr)->sin6_addr; } if (virtual_addr.sa_family == AF_INET) { net_sin(&inner_src)->sin_addr.s4_addr[3] = 2; innerv4 = &net_sin(&virtual_addr)->sin_addr; inner_len += sizeof(struct net_ipv4_hdr); } else { net_sin6(&inner_src)->sin6_addr.s6_addr[15] = 2; innerv6 = &net_sin6(&virtual_addr)->sin6_addr; inner_len += sizeof(struct net_ipv6_hdr); } if (peer_addr.sa_family == AF_INET) { outer = create_outer(attached, AF_INET, IPPROTO_IP, sizeof(struct net_ipv4_hdr), 0); zassert_not_null(outer, "Cannot allocate %s pkt", outer); ret = net_ipv4_create(outer, &net_sin(&src_addr)->sin_addr, &net_sin(&dst_addr)->sin_addr); zassert_equal(ret, 0, "Cannot create %s packet (%d)", "IPv4", ret); } else { outer = create_outer(attached, AF_INET6, IPPROTO_IPV6, sizeof(struct net_ipv6_hdr), 0); zassert_not_null(outer, "Cannot allocate %s pkt", outer); ret = net_ipv6_create(outer, &net_sin6(&src_addr)->sin6_addr, &net_sin6(&dst_addr)->sin6_addr); zassert_equal(ret, 0, "Cannot create %s packet (%d)", "IPv6", ret); } if (virtual_addr.sa_family == AF_INET) { inner = create_inner(iface, AF_INET, IPPROTO_IP, sizeof(struct net_ipv4_hdr), sizeof(struct net_udp_hdr) + strlen(test_data)); zassert_not_null(inner, "Cannot allocate %s pkt", inner); ret = net_ipv4_create(inner, &net_sin(&inner_src)->sin_addr, innerv4); zassert_equal(ret, 0, "Cannot create outer %s (%d)", "IPv4", ret); next_header = IPPROTO_IPIP; addrlen = sizeof(struct sockaddr_in); } else { inner = create_inner(iface, AF_INET6, IPPROTO_IPV6, sizeof(struct net_ipv6_hdr), sizeof(struct net_udp_hdr) + strlen(test_data)); zassert_not_null(inner, "Cannot allocate %s pkt", inner); ret = net_ipv6_create(inner, &net_sin6(&inner_src)->sin6_addr, innerv6); zassert_equal(ret, 0, "Cannot create outer %s (%d)", "IPv6", ret); next_header = IPPROTO_IPV6; addrlen = sizeof(struct sockaddr_in6); } ret = net_udp_create(inner, htons(src_port), htons(dst_port)); zassert_equal(ret, 0, "Cannot create UDP (%d)", ret); net_pkt_write(inner, test_data, strlen(test_data)); net_pkt_cursor_init(inner); net_ipv4_finalize(inner, IPPROTO_UDP); net_buf_frag_add(outer->buffer, inner->buffer); inner->buffer = NULL; net_pkt_unref(inner); net_pkt_cursor_init(outer); if (peer_addr.sa_family == AF_INET) { net_ipv4_finalize(outer, next_header); } else { net_ipv6_finalize(outer, next_header); } ret = net_context_get(virtual_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP, &udp_ctx); zassert_equal(ret, 0, "Create IP UDP context failed"); net_context_set_iface(udp_ctx, iface); ret = net_context_bind(udp_ctx, (struct sockaddr *)&virtual_addr, addrlen); zassert_equal(ret, 0, "Context bind failure test failed"); test_started = true; data_received = false; ret = net_context_recv(udp_ctx, recv_data, K_NO_WAIT, &wait_data); zassert_equal(ret, 0, "UDP recv failed"); net_pkt_cursor_init(outer); if (peer_addr.sa_family == AF_INET) { verdict = net_ipv4_input(outer); } else { verdict = net_ipv6_input(outer, false); } if (expected_ok) { zassert_equal(verdict, NET_CONTINUE, "Packet not accepted (%d)", verdict); } else { zassert_equal(verdict, NET_DROP, "Packet not dropped (%d)", verdict); } net_context_put(udp_ctx); } static void test_virtual_recv_data_from_tunnel_ok(void) { test_virtual_recv_data_from_tunnel(2, true); } static void test_virtual_recv_data_from_tunnel_fail(void) { test_virtual_recv_data_from_tunnel(3, false); } void test_main(void) { ztest_test_suite(net_virtual_test, ztest_unit_test(test_virtual_setup), ztest_unit_test(test_address_setup), ztest_unit_test(test_virtual_attach_and_detach), ztest_unit_test(test_virtual_set_mtu), ztest_unit_test(test_virtual_get_mtu), ztest_unit_test(test_virtual_set_peer), ztest_unit_test(test_virtual_get_peer), ztest_unit_test(test_virtual_verify_name), ztest_unit_test(test_virtual_send_data_to_tunnel), ztest_unit_test(test_virtual_recv_data_from_tunnel_ok), ztest_unit_test(test_virtual_recv_data_from_tunnel_fail) ); ztest_run_test_suite(net_virtual_test); }