diff --git a/tests/net/udp/Makefile b/tests/net/udp/Makefile new file mode 100644 index 00000000000..fa7f724b6bb --- /dev/null +++ b/tests/net/udp/Makefile @@ -0,0 +1,6 @@ +BOARD ?= qemu_x86 +MDEF_FILE = prj.mdef +KERNEL_TYPE ?= nano +CONF_FILE = prj_$(ARCH).conf + +include $(ZEPHYR_BASE)/Makefile.inc diff --git a/tests/net/udp/prj.mdef b/tests/net/udp/prj.mdef new file mode 100644 index 00000000000..648f29b5c4e --- /dev/null +++ b/tests/net/udp/prj.mdef @@ -0,0 +1,5 @@ +% Application : Network test + +% TASK NAME PRIO ENTRY STACK GROUPS +% =================================================== + TASK MAIN 7 main 2048 [EXE] diff --git a/tests/net/udp/prj_x86.conf b/tests/net/udp/prj_x86.conf new file mode 100644 index 00000000000..2b0dad5b8b1 --- /dev/null +++ b/tests/net/udp/prj_x86.conf @@ -0,0 +1,25 @@ +CONFIG_NETWORKING=y +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_UDP=y +CONFIG_NET_MAX_CONN=64 +CONFIG_NET_CONN_CACHE=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_YAIP=y +CONFIG_NET_BUF=y +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_NET_NBUF_RX_COUNT=5 +CONFIG_NET_NBUF_TX_COUNT=5 +CONFIG_NET_NBUF_DATA_COUNT=10 +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_IPV6_NO_ND=y +CONFIG_NET_IFACE_UNICAST_IPV6_ADDR_COUNT=2 +CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=2 +CONFIG_NETWORK_IP_STACK_DEBUG_CORE=y +CONFIG_NETWORK_IP_STACK_DEBUG_UDP=y +CONFIG_NETWORK_IP_STACK_DEBUG_CONN=y +#CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF=y +#CONFIG_NETWORK_IP_STACK_DEBUG_IF=y +#CONFIG_NETWORK_IP_STACK_DEBUG_L2=y diff --git a/tests/net/udp/src/Makefile b/tests/net/udp/src/Makefile new file mode 100644 index 00000000000..47ea26fa4c4 --- /dev/null +++ b/tests/net/udp/src/Makefile @@ -0,0 +1,2 @@ +obj-y = main.o +ccflags-y += -I${srctree}/net/yaip diff --git a/tests/net/udp/src/main.c b/tests/net/udp/src/main.c new file mode 100644 index 00000000000..685baad6bf5 --- /dev/null +++ b/tests/net/udp/src/main.c @@ -0,0 +1,563 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NET_DEBUG 1 + +#include "udp.h" +#include "net_private.h" + +static bool fail = true; +static struct nano_sem recv_lock; + +struct net_udp_context { + uint8_t mac_addr[sizeof(struct net_eth_addr)]; + struct net_linkaddr ll_addr; +}; + +int net_udp_dev_init(struct device *dev) +{ + struct net_udp_context *net_udp_context = dev->driver_data; + + net_udp_context = net_udp_context; + + return 0; +} + +static uint8_t *net_udp_get_mac(struct device *dev) +{ + struct net_udp_context *context = dev->driver_data; + + if (context->mac_addr[0] == 0x00) { + /* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */ + context->mac_addr[0] = 0x10; + context->mac_addr[1] = 0x00; + context->mac_addr[2] = 0x00; + context->mac_addr[3] = 0x00; + context->mac_addr[4] = 0x00; + context->mac_addr[5] = sys_rand32_get(); + } + + return context->mac_addr; +} + +static void net_udp_iface_init(struct net_if *iface) +{ + uint8_t *mac = net_udp_get_mac(net_if_get_device(iface)); + + net_if_set_link_addr(iface, mac, 8); +} + +static int send_status = -EINVAL; + +static int tester_send(struct net_if *iface, struct net_buf *buf) +{ + if (!buf->frags) { + printk("No data to send!\n"); + return -ENODATA; + } + + printk("Data was sent successfully\n"); + + net_nbuf_unref(buf); + + send_status = 0; + + return 0; +} + +static inline struct in_addr *if_get_addr(struct net_if *iface) +{ + int i; + + for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + if (iface->ipv4.unicast[i].is_used && + iface->ipv4.unicast[i].address.family == AF_INET && + iface->ipv4.unicast[i].addr_state == NET_ADDR_PREFERRED) { + return &iface->ipv4.unicast[i].address.in_addr; + } + } + + return NULL; +} + +struct net_udp_context net_udp_context_data; + +static struct net_if_api net_udp_if_api = { + .init = net_udp_iface_init, + .send = tester_send, +}; + +#define _ETH_L2_LAYER DUMMY_L2 + +NET_DEVICE_INIT(net_udp_test, "net_udp_test", + net_udp_dev_init, &net_udp_context_data, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &net_udp_if_api, _ETH_L2_LAYER, 127); + +struct ud { + const struct net_addr *remote_addr; + const struct net_addr *local_addr; + uint16_t remote_port; + uint16_t local_port; + char *test; + void *handle; +}; + +static struct ud *returned_ud; + +static enum net_verdict test_ok(struct net_buf *buf, void *user_data) +{ + struct ud *ud = (struct ud *)user_data; + + nano_sem_give(&recv_lock); + + if (!ud) { + fail = true; + + printk("Test %s failed.", ud->test); + + return NET_DROP; + } + + fail = false; + + returned_ud = user_data; + + net_nbuf_unref(buf); + + return NET_OK; +} + +static enum net_verdict test_fail(struct net_buf *buf, void *user_data) +{ + /* This function should never be called as there should not + * be a matching UDP connection. + */ + + fail = true; + return NET_DROP; +} + +static void setup_ipv6_udp(struct net_buf *buf, + struct in6_addr *remote_addr, + struct in6_addr *local_addr, + uint16_t remote_port, + uint16_t local_port) +{ + NET_IPV6_BUF(buf)->vtc = 0x60; + NET_IPV6_BUF(buf)->tcflow = 0; + NET_IPV6_BUF(buf)->flow = 0; + NET_IPV6_BUF(buf)->len[0] = 0; + NET_IPV6_BUF(buf)->len[1] = NET_UDPH_LEN; + + NET_IPV6_BUF(buf)->nexthdr = IPPROTO_UDP; + NET_IPV6_BUF(buf)->hop_limit = 255; + + net_ipaddr_copy(&NET_IPV6_BUF(buf)->src, remote_addr); + net_ipaddr_copy(&NET_IPV6_BUF(buf)->dst, local_addr); + + net_nbuf_ip_hdr_len(buf) = sizeof(struct net_ipv6_hdr); + + NET_UDP_BUF(buf)->src_port = htons(remote_port); + NET_UDP_BUF(buf)->dst_port = htons(local_port); + + net_nbuf_ext_len(buf) = 0; + + net_buf_add(buf->frags, net_nbuf_ip_hdr_len(buf) + + sizeof(struct net_udp_hdr)); +} + +static void setup_ipv4_udp(struct net_buf *buf, + struct in_addr *remote_addr, + struct in_addr *local_addr, + uint16_t remote_port, + uint16_t local_port) +{ + NET_IPV4_BUF(buf)->vhl = 0x45; + NET_IPV4_BUF(buf)->tos = 0; + NET_IPV4_BUF(buf)->len[0] = 0; + NET_IPV4_BUF(buf)->len[1] = NET_UDPH_LEN + + sizeof(struct net_ipv4_hdr); + + NET_IPV4_BUF(buf)->proto = IPPROTO_UDP; + + net_ipaddr_copy(&NET_IPV4_BUF(buf)->src, remote_addr); + net_ipaddr_copy(&NET_IPV4_BUF(buf)->dst, local_addr); + + net_nbuf_ip_hdr_len(buf) = sizeof(struct net_ipv4_hdr); + + NET_UDP_BUF(buf)->src_port = htons(remote_port); + NET_UDP_BUF(buf)->dst_port = htons(local_port); + + net_nbuf_ext_len(buf) = 0; + + net_buf_add(buf->frags, net_nbuf_ip_hdr_len(buf) + + sizeof(struct net_udp_hdr)); +} + +#define TIMEOUT (sys_clock_ticks_per_sec / 6) + +static bool send_ipv6_udp_msg(struct net_if *iface, + struct in6_addr *src, + struct in6_addr *dst, + uint16_t src_port, + uint16_t dst_port, + struct ud *ud, + bool expect_failure) +{ + struct net_buf *buf; + struct net_buf *frag; + int ret; + + buf = net_nbuf_get_reserve_tx(0); + frag = net_nbuf_get_reserve_data(0); + net_buf_frag_add(buf, frag); + + net_nbuf_iface(buf) = iface; + net_nbuf_ll_reserve(buf) = net_buf_headroom(frag); + + setup_ipv6_udp(buf, src, dst, src_port, dst_port); + + ret = net_recv_data(iface, buf); + if (ret < 0) { + printk("Cannot recv buf %p, ret %d\n", buf, ret); + return false; + } + + if (!nano_sem_take(&recv_lock, TIMEOUT)) { + printk("Timeout, packet not received\n"); + if (expect_failure) { + return false; + } else { + return true; + } + } + + /* Check that the returned user data is the same as what was given + * as a parameter. + */ + if (ud != returned_ud && !expect_failure) { + printk("IPv6 wrong user data %p returned, expected %p\n", + returned_ud, ud); + return false; + } + + return !fail; +} + +static bool send_ipv4_udp_msg(struct net_if *iface, + struct in_addr *src, + struct in_addr *dst, + uint16_t src_port, + uint16_t dst_port, + struct ud *ud, + bool expect_failure) +{ + struct net_buf *buf; + struct net_buf *frag; + int ret; + + buf = net_nbuf_get_reserve_tx(0); + frag = net_nbuf_get_reserve_data(0); + net_buf_frag_add(buf, frag); + + net_nbuf_iface(buf) = iface; + net_nbuf_ll_reserve(buf) = net_buf_headroom(frag); + + setup_ipv4_udp(buf, src, dst, src_port, dst_port); + + ret = net_recv_data(iface, buf); + if (ret < 0) { + printk("Cannot recv buf %p, ret %d\n", buf, ret); + return false; + } + + if (!nano_sem_take(&recv_lock, TIMEOUT)) { + printk("Timeout, packet not received\n"); + if (expect_failure) { + return false; + } else { + return true; + } + } + + /* Check that the returned user data is the same as what was given + * as a parameter. + */ + if (ud != returned_ud && !expect_failure) { + printk("IPv4 wrong user data %p returned, expected %p\n", + returned_ud, ud); + return false; + } + + return !fail; +} + +void main_fiber(void) +{ + void *handlers[CONFIG_NET_MAX_CONN]; + struct net_if *iface = net_if_get_default();; + struct net_if_addr *ifaddr; + struct ud *ud; + int ret, i = 0; + bool st; + + struct net_addr any_addr6; + const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; + + struct net_addr my_addr6; + struct in6_addr in6addr_my = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + + struct net_addr peer_addr6; + struct in6_addr in6addr_peer = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0x4e, 0x11, 0, 0, 0x2 } } }; + + struct net_addr any_addr4; + const struct in_addr in4addr_any = { { { 0 } } }; + + struct net_addr my_addr4; + struct in_addr in4addr_my = { { { 192, 0, 2, 1 } } }; + + struct net_addr peer_addr4; + struct in_addr in4addr_peer = { { { 192, 0, 2, 9 } } }; + + net_ipaddr_copy(&any_addr6.in6_addr, &in6addr_any); + any_addr6.family = AF_INET6; + + net_ipaddr_copy(&my_addr6.in6_addr, &in6addr_my); + my_addr6.family = AF_INET6; + + net_ipaddr_copy(&peer_addr6.in6_addr, &in6addr_peer); + peer_addr6.family = AF_INET6; + + net_ipaddr_copy(&any_addr4.in_addr, &in4addr_any); + any_addr4.family = AF_INET; + + net_ipaddr_copy(&my_addr4.in_addr, &in4addr_my); + my_addr4.family = AF_INET; + + net_ipaddr_copy(&peer_addr4.in_addr, &in4addr_peer); + peer_addr4.family = AF_INET; + + nano_sem_init(&recv_lock); + + ifaddr = net_if_ipv6_addr_add(iface, &in6addr_my, NET_ADDR_MANUAL, 0); + if (!ifaddr) { + printk("Cannot add %s to interface %p\n", + net_sprint_ipv6_addr(&in6addr_my)); + return; + } + + ifaddr = net_if_ipv4_addr_add(iface, &in4addr_my, NET_ADDR_MANUAL, 0); + if (!ifaddr) { + printk("Cannot add %s to interface %p\n", + net_sprint_ipv4_addr(&in4addr_my)); + return; + } + +#define REGISTER(raddr, laddr, rport, lport) \ + ({ \ + static struct ud user_data; \ + \ + user_data.remote_addr = raddr; \ + user_data.local_addr = laddr; \ + user_data.remote_port = rport; \ + user_data.local_port = lport; \ + user_data.test = #raddr"-"#laddr"-"#rport"-"#lport; \ + \ + ret = net_udp_register(raddr, laddr, rport, lport, \ + test_ok, &user_data, \ + &handlers[i]); \ + if (ret) { \ + printk("UDP register %s failed (%d)\n", \ + user_data.test, ret); \ + return; \ + } \ + user_data.handle = handlers[i++]; \ + &user_data; \ + }) + +#define REGISTER_FAIL(raddr, laddr, rport, lport) \ + ret = net_udp_register(raddr, laddr, rport, lport, test_fail, \ + INT_TO_POINTER(0), NULL); \ + if (!ret) { \ + printk("UDP register invalid match %s failed\n", \ + #raddr"-"#laddr"-"#rport"-"#lport); \ + return; \ + } + +#define UNREGISTER(ud) \ + ret = net_udp_unregister(ud->handle); \ + if (ret) { \ + printk("UDP unregister %p failed (%d)\n", ud->handle, \ + ret); \ + return; \ + } + +#define TEST_IPV6_OK(ud, raddr, laddr, rport, lport) \ + st = send_ipv6_udp_msg(iface, raddr, laddr, rport, lport, ud, \ + false); \ + if (!st) { \ + printk("%d: UDP test \"%s\" fail\n", __LINE__, \ + ud->test); \ + return; \ + } + +#define TEST_IPV4_OK(ud, raddr, laddr, rport, lport) \ + st = send_ipv4_udp_msg(iface, raddr, laddr, rport, lport, ud, \ + false); \ + if (!st) { \ + printk("%d: UDP test \"%s\" fail\n", __LINE__, \ + ud->test); \ + return; \ + } + +#define TEST_IPV6_FAIL(ud, raddr, laddr, rport, lport) \ + st = send_ipv6_udp_msg(iface, raddr, laddr, rport, lport, ud, \ + true); \ + if (st) { \ + printk("%d: UDP neg test \"%s\" fail\n", __LINE__, \ + ud->test); \ + return; \ + } + +#define TEST_IPV4_FAIL(ud, raddr, laddr, rport, lport) \ + st = send_ipv4_udp_msg(iface, raddr, laddr, rport, lport, ud, \ + true); \ + if (st) { \ + printk("%d: UDP neg test \"%s\" fail\n", __LINE__, \ + ud->test); \ + return; \ + } + + ud = REGISTER(&any_addr6, &any_addr6, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); + UNREGISTER(ud); + + ud = REGISTER(&any_addr4, &any_addr4, 1234, 4242); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 4242); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 4242); + TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 1234, 4325); + TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 1234, 4325); + UNREGISTER(ud); + + ud = REGISTER(&any_addr6, NULL, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); + UNREGISTER(ud); + + ud = REGISTER(NULL, &any_addr6, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); + UNREGISTER(ud); + + ud = REGISTER(&peer_addr6, &my_addr6, 1234, 4242); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 4243); + + ud = REGISTER(&peer_addr4, &my_addr4, 1234, 4242); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 4242); + TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 1234, 4243); + + ud = REGISTER(NULL, NULL, 1234, 42423); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 42423); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 42423); + + ud = REGISTER(NULL, NULL, 1234, 0); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 42422); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 42422); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 42422); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 42422); + + TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 12345, 42421); + TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 12345, 42421); + + ud = REGISTER(NULL, NULL, 0, 0); + TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 12345, 42421); + TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421); + + /* Remote addr same as local addr, these two will never match */ + REGISTER(&my_addr6, NULL, 1234, 4242); + REGISTER(&my_addr4, NULL, 1234, 4242); + + /* IPv4 remote addr and IPv6 remote addr, impossible combination */ + REGISTER_FAIL(&my_addr4, &my_addr6, 1234, 4242); + + if (fail) { + printk("Tests failed\n"); + return; + } + + i--; + while (i) { + ret = net_udp_unregister(handlers[i]); + if (ret < 0 && ret != -ENOENT) { + printk("Cannot unregister udp %d\n", i); + return; + } + + i--; + } + + if (!(net_udp_unregister(NULL) < 0)) { + printk("Unregister udp failed\n"); + return; + } + + printk("Network UDP checks passed\n"); +} + +#if defined(CONFIG_NANOKERNEL) +#define STACKSIZE 2000 +char __noinit __stack fiberStack[STACKSIZE]; +#endif + +void main(void) +{ +#if defined(CONFIG_MICROKERNEL) + main_fiber(); +#else + task_fiber_start(&fiberStack[0], STACKSIZE, + (nano_fiber_entry_t)main_fiber, 0, 0, 7, 0); +#endif +} diff --git a/tests/net/udp/testcase.ini b/tests/net/udp/testcase.ini new file mode 100644 index 00000000000..04148cf38aa --- /dev/null +++ b/tests/net/udp/testcase.ini @@ -0,0 +1,6 @@ +[test] +tags = net-udp +build_only = true +arch_whitelist = x86 +# Doesn't work for ia32_pci +filter = CONFIG_SOC : "ia32"