diff --git a/tests/net/icmpv4/prj.conf b/tests/net/icmpv4/prj.conf index 3146b227d65..a3d298070d3 100644 --- a/tests/net/icmpv4/prj.conf +++ b/tests/net/icmpv4/prj.conf @@ -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 diff --git a/tests/net/icmpv4/src/main.c b/tests/net/icmpv4/src/main.c index d1e0c06a75f..f87cb062c2c 100644 --- a/tests/net/icmpv4/src/main.c +++ b/tests/net/icmpv4/src/main.c @@ -19,15 +19,15 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_ICMPV4_LOG_LEVEL); #include #include +#include +#include #include "net_private.h" #include "icmpv4.h" +#include "ipv4.h" #include -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); }