Add a bunch of missing "zephyr/" prefixes to #include statements in various test and test framework files. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
1025 lines
28 KiB
C
1025 lines
28 KiB
C
/* 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 <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL);
|
|
|
|
#include <zephyr/types.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <zephyr/sys/printk.h>
|
|
#include <zephyr/random/rand32.h>
|
|
|
|
#include <zephyr/ztest.h>
|
|
|
|
#include <zephyr/net/dummy.h>
|
|
#include <zephyr/net/buf.h>
|
|
#include <zephyr/net/net_ip.h>
|
|
#include <zephyr/net/virtual.h>
|
|
#include <zephyr/net/virtual_mgmt.h>
|
|
#include <zephyr/net/ethernet.h>
|
|
#include <zephyr/net/net_l2.h>
|
|
|
|
#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 "<unknown type>";
|
|
}
|
|
#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);
|
|
}
|