* As we are replacing native_posix with native_sim, let's refer to native_sim instead of native_posix in the comments of why we have 1 extra interface. * scripts/net/run-sample-tests.sh builds for native_sim now, not native_posix => let's fix it Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
410 lines
9.6 KiB
C
410 lines
9.6 KiB
C
/* main.c - Application main entry point */
|
|
|
|
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define NET_LOG_LEVEL CONFIG_NET_IF_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/ztest.h>
|
|
|
|
#include <zephyr/net/ethernet.h>
|
|
#include <zephyr/net/net_ip.h>
|
|
#include <zephyr/net/net_if.h>
|
|
#include <zephyr/net/promiscuous.h>
|
|
|
|
#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
|
|
|
|
/* Interface 1 addresses */
|
|
static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
|
|
|
|
/* 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 } } };
|
|
|
|
static struct in6_addr in6addr_mcast = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
|
|
|
|
static struct net_if *iface1;
|
|
static struct net_if *iface2;
|
|
|
|
#define WAIT_TIME 250
|
|
|
|
struct net_if_test {
|
|
uint8_t idx;
|
|
uint8_t mac_addr[sizeof(struct net_eth_addr)];
|
|
struct net_linkaddr ll_addr;
|
|
};
|
|
|
|
struct eth_fake_context {
|
|
struct net_if *iface;
|
|
uint8_t mac_address[6];
|
|
bool promisc_mode;
|
|
};
|
|
|
|
static struct eth_fake_context eth_fake_data1;
|
|
static struct eth_fake_context eth_fake_data2;
|
|
|
|
static void eth_fake_iface_init(struct net_if *iface)
|
|
{
|
|
const struct device *dev = net_if_get_device(iface);
|
|
struct eth_fake_context *ctx = dev->data;
|
|
|
|
ctx->iface = iface;
|
|
|
|
net_if_set_link_addr(iface, ctx->mac_address,
|
|
sizeof(ctx->mac_address),
|
|
NET_LINK_ETHERNET);
|
|
|
|
ethernet_init(iface);
|
|
}
|
|
|
|
static int eth_fake_send(const struct device *dev,
|
|
struct net_pkt *pkt)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
ARG_UNUSED(pkt);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev)
|
|
{
|
|
return ETHERNET_PROMISC_MODE;
|
|
}
|
|
|
|
static int eth_fake_set_config(const struct device *dev,
|
|
enum ethernet_config_type type,
|
|
const struct ethernet_config *config)
|
|
{
|
|
struct eth_fake_context *ctx = dev->data;
|
|
|
|
switch (type) {
|
|
case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
|
|
if (config->promisc_mode == ctx->promisc_mode) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
ctx->promisc_mode = config->promisc_mode;
|
|
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct ethernet_api eth_fake_api_funcs = {
|
|
.iface_api.init = eth_fake_iface_init,
|
|
|
|
.get_capabilities = eth_fake_get_capabilities,
|
|
.set_config = eth_fake_set_config,
|
|
.send = eth_fake_send,
|
|
};
|
|
|
|
static int eth_fake_init(const struct device *dev)
|
|
{
|
|
struct eth_fake_context *ctx = dev->data;
|
|
|
|
ctx->promisc_mode = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ETH_NET_DEVICE_INIT(eth_fake1, "eth_fake1",
|
|
eth_fake_init, NULL,
|
|
ð_fake_data1, NULL, CONFIG_ETH_INIT_PRIORITY,
|
|
ð_fake_api_funcs, NET_ETH_MTU);
|
|
|
|
ETH_NET_DEVICE_INIT(eth_fake2, "eth_fake2",
|
|
eth_fake_init, NULL,
|
|
ð_fake_data2, NULL, CONFIG_ETH_INIT_PRIORITY,
|
|
ð_fake_api_funcs, NET_ETH_MTU);
|
|
|
|
#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";
|
|
}
|
|
|
|
return "<unknown type>";
|
|
}
|
|
#endif
|
|
|
|
static void iface_cb(struct net_if *iface, void *user_data)
|
|
{
|
|
static int if_count;
|
|
|
|
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)) {
|
|
const struct ethernet_api *api =
|
|
net_if_get_device(iface)->api;
|
|
|
|
/* As native_sim board will introduce another ethernet
|
|
* interface, make sure that we only use our own in this test.
|
|
*/
|
|
if (api->get_capabilities ==
|
|
eth_fake_api_funcs.get_capabilities) {
|
|
switch (if_count) {
|
|
case 0:
|
|
iface1 = iface;
|
|
break;
|
|
case 1:
|
|
iface2 = iface;
|
|
break;
|
|
}
|
|
|
|
if_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test_iface_setup(void)
|
|
{
|
|
struct net_if_mcast_addr *maddr;
|
|
struct net_if_addr *ifaddr;
|
|
int idx;
|
|
|
|
net_if_foreach(iface_cb, NULL);
|
|
|
|
idx = net_if_get_by_iface(iface1);
|
|
((struct net_if_test *)
|
|
net_if_get_device(iface1)->data)->idx = idx;
|
|
|
|
idx = net_if_get_by_iface(iface2);
|
|
((struct net_if_test *)
|
|
net_if_get_device(iface2)->data)->idx = idx;
|
|
|
|
zassert_not_null(iface1, "Interface 1");
|
|
zassert_not_null(iface2, "Interface 2");
|
|
|
|
DBG("Interfaces: [%d] iface1 %p, [%d] iface2 %p\n",
|
|
net_if_get_by_iface(iface1), iface1,
|
|
net_if_get_by_iface(iface2), iface2);
|
|
|
|
ifaddr = net_if_ipv6_addr_add(iface1, &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, "addr1");
|
|
}
|
|
|
|
/* For testing purposes we need to set the addresses preferred */
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
|
|
|
ifaddr = net_if_ipv6_addr_add(iface1, &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(iface2, &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, "addr2");
|
|
}
|
|
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
|
|
|
ifaddr = net_if_ipv6_addr_add(iface2, &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, "addr3");
|
|
}
|
|
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
|
|
|
net_ipv6_addr_create(&in6addr_mcast, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001);
|
|
|
|
maddr = net_if_ipv6_maddr_add(iface1, &in6addr_mcast);
|
|
if (!maddr) {
|
|
DBG("Cannot add multicast IPv6 address %s\n",
|
|
net_sprint_ipv6_addr(&in6addr_mcast));
|
|
zassert_not_null(maddr, "mcast");
|
|
}
|
|
|
|
net_if_up(iface1);
|
|
net_if_up(iface2);
|
|
}
|
|
|
|
static void _set_promisc_mode_on_again(struct net_if *iface)
|
|
{
|
|
int ret;
|
|
|
|
DBG("Make sure promiscuous mode is ON (%p)\n", iface);
|
|
|
|
ret = net_promisc_mode_on(iface);
|
|
|
|
zassert_equal(ret, -EALREADY, "iface %p promiscuous mode ON", iface);
|
|
}
|
|
|
|
static void _set_promisc_mode_on(struct net_if *iface)
|
|
{
|
|
bool ret;
|
|
|
|
DBG("Setting promiscuous mode ON (%p)\n", iface);
|
|
|
|
ret = net_promisc_mode_on(iface);
|
|
|
|
zassert_equal(ret, 0, "iface %p promiscuous mode set ON failed",
|
|
iface);
|
|
}
|
|
|
|
static void _set_promisc_mode_off_again(struct net_if *iface)
|
|
{
|
|
int ret;
|
|
|
|
DBG("Make sure promiscuous mode is OFF (%p)\n", iface);
|
|
|
|
ret = net_promisc_mode_off(iface);
|
|
|
|
zassert_equal(ret, -EALREADY, "iface %p promiscuous mode OFF", iface);
|
|
}
|
|
|
|
static void _set_promisc_mode_off(struct net_if *iface)
|
|
{
|
|
int ret;
|
|
|
|
DBG("Setting promiscuous mode OFF (%p)\n", iface);
|
|
|
|
ret = net_promisc_mode_off(iface);
|
|
|
|
zassert_equal(ret, 0, "iface %p promiscuous mode set OFF failed",
|
|
iface);
|
|
}
|
|
|
|
static void test_set_promisc_mode_on_again(void)
|
|
{
|
|
_set_promisc_mode_on_again(iface1);
|
|
_set_promisc_mode_on_again(iface2);
|
|
}
|
|
|
|
static void test_set_promisc_mode_on(void)
|
|
{
|
|
_set_promisc_mode_on(iface1);
|
|
_set_promisc_mode_on(iface2);
|
|
}
|
|
|
|
static void test_set_promisc_mode_off_again(void)
|
|
{
|
|
_set_promisc_mode_off_again(iface1);
|
|
_set_promisc_mode_off_again(iface2);
|
|
}
|
|
|
|
static void test_set_promisc_mode_off(void)
|
|
{
|
|
_set_promisc_mode_off(iface1);
|
|
_set_promisc_mode_off(iface2);
|
|
}
|
|
|
|
static void _recv_data(struct net_if *iface, struct net_pkt **pkt)
|
|
{
|
|
static uint8_t data[] = { 't', 'e', 's', 't', '\0' };
|
|
int ret;
|
|
|
|
*pkt = net_pkt_rx_alloc_with_buffer(iface, sizeof(data),
|
|
AF_UNSPEC, 0, K_FOREVER);
|
|
|
|
net_pkt_ref(*pkt);
|
|
|
|
net_pkt_write(*pkt, data, sizeof(data));
|
|
|
|
ret = net_recv_data(iface, *pkt);
|
|
zassert_equal(ret, 0, "Data receive failure");
|
|
}
|
|
|
|
static struct net_pkt *pkt1;
|
|
static struct net_pkt *pkt2;
|
|
|
|
static void test_recv_data(void)
|
|
{
|
|
_recv_data(iface1, &pkt1);
|
|
_recv_data(iface2, &pkt2);
|
|
}
|
|
|
|
static void test_verify_data(void)
|
|
{
|
|
struct net_pkt *pkt;
|
|
|
|
pkt = net_promisc_mode_wait_data(K_SECONDS(1));
|
|
zassert_not_null(pkt, "pkt");
|
|
zassert_not_null(pkt->buffer, "pkt->buffer");
|
|
zassert_not_null(pkt1, "pkt1");
|
|
zassert_not_null(pkt1->buffer, "pkt1->buffer");
|
|
zassert_equal(pkt->buffer->len, pkt1->buffer->len, "packet length differs");
|
|
zassert_not_null(pkt->buffer->data, "pkt->buffer->data");
|
|
zassert_not_null(pkt1->buffer->data, "pkt1->buffer->data");
|
|
zassert_mem_equal(pkt->buffer->data, pkt1->buffer->data, pkt1->buffer->len);
|
|
net_pkt_unref(pkt);
|
|
|
|
pkt = net_promisc_mode_wait_data(K_SECONDS(1));
|
|
zassert_not_null(pkt, "pkt");
|
|
zassert_not_null(pkt->buffer, "pkt->buffer");
|
|
zassert_not_null(pkt2, "pkt2");
|
|
zassert_not_null(pkt2->buffer, "pkt2->buffer");
|
|
zassert_equal(pkt->buffer->len, pkt2->buffer->len, "packet length differs");
|
|
zassert_not_null(pkt->buffer->data, "pkt->buffer->data");
|
|
zassert_not_null(pkt2->buffer->data, "pkt2->buffer->data");
|
|
zassert_mem_equal(pkt->buffer->data, pkt2->buffer->data, pkt2->buffer->len);
|
|
net_pkt_unref(pkt);
|
|
}
|
|
|
|
ZTEST(net_promisc_test_suite, test_net_promisc)
|
|
{
|
|
test_iface_setup();
|
|
test_set_promisc_mode_on();
|
|
test_set_promisc_mode_on_again();
|
|
test_recv_data();
|
|
test_verify_data();
|
|
test_set_promisc_mode_off();
|
|
test_set_promisc_mode_off_again();
|
|
}
|
|
|
|
ZTEST_SUITE(net_promisc_test_suite, NULL, NULL, NULL, NULL, NULL);
|