tests: net: Network packet checksum offloading tests

Test that if the checksum offloading is enabled, then we do not
calculate the checksum. Also the normal case, where offloading is
disabled and we need to calculate the checksum, is tested.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2018-03-14 09:45:14 +02:00
commit 22eeb70a26
4 changed files with 1015 additions and 0 deletions

View file

@ -0,0 +1,6 @@
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(NONE)
target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/subsys/net/ip)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -0,0 +1,33 @@
CONFIG_NETWORKING=y
CONFIG_NET_TEST=y
CONFIG_NET_IPV6=y
CONFIG_NET_UDP=y
CONFIG_NET_TCP=y
CONFIG_NET_IPV4=y
CONFIG_NET_ARP=n
CONFIG_NET_MAX_CONTEXTS=4
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_LOG=y
CONFIG_SYS_LOG_SHOW_COLOR=y
CONFIG_ENTROPY_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NET_IPV6_DAD=n
CONFIG_NET_IPV6_MLD=n
CONFIG_NET_PKT_TX_COUNT=15
CONFIG_NET_PKT_RX_COUNT=15
CONFIG_NET_BUF_RX_COUNT=15
CONFIG_NET_BUF_TX_COUNT=15
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6
CONFIG_NET_IPV6_ND=n
CONFIG_ZTEST=y
CONFIG_NET_APP=n
CONFIG_NET_APP_SETTINGS=n
CONFIG_NET_DEBUG_L2_ETHERNET=n
CONFIG_NET_DEBUG_CONTEXT=n
CONFIG_NET_DEBUG_IF=n
CONFIG_NET_DEBUG_CORE=n
CONFIG_NET_DEBUG_IPV6=n
CONFIG_NET_DEBUG_IPV4=n
CONFIG_NET_DEBUG_NET_PKT=y
CONFIG_SYS_LOG_NET_LEVEL=4
CONFIG_NET_SHELL=n

View file

