tests: net: Improve ICMPv4 tests

Earlier tests were not going through ICMP echo
core stack handlers. Due to that unable to verify
echo reply. Tests are improved to verify replies.

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com>
This commit is contained in:
Ravi kumar Veeramally 2020-03-03 15:43:42 +02:00 committed by Jukka Rissanen
commit 2f6bb980e8
2 changed files with 379 additions and 209 deletions

View file

@ -1,5 +1,6 @@
CONFIG_NETWORKING=y
CONFIG_NET_TEST=y
CONFIG_NET_L2_DUMMY=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y
CONFIG_NET_BUF=y

View file

@ -19,15 +19,15 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_ICMPV4_LOG_LEVEL);
#include <tc_util.h>
#include <net/buf.h>
#include <net/ethernet.h>
#include <net/dummy.h>
#include "net_private.h"
#include "icmpv4.h"
#include "ipv4.h"
#include <ztest.h>
static int handler_called;
static int handler_status;
static const unsigned char icmpv4_echo_req[] = {
/* IPv4 Header */
0x45, 0x00, 0x00, 0x54, 0xea, 0x8c, 0x40, 0x00,
@ -106,76 +106,24 @@ static const unsigned char icmpv4_echo_req_opt_bad[] = {
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00 };
#define TEST_ICMPV4_UNKNOWN 0
#define TEST_ICMPV4_ECHO_REQ 1
#define TEST_ICMPV4_ECHO_REQ_OPTS 2
static u8_t current = TEST_ICMPV4_UNKNOWN;
static struct in_addr my_addr = { { { 192, 0, 2, 1 } } };
static struct net_if *iface;
static enum net_verdict handle_reply_msg(struct net_pkt *pkt,
struct net_ipv4_hdr *ip_hdr,
struct net_icmp_hdr *icmp_hdr)
{
enum net_verdict ret;
handler_called++;
if (net_pkt_get_len(pkt) != sizeof(icmpv4_echo_rep)) {
goto fail;
return NET_DROP;
}
handler_status = 0;
ret = NET_OK;
return ret;
fail:
handler_status = -EINVAL;
ret = NET_DROP;
return ret;
}
static enum net_verdict handle_request_msg(struct net_pkt *pkt,
struct net_ipv4_hdr *ip_hdr,
struct net_icmp_hdr *icmp_hdr)
{
enum net_verdict ret;
handler_called++;
if (net_pkt_get_len(pkt) != sizeof(icmpv4_echo_req)) {
goto fail;
}
handler_status = 0;
ret = NET_OK;
return ret;
fail:
handler_status = -EINVAL;
ret = NET_DROP;
return ret;
}
static enum net_verdict handle_request_opt_msg(struct net_pkt *pkt,
struct net_ipv4_hdr *ip_hdr,
struct net_icmp_hdr *icmp_hdr)
{
enum net_verdict ret;
handler_called++;
if (net_pkt_get_len(pkt) != sizeof(icmpv4_echo_req_opt)) {
goto fail;
}
handler_status = 0;
ret = NET_OK;
return ret;
fail:
handler_status = -EINVAL;
ret = NET_DROP;
return ret;
net_pkt_unref(pkt);
return NET_OK;
}
static struct net_icmpv4_handler echo_rep_handler = {
@ -184,158 +132,379 @@ static struct net_icmpv4_handler echo_rep_handler = {
.handler = handle_reply_msg,
};
static struct net_icmpv4_handler echo_req_handler = {
.type = NET_ICMPV4_ECHO_REQUEST,
.code = 0,
.handler = handle_request_msg,
struct net_icmpv4_context {
u8_t mac_addr[sizeof(struct net_eth_addr)];
struct net_linkaddr ll_addr;
};
static struct net_icmpv4_handler echo_req_opt_handler = {
.type = NET_ICMPV4_ECHO_REQUEST,
.code = 0,
.handler = handle_request_opt_msg,
};
void test_icmpv4(void)
static int net_icmpv4_dev_init(struct device *dev)
{
k_thread_priority_set(k_current_get(), K_PRIO_COOP(7));
struct net_icmpv4_context *net_icmpv4_context = dev->driver_data;
struct net_ipv4_hdr *hdr;
struct net_pkt *pkt;
int ret;
net_icmpv4_context = net_icmpv4_context;
/* ================ Echo Request ================= */
net_icmpv4_register_handler(&echo_req_handler);
pkt = net_pkt_alloc_with_buffer(NULL, sizeof(icmpv4_echo_req),
AF_UNSPEC, 0, K_SECONDS(1));
zassert_not_null(pkt, "Allocation failed");
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
net_pkt_write(pkt, icmpv4_echo_req, sizeof(icmpv4_echo_req));
net_pkt_cursor_init(pkt);
net_pkt_set_ipv4_opts_len(pkt, 0);
net_pkt_set_overwrite(pkt, true);
net_pkt_skip(pkt, sizeof(struct net_ipv4_hdr));
hdr = (struct net_ipv4_hdr *)pkt->buffer->data;
ret = net_icmpv4_input(pkt, hdr);
/** TESTPOINT: Check input */
zassert_true(!(ret == NET_DROP || handler_status != 0),
"Callback not called properly");
/** TESTPOINT: Check input */
zassert_true(!(handler_called != 1), "Callbacks not called properly");
net_icmpv4_unregister_handler(&echo_req_handler);
net_pkt_unref(pkt);
/* ================ Echo Reply ================= */
net_icmpv4_register_handler(&echo_rep_handler);
pkt = net_pkt_alloc_with_buffer(NULL, sizeof(icmpv4_echo_rep),
AF_UNSPEC, 0, K_SECONDS(1));
zassert_not_null(pkt, "Allocation failed");
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
net_pkt_write(pkt, icmpv4_echo_rep, sizeof(icmpv4_echo_rep));
net_pkt_cursor_init(pkt);
net_pkt_set_ipv4_opts_len(pkt, 0);
net_pkt_set_overwrite(pkt, true);
net_pkt_skip(pkt, sizeof(struct net_ipv4_hdr));
hdr = (struct net_ipv4_hdr *)pkt->buffer->data;
ret = net_icmpv4_input(pkt, hdr);
/** TESTPOINT: Check input */
zassert_true(!(ret == NET_DROP || handler_status != 0),
"Callback not called properly");
/** TESTPOINT: Check input */
zassert_true(!(handler_called != 2), "Callbacks not called properly");
net_icmpv4_unregister_handler(&echo_rep_handler);
net_pkt_unref(pkt);
/* ================ Echo Request with Options ================= */
net_icmpv4_register_handler(&echo_req_opt_handler);
pkt = net_pkt_alloc_with_buffer(NULL, sizeof(icmpv4_echo_req_opt),
AF_UNSPEC, 0, K_SECONDS(1));
zassert_not_null(pkt, "Allocation failed");
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
net_pkt_write(pkt, icmpv4_echo_req_opt, sizeof(icmpv4_echo_req_opt));
net_pkt_cursor_init(pkt);
net_pkt_set_ipv4_opts_len(pkt, 36);
net_pkt_set_overwrite(pkt, true);
net_pkt_skip(pkt, sizeof(struct net_ipv4_hdr)); /* Header*/
net_pkt_skip(pkt, 36); /* Options length */
hdr = (struct net_ipv4_hdr *)pkt->buffer->data;
ret = net_icmpv4_input(pkt, hdr);
/** TESTPOINT: Check input */
zassert_true(!(ret == NET_DROP || handler_status != 0),
"Callback not called properly");
/** TESTPOINT: Check input */
zassert_true(!(handler_called != 3), "Callbacks not called properly");
net_icmpv4_unregister_handler(&echo_req_opt_handler);
net_pkt_unref(pkt);
/* ================ Echo Request with Bad Options ================= */
net_icmpv4_register_handler(&echo_req_opt_handler);
pkt = net_pkt_alloc_with_buffer(NULL, sizeof(icmpv4_echo_req_opt_bad),
AF_UNSPEC, 0, K_SECONDS(1));
zassert_not_null(pkt, "Allocation failed");
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
net_pkt_write(pkt, icmpv4_echo_req_opt_bad,
sizeof(icmpv4_echo_req_opt_bad));
net_pkt_cursor_init(pkt);
net_pkt_set_ipv4_opts_len(pkt, 4);
net_pkt_set_overwrite(pkt, true);
net_pkt_skip(pkt, sizeof(struct net_ipv4_hdr)); /* Header*/
net_pkt_skip(pkt, 4); /* Options length */
hdr = (struct net_ipv4_hdr *)pkt->buffer->data;
ret = net_icmpv4_input(pkt, hdr);
/** TESTPOINT: Check input */
zassert_true((ret == NET_DROP), "Packet should drop");
net_icmpv4_unregister_handler(&echo_req_opt_handler);
net_pkt_unref(pkt);
return 0;
}
/**test case main entry*/
static u8_t *net_icmpv4_get_mac(struct device *dev)
{
struct net_icmpv4_context *context = dev->driver_data;
if (context->mac_addr[2] == 0x00) {
/* 00-00-5E-00-53-xx Documentation RFC 7042 */
context->mac_addr[0] = 0x00;
context->mac_addr[1] = 0x00;
context->mac_addr[2] = 0x5E;
context->mac_addr[3] = 0x00;
context->mac_addr[4] = 0x53;
context->mac_addr[5] = 0x01;
}
return context->mac_addr;
}
static void net_icmpv4_iface_init(struct net_if *iface)
{
u8_t *mac = net_icmpv4_get_mac(net_if_get_device(iface));
net_if_set_link_addr(iface, mac, 6, NET_LINK_ETHERNET);
}
static int verify_echo_reply(struct net_pkt *pkt)
{
struct net_icmp_hdr icmp_hdr;
u8_t buf[60];
int ret;
u8_t payload_len;
net_pkt_set_overwrite(pkt, true);
net_pkt_cursor_init(pkt);
ret = net_pkt_skip(pkt, NET_IPV4H_LEN);
if (ret != 0) {
zassert_true(false, "echo_reply skip failed");
}
/* EchoReply Code and Type is 0 */
ret = net_pkt_read(pkt, &icmp_hdr, sizeof(struct net_icmp_hdr));
if (ret != 0) {
zassert_true(false, "echo_reply read failed");
}
if (icmp_hdr.code != 0 || icmp_hdr.type != 0) {
zassert_true(false, "echo_reply invalid type or code");
}
/* Calculate payload length */
payload_len = sizeof(icmpv4_echo_req) -
NET_IPV4H_LEN - NET_ICMPH_LEN;
if (payload_len != net_pkt_remaining_data(pkt)) {
zassert_true(false, "echo_reply invalid payload len");
}
ret = net_pkt_read(pkt, buf, payload_len);
if (ret != 0) {
zassert_true(false, "echo_reply read payload failed");
}
/* Compare the payload */
if (memcmp(buf, icmpv4_echo_req + NET_IPV4H_LEN + NET_ICMPH_LEN,
payload_len)) {
zassert_true(false, "echo_reply invalid payload");
}
/* Options length should be zero */
if (net_pkt_ipv4_opts_len(pkt)) {
zassert_true(false, "echo_reply invalid opts len");
}
return 0;
}
static int verify_echo_reply_with_opts(struct net_pkt *pkt)
{
struct net_icmp_hdr icmp_hdr;
u8_t buf[60];
int ret;
u8_t vhl;
u8_t opts_len;
u8_t payload_len;
net_pkt_set_overwrite(pkt, true);
net_pkt_cursor_init(pkt);
ret = net_pkt_read_u8(pkt, &vhl);
if (ret != 0) {
zassert_true(false, "echo_reply_opts read failed");
}
vhl = (vhl & NET_IPV4_IHL_MASK) * 4U;
opts_len = vhl - sizeof(struct net_ipv4_hdr);
if (opts_len == 0) {
zassert_true(false, "echo_reply_opts wrong opts len");
}
ret = net_pkt_skip(pkt, NET_IPV4H_LEN - 1U + opts_len);
if (ret != 0) {
zassert_true(false, "echo_reply_opts skip failed");
}
/* EchoReply Code and Type is 0 */
ret = net_pkt_read(pkt, &icmp_hdr, sizeof(struct net_icmp_hdr));
if (ret != 0) {
zassert_true(false, "echo_reply_opts read failed");
}
if (icmp_hdr.code != 0 || icmp_hdr.type != 0) {
zassert_true(false, "echo_reply_opts wrong code and type");
}
/* Calculate payload length */
payload_len = sizeof(icmpv4_echo_req_opt) -
NET_IPV4H_LEN - NET_ICMPH_LEN - opts_len;
if (payload_len != net_pkt_remaining_data(pkt)) {
zassert_true(false, "echo_reply_opts invalid paylaod len");
}
ret = net_pkt_read(pkt, buf, payload_len);
if (ret != 0) {
zassert_true(false, "echo_reply_opts read payload failed");
}
/* Compare the payload */
if (memcmp(buf, icmpv4_echo_req_opt +
NET_IPV4H_LEN + NET_ICMPH_LEN + opts_len,
payload_len)) {
zassert_true(false, "echo_reply_opts invalid payload");
}
/* Options length should not be zero */
if (net_pkt_ipv4_opts_len(pkt) != opts_len) {
zassert_true(false, "echo_reply_opts wrong opts len");
}
return 0;
}
static int tester_send(struct device *dev, struct net_pkt *pkt)
{
if (current == TEST_ICMPV4_ECHO_REQ) {
return verify_echo_reply(pkt);
} else if (current == TEST_ICMPV4_ECHO_REQ_OPTS) {
return verify_echo_reply_with_opts(pkt);
}
return -EINVAL;
}
struct net_icmpv4_context net_icmpv4_context_data;
static struct dummy_api net_icmpv4_if_api = {
.iface_api.init = net_icmpv4_iface_init,
.send = tester_send,
};
NET_DEVICE_INIT(net_icmpv4_test, "net_icmpv4_test",
net_icmpv4_dev_init, &net_icmpv4_context_data, NULL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&net_icmpv4_if_api, DUMMY_L2,
NET_L2_GET_CTX_TYPE(DUMMY_L2), 127);
static struct net_pkt *prepare_echo_request(struct net_if *iface)
{
struct net_pkt *pkt;
pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_req),
AF_INET, IPPROTO_ICMP, K_FOREVER);
if (!pkt) {
return NULL;
}
if (net_pkt_write(pkt, icmpv4_echo_req, sizeof(icmpv4_echo_req))) {
goto fail;
}
net_pkt_set_overwrite(pkt, true);
net_pkt_cursor_init(pkt);
return pkt;
fail:
net_pkt_unref(pkt);
return NULL;
}
static struct net_pkt *prepare_echo_reply(struct net_if *iface)
{
struct net_pkt *pkt;
pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_rep),
AF_INET, IPPROTO_ICMP, K_FOREVER);
if (!pkt) {
return NULL;
}
if (net_pkt_write(pkt, icmpv4_echo_rep, sizeof(icmpv4_echo_rep))) {
goto fail;
}
net_pkt_set_overwrite(pkt, true);
net_pkt_cursor_init(pkt);
return pkt;
fail:
net_pkt_unref(pkt);
return NULL;
}
static struct net_pkt *prepare_echo_request_with_options(struct net_if *iface)
{
struct net_pkt *pkt;
pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_req_opt),
AF_INET, IPPROTO_ICMP, K_FOREVER);
if (!pkt) {
return NULL;
}
if (net_pkt_write(pkt, icmpv4_echo_req_opt,
sizeof(icmpv4_echo_req_opt))) {
goto fail;
}
net_pkt_set_overwrite(pkt, true);
net_pkt_cursor_init(pkt);
return pkt;
fail:
net_pkt_unref(pkt);
return NULL;
}
static struct net_pkt *prepare_echo_request_with_bad_options(
struct net_if *iface)
{
struct net_pkt *pkt;
pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_req_opt_bad),
AF_INET, IPPROTO_ICMP, K_FOREVER);
if (!pkt) {
return NULL;
}
if (net_pkt_write(pkt, icmpv4_echo_req_opt_bad,
sizeof(icmpv4_echo_req_opt_bad))) {
goto fail;
}
net_pkt_set_overwrite(pkt, true);
net_pkt_cursor_init(pkt);
return pkt;
fail:
net_pkt_unref(pkt);
return NULL;
}
static void test_icmpv4(void)
{
struct net_if_addr *ifaddr;
iface = net_if_get_default();
if (!iface) {
zassert_true(false, "Interface not available");
}
ifaddr = net_if_ipv4_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0);
if (!ifaddr) {
zassert_true(false, "Failed to add address");
}
}
static void test_icmpv4_send_echo_req(void)
{
struct net_pkt *pkt;
current = TEST_ICMPV4_ECHO_REQ;
pkt = prepare_echo_request(iface);
if (!pkt) {
zassert_true(false, "EchoRequest packet prep failed");
}
if (net_ipv4_input(pkt)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
}
static void test_icmpv4_send_echo_rep(void)
{
struct net_pkt *pkt;
net_icmpv4_register_handler(&echo_rep_handler);
pkt = prepare_echo_reply(iface);
if (!pkt) {
zassert_true(false, "EchoReply packet prep failed");
}
if (net_ipv4_input(pkt)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
net_icmpv4_unregister_handler(&echo_rep_handler);
}
static void test_icmpv4_send_echo_req_opt(void)
{
struct net_pkt *pkt;
current = TEST_ICMPV4_ECHO_REQ_OPTS;
pkt = prepare_echo_request_with_options(iface);
if (!pkt) {
zassert_true(false, "EchoRequest with opts packet prep failed");
}
if (net_ipv4_input(pkt)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
}
static void test_icmpv4_send_echo_req_bad_opt(void)
{
struct net_pkt *pkt;
pkt = prepare_echo_request_with_bad_options(iface);
if (!pkt) {
zassert_true(false,
"EchoRequest with bad opts packet prep failed");
}
if (!net_ipv4_input(pkt)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
}
/**test case main entry */
void test_main(void)
{
ztest_test_suite(test_icmpv4_fn,
ztest_unit_test(test_icmpv4));
ztest_unit_test(test_icmpv4),
ztest_unit_test(test_icmpv4_send_echo_req),
ztest_unit_test(test_icmpv4_send_echo_rep),
ztest_unit_test(test_icmpv4_send_echo_req_opt),
ztest_unit_test(test_icmpv4_send_echo_req_bad_opt));
ztest_run_test_suite(test_icmpv4_fn);
}