@ -0,0 +1,971 @@
/* main.c - Application main entry point */
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <misc/printk.h>
#include <linker/sections.h>
#include <ztest.h>
#include <net/ethernet.h>
#include <net/buf.h>
#include <net/net_ip.h>
#include <net/net_l2.h>
#include <net/udp.h>
#include "ipv6.h"
#include "udp_internal.h"
#define NET_LOG_ENABLED 1
#include "net_private.h"
#if defined(CONFIG_NET_DEBUG_L2_ETHERNET)
#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif
#define PORT 9999
static char *test_data = "Test data to be sent";
/* 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, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
/* Destination address for test packets */
static struct in6_addr dst_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 9, 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 in_addr in4addr_my = { { { 192, 0, 2, 1 } } };
static struct in_addr in4addr_dst = { { { 192, 168, 1, 1 } } };
static struct in_addr in4addr_my2 = { { { 192, 0, 42, 1 } } };
/* Keep track of all ethernet interfaces */
static struct net_if *eth_interfaces[2];
static struct net_context *udp_v6_ctx_1;
static struct net_context *udp_v6_ctx_2;
static struct net_context *udp_v4_ctx_1;
static struct net_context *udp_v4_ctx_2;
static bool test_failed;
static bool test_started;
static bool start_receiving;
static K_SEM_DEFINE(wait_data, 0, UINT_MAX);
#define WAIT_TIME K_SECONDS(1)
struct eth_context {
struct net_if *iface;
u8_t mac_addr[6];
u16_t expecting_tag;
};
static struct eth_context eth_context_offloading_disabled;
static struct eth_context eth_context_offloading_enabled;
static void eth_iface_init(struct net_if *iface)
{
struct device *dev = net_if_get_device(iface);
struct eth_context *context = dev->driver_data;
net_if_set_link_addr(iface, context->mac_addr,
sizeof(context->mac_addr),
NET_LINK_ETHERNET);
DBG("Iface %p addr %s\n", iface,
net_sprint_ll_addr(context->mac_addr, sizeof(context->mac_addr)));
}
static int eth_tx_offloading_disabled(struct net_if *iface, struct net_pkt *pkt)
{
struct eth_context *context = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_disabled, context,
"Context pointers do not match (%p vs %p)",
eth_context_offloading_disabled, context);
if (!pkt->frags) {
DBG("No data to send!\n");
return -ENODATA;
}
if (start_receiving) {
struct net_udp_hdr hdr, *udp_hdr;
u16_t port;
u8_t lladdr[6];
DBG("Packet %p received\n", pkt);
/* Swap IP src and destination address so that we can receive
* the packet and the stack will not reject it.
*/
if (net_pkt_family(pkt) == AF_INET6) {
struct in6_addr addr;
net_ipaddr_copy(&addr, &NET_IPV6_HDR(pkt)->src);
net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src,
&NET_IPV6_HDR(pkt)->dst);
net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr);
} else {
struct in_addr addr;
net_ipaddr_copy(&addr, &NET_IPV4_HDR(pkt)->src);
net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src,
&NET_IPV4_HDR(pkt)->dst);
net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr);
}
udp_hdr = net_udp_get_hdr(pkt, &hdr);
zassert_not_null(udp_hdr, "UDP header missing");
port = udp_hdr->src_port;
udp_hdr->src_port = udp_hdr->dst_port;
udp_hdr->dst_port = port;
memcpy(lladdr,
((struct net_eth_hdr *)net_pkt_ll(pkt))->src.addr,
sizeof(lladdr));
memcpy(((struct net_eth_hdr *)net_pkt_ll(pkt))->src.addr,
((struct net_eth_hdr *)net_pkt_ll(pkt))->dst.addr,
sizeof(lladdr));
memcpy(((struct net_eth_hdr *)net_pkt_ll(pkt))->dst.addr,
lladdr, sizeof(lladdr));
pkt->frags->data -= net_pkt_ll_reserve(pkt);
pkt->frags->len += net_pkt_ll_reserve(pkt);
net_pkt_set_ll_reserve(pkt, 0);
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) {
test_failed = true;
zassert_true(false, "Packet %p receive failed\n", pkt);
}
return 0;
}
if (test_started) {
u16_t chksum;
chksum = net_udp_get_chksum(pkt, pkt->frags);
DBG("Chksum 0x%x offloading disabled\n", chksum);
zassert_not_equal(chksum, 0, "Checksum calculated");
k_sem_give(&wait_data);
}
net_pkt_unref(pkt);
return 0;
}
static int eth_tx_offloading_enabled(struct net_if *iface, struct net_pkt *pkt)
{
struct eth_context *context = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_enabled, context,
"Context pointers do not match (%p vs %p)",
eth_context_offloading_enabled, context);
if (!pkt->frags) {
DBG("No data to send!\n");
return -ENODATA;
}
if (test_started) {
u16_t chksum;
chksum = net_udp_get_chksum(pkt, pkt->frags);
DBG("Chksum 0x%x offloading enabled\n", chksum);
zassert_equal(chksum, 0, "Checksum calculated\n");
k_sem_give(&wait_data);
}
net_pkt_unref(pkt);
return 0;
}
static enum eth_hw_caps eth_offloading_enabled(struct device *dev)
{
return ETH_HW_TX_CHKSUM_OFFLOAD |
ETH_HW_RX_CHKSUM_OFFLOAD;
}
static struct ethernet_api api_funcs_offloading_disabled = {
.iface_api.init = eth_iface_init,
.iface_api.send = eth_tx_offloading_disabled,
};
static struct ethernet_api api_funcs_offloading_enabled = {
.iface_api.init = eth_iface_init,
.iface_api.send = eth_tx_offloading_enabled,
.get_capabilities = eth_offloading_enabled,
};
static void generate_mac(u8_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(struct device *dev)
{
struct eth_context *context = dev->driver_data;
generate_mac(context->mac_addr);
return 0;
}
NET_DEVICE_INIT(eth_offloading_disabled_test, "eth_offloading_disabled_test",
eth_init, &eth_context_offloading_disabled,
NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs_offloading_disabled,
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), 1500);
NET_DEVICE_INIT(eth_offloading_enabled_test, "eth_offloading_enabled_test",
eth_init, &eth_context_offloading_enabled,
NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs_offloading_enabled,
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), 1500);
struct user_data {
int eth_if_count;
int total_if_count;
};
#if defined(CONFIG_NET_DEBUG_L2_ETHERNET)
static const char *iface2str(struct net_if *iface)
{
#ifdef CONFIG_NET_L2_ETHERNET
if (iface->l2 == &NET_L2_GET_NAME(ETHERNET)) {
return "Ethernet";
}
#endif
#ifdef CONFIG_NET_L2_DUMMY
if (iface->l2 == &NET_L2_GET_NAME(DUMMY)) {
return "Dummy";
}
#endif
return "<unknown type>";
}
#endif
static void iface_cb(struct net_if *iface, void *user_data)
{
struct user_data *ud = user_data;
DBG("Interface %p (%s) [%d]\n", iface, iface2str(iface),
net_if_get_by_iface(iface));
if (iface->l2 == &NET_L2_GET_NAME(ETHERNET)) {
struct eth_context *eth_ctx =
net_if_get_device(iface)->driver_data;
if (eth_ctx == &eth_context_offloading_disabled) {
DBG("Iface %p without offloading\n", iface);
eth_interfaces[0] = iface;
}
if (eth_ctx == &eth_context_offloading_enabled) {
DBG("Iface %p with offloading\n", iface);
eth_interfaces[1] = iface;
}
ud->eth_if_count++;
}
/* By default all interfaces are down initially */
net_if_down(iface);
ud->total_if_count++;
}
static void eth_setup(void)
{
struct user_data ud = { 0 };
/* Make sure we have enough virtual interfaces */
net_if_foreach(iface_cb, &ud);
zassert_equal(ud.eth_if_count, sizeof(eth_interfaces) / sizeof(void *),
"Invalid number of interfaces (%d vs %d)\n",
ud.eth_if_count,
sizeof(eth_interfaces) / sizeof(void *));
}
static void address_setup(void)
{
struct net_if_addr *ifaddr;
struct net_if *iface1, *iface2;
iface1 = eth_interfaces[0];
iface2 = eth_interfaces[1];
zassert_not_null(iface1, "Interface 1\n");
zassert_not_null(iface2, "Interface 2\n");
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\n");
}
/* For testing purposes we need to set the adddresses 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\n");
}
ifaddr->addr_state = NET_ADDR_PREFERRED;
ifaddr = net_if_ipv4_addr_add(iface1, &in4addr_my,
NET_ADDR_MANUAL, 0);
zassert_not_null(ifaddr, "Cannot add IPv4 address\n");
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\n");
}
ifaddr->addr_state = NET_ADDR_PREFERRED;
ifaddr = net_if_ipv4_addr_add(iface2, &in4addr_my2,
NET_ADDR_MANUAL, 0);
zassert_not_null(ifaddr, "Cannot add IPv4 address\n");
net_if_up(iface1);
net_if_up(iface2);
/* 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 = 6;
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 void tx_chksum_offload_disabled_test_v6(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in6 dst_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(PORT),
};
struct sockaddr_in6 src_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = 0,
};
ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
&udp_v6_ctx_1);
zassert_equal(ret, 0, "Create IPv6 UDP context failed\n");
memcpy(&src_addr6.sin6_addr, &my_addr1, sizeof(struct in6_addr));
memcpy(&dst_addr6.sin6_addr, &dst_addr, sizeof(struct in6_addr));
ret = net_context_bind(udp_v6_ctx_1, (struct sockaddr *)&src_addr6,
sizeof(struct sockaddr_in6));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[0];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_disabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v6_ctx_1, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v6_ctx_1, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
ret = add_neighbor(iface, &dst_addr);
zassert_true(ret, "Cannot add neighbor\n");
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr6,
sizeof(struct sockaddr_in6),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
net_context_unref(udp_v6_ctx_1);
}
static void tx_chksum_offload_disabled_test_v4(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in dst_addr4 = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
};
struct sockaddr_in src_addr4 = {
.sin_family = AF_INET,
.sin_port = 0,
};
ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
&udp_v4_ctx_1);
zassert_equal(ret, 0, "Create IPv4 UDP context failed\n");
memcpy(&src_addr4.sin_addr, &in4addr_my, sizeof(struct in_addr));
memcpy(&dst_addr4.sin_addr, &in4addr_dst, sizeof(struct in_addr));
ret = net_context_bind(udp_v4_ctx_1, (struct sockaddr *)&src_addr4,
sizeof(struct sockaddr_in));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[0];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_disabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v4_ctx_1, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v4_ctx_1, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
ret = add_neighbor(iface, &dst_addr);
zassert_true(ret, "Cannot add neighbor\n");
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr4,
sizeof(struct sockaddr_in),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
net_context_unref(udp_v4_ctx_1);
}
static void tx_chksum_offload_enabled_test_v6(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in6 dst_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(PORT),
};
struct sockaddr_in6 src_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = 0,
};
ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
&udp_v6_ctx_2);
zassert_equal(ret, 0, "Create IPv6 UDP context failed\n");
memcpy(&src_addr6.sin6_addr, &my_addr2, sizeof(struct in6_addr));
memcpy(&dst_addr6.sin6_addr, &dst_addr, sizeof(struct in6_addr));
ret = net_context_bind(udp_v6_ctx_2, (struct sockaddr *)&src_addr6,
sizeof(struct sockaddr_in6));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[1];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_enabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v6_ctx_2, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v6_ctx_2, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
ret = add_neighbor(iface, &dst_addr);
zassert_true(ret, "Cannot add neighbor\n");
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr6,
sizeof(struct sockaddr_in6),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
net_context_unref(udp_v6_ctx_2);
}
static void tx_chksum_offload_enabled_test_v4(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in dst_addr4 = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
};
struct sockaddr_in src_addr4 = {
.sin_family = AF_INET,
.sin_port = 0,
};
ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
&udp_v4_ctx_2);
zassert_equal(ret, 0, "Create IPv4 UDP context failed\n");
memcpy(&src_addr4.sin_addr, &in4addr_my2, sizeof(struct in_addr));
memcpy(&dst_addr4.sin_addr, &in4addr_dst, sizeof(struct in_addr));
ret = net_context_bind(udp_v4_ctx_2, (struct sockaddr *)&src_addr4,
sizeof(struct sockaddr_in));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[1];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_enabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v4_ctx_2, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v4_ctx_2, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
ret = add_neighbor(iface, &dst_addr);
zassert_true(ret, "Cannot add neighbor\n");
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr4,
sizeof(struct sockaddr_in),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
net_context_unref(udp_v4_ctx_2);
}
static void recv_cb_offload_disabled(struct net_context *context,
struct net_pkt *pkt,
int status,
void *user_data)
{
struct net_udp_hdr hdr, *udp_hdr;
udp_hdr = net_udp_get_hdr(pkt, &hdr);
zassert_not_equal(udp_hdr->chksum, 0, "Checksum is not set\n");
if (net_pkt_family(pkt) == AF_INET) {
struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt);
zassert_not_equal(ipv4->chksum, 0,
"IPv4 checksum is not set\n");
}
k_sem_give(&wait_data);
net_pkt_unref(pkt);
}
static void recv_cb_offload_enabled(struct net_context *context,
struct net_pkt *pkt,
int status,
void *user_data)
{
struct net_udp_hdr hdr, *udp_hdr;
udp_hdr = net_udp_get_hdr(pkt, &hdr);
zassert_equal(udp_hdr->chksum, 0, "Checksum is set\n");
if (net_pkt_family(pkt) == AF_INET) {
struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt);
zassert_equal(ipv4->chksum, 0, "IPv4 checksum is set\n");
}
k_sem_give(&wait_data);
net_pkt_unref(pkt);
}
static void rx_chksum_offload_disabled_test_v6(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in6 dst_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(PORT),
};
struct sockaddr_in6 src_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = 0,
};
ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
&udp_v6_ctx_1);
zassert_equal(ret, 0, "Create IPv6 UDP context failed\n");
memcpy(&src_addr6.sin6_addr, &my_addr1, sizeof(struct in6_addr));
memcpy(&dst_addr6.sin6_addr, &dst_addr, sizeof(struct in6_addr));
ret = net_context_bind(udp_v6_ctx_1, (struct sockaddr *)&src_addr6,
sizeof(struct sockaddr_in6));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[0];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_disabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v6_ctx_1, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v6_ctx_1, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
start_receiving = true;
ret = net_context_recv(udp_v6_ctx_1, recv_cb_offload_disabled, 0,
NULL);
zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr6,
sizeof(struct sockaddr_in6),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
/* Let the receiver to receive the packets */
k_sleep(MSEC(10));
}
static void rx_chksum_offload_disabled_test_v4(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in dst_addr4 = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
};
struct sockaddr_in src_addr4 = {
.sin_family = AF_INET,
.sin_port = 0,
};
ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
&udp_v4_ctx_1);
zassert_equal(ret, 0, "Create IPv4 UDP context failed\n");
memcpy(&src_addr4.sin_addr, &in4addr_my, sizeof(struct in_addr));
memcpy(&dst_addr4.sin_addr, &in4addr_dst, sizeof(struct in_addr));
ret = net_context_bind(udp_v4_ctx_1, (struct sockaddr *)&src_addr4,
sizeof(struct sockaddr_in));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[0];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_disabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v4_ctx_1, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v4_ctx_1, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
start_receiving = true;
ret = net_context_recv(udp_v4_ctx_1, recv_cb_offload_disabled, 0,
NULL);
zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr4,
sizeof(struct sockaddr_in),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
/* Let the receiver to receive the packets */
k_sleep(MSEC(10));
}
static void rx_chksum_offload_enabled_test_v6(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in6 dst_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(PORT),
};
struct sockaddr_in6 src_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = 0,
};
ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
&udp_v6_ctx_2);
zassert_equal(ret, 0, "Create IPv6 UDP context failed\n");
memcpy(&src_addr6.sin6_addr, &my_addr2, sizeof(struct in6_addr));
memcpy(&dst_addr6.sin6_addr, &dst_addr, sizeof(struct in6_addr));
ret = net_context_bind(udp_v6_ctx_2, (struct sockaddr *)&src_addr6,
sizeof(struct sockaddr_in6));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[1];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_enabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v6_ctx_2, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v6_ctx_2, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
start_receiving = true;
ret = net_context_recv(udp_v6_ctx_2, recv_cb_offload_enabled, 0,
NULL);
zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr6,
sizeof(struct sockaddr_in6),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
/* Let the receiver to receive the packets */
k_sleep(MSEC(10));
}
static void rx_chksum_offload_enabled_test_v4(void)
{
struct eth_context *ctx; /* This is interface context */
struct net_if *iface;
struct net_pkt *pkt;
struct net_buf *frag;
int ret, len;
struct sockaddr_in dst_addr4 = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
};
struct sockaddr_in src_addr4 = {
.sin_family = AF_INET,
.sin_port = 0,
};
ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
&udp_v4_ctx_2);
zassert_equal(ret, 0, "Create IPv4 UDP context failed\n");
memcpy(&src_addr4.sin_addr, &in4addr_my2, sizeof(struct in_addr));
memcpy(&dst_addr4.sin_addr, &in4addr_dst, sizeof(struct in_addr));
ret = net_context_bind(udp_v4_ctx_2, (struct sockaddr *)&src_addr4,
sizeof(struct sockaddr_in));
zassert_equal(ret, 0, "Context bind failure test failed\n");
iface = eth_interfaces[1];
ctx = net_if_get_device(iface)->driver_data;
zassert_equal_ptr(&eth_context_offloading_enabled, ctx,
"eth context mismatch\n");
pkt = net_pkt_get_tx(udp_v4_ctx_2, K_FOREVER);
zassert_not_null(pkt, "Cannot get pkt\n");
frag = net_pkt_get_data(udp_v4_ctx_2, K_FOREVER);
zassert_not_null(frag, "Cannot get frag\n");
net_pkt_frag_add(pkt, frag);
len = strlen(test_data);
memcpy(net_buf_add(frag, len), test_data, len);
net_pkt_set_appdatalen(pkt, len);
test_started = true;
start_receiving = true;
ret = net_context_recv(udp_v4_ctx_2, recv_cb_offload_enabled, 0,
NULL);
zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
ret = net_context_sendto(pkt, (struct sockaddr *)&dst_addr4,
sizeof(struct sockaddr_in),
NULL, 0, NULL, NULL);
zassert_equal(ret, 0, "Send UDP pkt failed (%d)\n", ret);
if (k_sem_take(&wait_data, WAIT_TIME)) {
DBG("Timeout while waiting interface data\n");
zassert_false(true, "Timeout\n");
}
/* Let the receiver to receive the packets */
k_sleep(MSEC(10));
}
void test_main(void)
{
ztest_test_suite(net_chksum_offload_test,
ztest_unit_test(eth_setup),
ztest_unit_test(address_setup),
ztest_unit_test(tx_chksum_offload_disabled_test_v6),
ztest_unit_test(tx_chksum_offload_disabled_test_v4),
ztest_unit_test(tx_chksum_offload_enabled_test_v6),
ztest_unit_test(tx_chksum_offload_enabled_test_v4),
ztest_unit_test(rx_chksum_offload_disabled_test_v6),
ztest_unit_test(rx_chksum_offload_disabled_test_v4),
ztest_unit_test(rx_chksum_offload_enabled_test_v6),
ztest_unit_test(rx_chksum_offload_enabled_test_v4)
);
ztest_run_test_suite(net_chksum_offload_test);
}

View file

@ -0,0 +1,5 @@
tests:
test:
min_ram: 16
tags: net checksum_offload
depends_on: netif