From fbcdfbee5bd756edd419cfdd53315cc9b60b7c7f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 16 Oct 2017 15:25:42 +0300 Subject: [PATCH 1/3] net: app: Bind to correct address family Use the remote address to determine what address family to bind. This prevents extra context to be created. In order to avoid parsing the peer address string multiple times, the client init function is re-factored. Signed-off-by: Jukka Rissanen --- subsys/net/lib/app/client.c | 286 +++++++++++++++++++++--------------- 1 file changed, 164 insertions(+), 122 deletions(-) diff --git a/subsys/net/lib/app/client.c b/subsys/net/lib/app/client.c index 995e28e8e7d1d..8f62034f514db 100644 --- a/subsys/net/lib/app/client.c +++ b/subsys/net/lib/app/client.c @@ -104,6 +104,95 @@ static int resolve_name(struct net_app_ctx *ctx, } #endif /* CONFIG_DNS_RESOLVER */ +static int try_resolve(struct net_app_ctx *ctx, + const char *peer_addr_str, + enum dns_query_type type, + s32_t timeout) +{ +#if !defined(CONFIG_DNS_RESOLVER) + NET_ERR("Invalid IP address %s", peer_addr_str); + return -EINVAL; +#else + int ret; + + ret = resolve_name(ctx, peer_addr_str, type, timeout); + if (ret < 0) { + NET_ERR("Cannot resolve %s (%d)", peer_addr_str, ret); + } + + return ret; +#endif +} + +static int set_remote_addr(struct net_app_ctx *ctx, + struct sockaddr *remote_addr, + const char *peer_addr_str, + bool peer_addr_ok, + s32_t timeout) +{ + int ret; + + if (peer_addr_ok && remote_addr->sa_family == AF_INET6) { +#if defined(CONFIG_NET_IPV6) + memcpy(&ctx->ipv6.remote, remote_addr, + sizeof(struct sockaddr)); + ctx->default_ctx = &ctx->ipv6; + return 0; +#else + return -EAFNOSUPPORT; +#endif + } + + if (peer_addr_ok && remote_addr->sa_family == AF_INET) { +#if defined(CONFIG_NET_IPV4) + memcpy(&ctx->ipv4.remote, remote_addr, + sizeof(struct sockaddr)); + ctx->default_ctx = &ctx->ipv4; + return 0; +#else + return -EAFNOSUPPORT; +#endif + } + +#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4) + /* Could be hostname, try DNS if configured. */ + ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_AAAA, timeout); + if (ret < 0) { + return ret; + } + + ctx->default_ctx = &ctx->ipv6; + return 0; +#endif /* IPV6 && !IPV4 */ + +#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6) + ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_A, timeout); + if (ret < 0) { + return ret; + } + + ctx->default_ctx = &ctx->ipv4; + return 0; +#endif /* IPV6 && !IPV4 */ + +#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6) + ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_A, timeout); + if (ret < 0) { + ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_AAAA, + timeout); + if (ret < 0) { + return ret; + } + + ctx->default_ctx = &ctx->ipv6; + return 0; + } + + ctx->default_ctx = &ctx->ipv4; + return 0; +#endif /* IPV4 && IPV6 */ +} + static int get_port_number(const char *peer_addr_str, char *buf, size_t buf_len) @@ -168,132 +257,26 @@ static int get_port_number(const char *peer_addr_str, return 0; } -static int set_remote_addr(struct net_app_ctx *ctx, - const char *peer_addr_str, - u16_t peer_port, - s32_t timeout) +static void close_net_ctx(struct net_app_ctx *ctx) { - char addr_str[INET6_ADDRSTRLEN + 1]; - char *addr; - int ret; - - /* If the peer string contains port number, use that and ignore - * the port number parameter. - */ - ret = get_port_number(peer_addr_str, addr_str, sizeof(addr_str)); - if (ret > 0) { - addr = addr_str; - peer_port = ret; - } else { - addr = (char *)peer_addr_str; +#if defined(CONFIG_NET_IPV6) + if (ctx->ipv6.ctx) { + net_context_put(ctx->ipv6.ctx); + ctx->ipv6.ctx = NULL; } - -#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4) - ret = net_addr_pton(AF_INET6, addr, - &net_sin6(&ctx->ipv6.remote)->sin6_addr); - if (ret < 0) { - /* Could be hostname, try DNS if configured. */ -#if !defined(CONFIG_DNS_RESOLVER) - NET_ERR("Invalid IPv6 address %s", addr); - return -EINVAL; -#else - ret = resolve_name(ctx, addr, DNS_QUERY_TYPE_AAAA, timeout); - if (ret < 0) { - NET_ERR("Cannot resolve %s (%d)", addr, ret); - return ret; - } #endif +#if defined(CONFIG_NET_IPV4) + if (ctx->ipv4.ctx) { + net_context_put(ctx->ipv4.ctx); + ctx->ipv4.ctx = NULL; } - - net_sin6(&ctx->ipv6.remote)->sin6_port = htons(peer_port); - net_sin6(&ctx->ipv6.remote)->sin6_family = AF_INET6; - ctx->ipv6.remote.sa_family = AF_INET6; - ctx->default_ctx = &ctx->ipv6; -#endif /* IPV6 && !IPV4 */ - -#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6) - ret = net_addr_pton(AF_INET, addr, - &net_sin(&ctx->ipv4.remote)->sin_addr); - if (ret < 0) { - /* Could be hostname, try DNS if configured. */ -#if !defined(CONFIG_DNS_RESOLVER) - NET_ERR("Invalid IPv4 address %s", addr); - return -EINVAL; -#else - ret = resolve_name(ctx, addr, DNS_QUERY_TYPE_A, timeout); - if (ret < 0) { - NET_ERR("Cannot resolve %s (%d)", addr, ret); - return ret; - } #endif +#if defined(CONFIG_NET_APP_SERVER) + if (ctx->server.net_ctx) { + net_context_put(ctx->server.net_ctx); + ctx->server.net_ctx = NULL; } - - net_sin(&ctx->ipv4.remote)->sin_port = htons(peer_port); - net_sin(&ctx->ipv4.remote)->sin_family = AF_INET; - ctx->ipv4.remote.sa_family = AF_INET; - ctx->default_ctx = &ctx->ipv4; -#endif /* IPV6 && !IPV4 */ - -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6) - ret = net_addr_pton(AF_INET, addr, - &net_sin(&ctx->ipv4.remote)->sin_addr); - if (ret < 0) { - ret = net_addr_pton(AF_INET6, addr, - &net_sin6(&ctx->ipv6.remote)->sin6_addr); - if (ret < 0) { - /* Could be hostname, try DNS if configured. */ -#if !defined(CONFIG_DNS_RESOLVER) - NET_ERR("Invalid IPv4 or IPv6 address %s", addr); - return -EINVAL; -#else - ret = resolve_name(ctx, addr, - DNS_QUERY_TYPE_A, timeout); - if (ret < 0) { - ret = resolve_name(ctx, addr, - DNS_QUERY_TYPE_AAAA, - timeout); - if (ret < 0) { - NET_ERR("Cannot resolve %s (%d)", - addr, ret); - return ret; - } - - goto ipv6; - } - - goto ipv4; -#endif /* !CONFIG_DNS_RESOLVER */ - } else { -#if defined(CONFIG_DNS_RESOLVER) - ipv6: #endif - net_sin6(&ctx->ipv6.remote)->sin6_port = - htons(peer_port); - net_sin6(&ctx->ipv6.remote)->sin6_family = AF_INET6; - ctx->ipv6.remote.sa_family = AF_INET6; - ctx->default_ctx = &ctx->ipv6; - } - } else { -#if defined(CONFIG_DNS_RESOLVER) - ipv4: -#endif - net_sin(&ctx->ipv4.remote)->sin_port = htons(peer_port); - net_sin(&ctx->ipv4.remote)->sin_family = AF_INET; - ctx->ipv4.remote.sa_family = AF_INET; - ctx->default_ctx = &ctx->ipv4; - } -#endif /* IPV4 && IPV6 */ - - /* If we have not yet figured out what is the protocol family, - * then we cannot continue. - */ - if (!ctx->default_ctx || - ctx->default_ctx->remote.sa_family == AF_UNSPEC) { - NET_ERR("Unknown protocol family."); - return -EPFNOSUPPORT; - } - - return 0; } int net_app_init_client(struct net_app_ctx *ctx, @@ -306,8 +289,11 @@ int net_app_init_client(struct net_app_ctx *ctx, s32_t timeout, void *user_data) { + const char *base_peer_addr = peer_addr_str; + char base_addr_str[INET6_ADDRSTRLEN + 1]; + struct sockaddr remote_addr; struct sockaddr addr; - int ret; + int ret, addr_ok = false; if (!ctx) { return -EINVAL; @@ -318,11 +304,54 @@ int net_app_init_client(struct net_app_ctx *ctx, } memset(&addr, 0, sizeof(addr)); + memset(&remote_addr, 0, sizeof(remote_addr)); + + if (peer_addr) { + memcpy(&remote_addr, peer_addr, sizeof(remote_addr)); + } else if (peer_addr_str) { + /* If the peer string contains port number, use that and + * ignore the port number parameter. + */ + ret = get_port_number(peer_addr_str, base_addr_str, + sizeof(base_addr_str)); + if (ret > 0) { + base_peer_addr = base_addr_str; + peer_port = ret; + } else { + strncpy(base_addr_str, peer_addr_str, + sizeof(base_addr_str) - 1); + } + + addr_ok = net_ipaddr_parse(base_peer_addr, + strlen(base_peer_addr), + &remote_addr); + +#if defined(CONFIG_NET_IPV6) + if (remote_addr.sa_family == AF_INET6) { + net_sin6(&remote_addr)->sin6_port = htons(peer_port); + } +#endif +#if defined(CONFIG_NET_IPV4) + if (remote_addr.sa_family == AF_INET) { + net_sin(&remote_addr)->sin_port = htons(peer_port); + } +#endif + + /* The remote_addr will be used by set_remote_addr() to + * set the actual peer address. + */ + } if (client_addr) { memcpy(&addr, client_addr, sizeof(addr)); + + if (addr.sa_family != remote_addr.sa_family) { + NET_DBG("Address family mismatch %d vs %d", + addr.sa_family, remote_addr.sa_family); + return -EINVAL; + } } else { - addr.sa_family = AF_UNSPEC; + addr.sa_family = remote_addr.sa_family; } ctx->app_type = NET_APP_CLIENT; @@ -334,6 +363,7 @@ int net_app_init_client(struct net_app_ctx *ctx, ret = _net_app_config_local_ctx(ctx, sock_type, proto, &addr); if (ret < 0) { + close_net_ctx(ctx); goto fail; } @@ -362,14 +392,26 @@ int net_app_init_client(struct net_app_ctx *ctx, if (!peer_addr_str) { NET_ERR("Cannot know where to connect."); ret = -EINVAL; + close_net_ctx(ctx); goto fail; } - ret = set_remote_addr(ctx, peer_addr_str, peer_port, timeout); + ret = set_remote_addr(ctx, &remote_addr, base_addr_str, + addr_ok, timeout); if (ret < 0) { + close_net_ctx(ctx); goto fail; } + /* If we have not yet figured out what is the protocol family, + * then we cannot continue. + */ + if (!ctx->default_ctx || + ctx->default_ctx->remote.sa_family == AF_UNSPEC) { + NET_ERR("Unknown protocol family."); + return -EPFNOSUPPORT; + } + #if defined(CONFIG_NET_IPV4) if (ctx->ipv4.remote.sa_family == AF_INET) { ctx->ipv4.local.sa_family = AF_INET; From 72ef4728bbd6b1f9f34ee51783716f07fc6696a8 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 17 Oct 2017 12:40:47 +0300 Subject: [PATCH 2/3] net: app: Close context even if there is no connection If there is no connection to server, then _net_app_select_net_ctx() will return NULL. This is perfectly fine and we can just continue. Signed-off-by: Jukka Rissanen --- subsys/net/lib/app/net_app.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/app/net_app.c b/subsys/net/lib/app/net_app.c index b9d6a83436565..c3a6b811044a7 100644 --- a/subsys/net/lib/app/net_app.c +++ b/subsys/net/lib/app/net_app.c @@ -852,9 +852,6 @@ int net_app_close(struct net_app_ctx *ctx) } net_ctx = _net_app_select_net_ctx(ctx, NULL); - if (!net_ctx) { - return -EAFNOSUPPORT; - } if (ctx->cb.close) { ctx->cb.close(ctx, 0, ctx->user_data); @@ -866,7 +863,9 @@ int net_app_close(struct net_app_ctx *ctx) } #endif - net_context_put(net_ctx); + if (net_ctx) { + net_context_put(net_ctx); + } return 0; } From 351627345f9d7483074945f531effba3386cbf93 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 17 Oct 2017 14:56:41 +0300 Subject: [PATCH 3/3] tests: net: app: Simple testcases for net-app testing These are simple tests for net-app testing. These do not try to actually send anything to net but test mainly net-app setup and close functionality. Signed-off-by: Jukka Rissanen --- tests/net/app/Makefile | 4 + tests/net/app/prj-no-ipv4.conf | 32 ++ tests/net/app/prj-no-ipv6.conf | 28 ++ tests/net/app/prj-with-dns.conf | 46 ++ tests/net/app/prj.conf | 35 ++ tests/net/app/src/Makefile | 4 + tests/net/app/src/main.c | 818 ++++++++++++++++++++++++++++++++ tests/net/app/testcase.yaml | 16 + 8 files changed, 983 insertions(+) create mode 100644 tests/net/app/Makefile create mode 100644 tests/net/app/prj-no-ipv4.conf create mode 100644 tests/net/app/prj-no-ipv6.conf create mode 100644 tests/net/app/prj-with-dns.conf create mode 100644 tests/net/app/prj.conf create mode 100644 tests/net/app/src/Makefile create mode 100644 tests/net/app/src/main.c create mode 100644 tests/net/app/testcase.yaml diff --git a/tests/net/app/Makefile b/tests/net/app/Makefile new file mode 100644 index 0000000000000..4b05dca8edb6d --- /dev/null +++ b/tests/net/app/Makefile @@ -0,0 +1,4 @@ +BOARD ?= qemu_x86 +CONF_FILE = prj.conf + +include $(ZEPHYR_BASE)/Makefile.test diff --git a/tests/net/app/prj-no-ipv4.conf b/tests/net/app/prj-no-ipv4.conf new file mode 100644 index 0000000000000..bd8b99ea61388 --- /dev/null +++ b/tests/net/app/prj-no-ipv4.conf @@ -0,0 +1,32 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=n +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_DHCPV4=n +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_IPV6_DAD=n +CONFIG_NET_IPV6_MLD=n +CONFIG_NET_IPV6_ND=n +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=10 +CONFIG_NET_BUF_TX_COUNT=10 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=6 +CONFIG_NET_IPV6_MAX_NEIGHBORS=8 +CONFIG_NET_APP=y +CONFIG_NET_APP_AUTO_INIT=n +CONFIG_NET_APP_SERVER=y +CONFIG_NET_APP_CLIENT=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_ZTEST=y +#CONFIG_NET_DEBUG_APP=y +#CONFIG_SYS_LOG_NET_LEVEL=4 +#CONFIG_NET_SHELL=y diff --git a/tests/net/app/prj-no-ipv6.conf b/tests/net/app/prj-no-ipv6.conf new file mode 100644 index 0000000000000..a8db32f3d0c0b --- /dev/null +++ b/tests/net/app/prj-no-ipv6.conf @@ -0,0 +1,28 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV6=n +CONFIG_NET_IPV4=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_DHCPV4=n +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=10 +CONFIG_NET_BUF_TX_COUNT=10 +CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 +CONFIG_NET_APP=y +CONFIG_NET_APP_AUTO_INIT=n +CONFIG_NET_APP_SERVER=y +CONFIG_NET_APP_CLIENT=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_ZTEST=y +#CONFIG_NET_DEBUG_APP=y +#CONFIG_SYS_LOG_NET_LEVEL=4 +#CONFIG_NET_SHELL=y diff --git a/tests/net/app/prj-with-dns.conf b/tests/net/app/prj-with-dns.conf new file mode 100644 index 0000000000000..6e4eaaf8bb5bf --- /dev/null +++ b/tests/net/app/prj-with-dns.conf @@ -0,0 +1,46 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_DHCPV4=n +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_IPV6_DAD=n +CONFIG_NET_IPV6_MLD=n +CONFIG_NET_IPV6_ND=n +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=10 +CONFIG_NET_BUF_TX_COUNT=10 +CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=6 +CONFIG_NET_IPV6_MAX_NEIGHBORS=8 +CONFIG_NET_APP=y +CONFIG_NET_APP_AUTO_INIT=n +CONFIG_NET_APP_SERVER=y +CONFIG_NET_APP_CLIENT=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_ZTEST=y + +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_RESOLVER_MAX_SERVERS=4 +CONFIG_DNS_NUM_OF_CONCUR_QUERIES=1 +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" +CONFIG_DNS_SERVER2="2001:db8::2" +CONFIG_DNS_SERVER3="192.0.2.2:5353" +CONFIG_DNS_SERVER4="[2001:db8::2]:5353" + +#CONFIG_NET_DEBUG_DNS_RESOLVE=y +#CONFIG_NET_DEBUG_APP=y +#CONFIG_SYS_LOG_NET_LEVEL=4 +#CONFIG_NET_SHELL=y diff --git a/tests/net/app/prj.conf b/tests/net/app/prj.conf new file mode 100644 index 0000000000000..f0f6d9cd6b40e --- /dev/null +++ b/tests/net/app/prj.conf @@ -0,0 +1,35 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_DHCPV4=n +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_IPV6_DAD=n +CONFIG_NET_IPV6_MLD=n +CONFIG_NET_IPV6_ND=n +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=10 +CONFIG_NET_BUF_TX_COUNT=10 +CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=6 +CONFIG_NET_IPV6_MAX_NEIGHBORS=8 +CONFIG_NET_APP=y +CONFIG_NET_APP_AUTO_INIT=n +CONFIG_NET_APP_SERVER=y +CONFIG_NET_APP_CLIENT=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_ZTEST=y +#CONFIG_NET_DEBUG_APP=y +#CONFIG_SYS_LOG_NET_LEVEL=4 +#CONFIG_NET_SHELL=y diff --git a/tests/net/app/src/Makefile b/tests/net/app/src/Makefile new file mode 100644 index 0000000000000..cc0883fd51afe --- /dev/null +++ b/tests/net/app/src/Makefile @@ -0,0 +1,4 @@ +obj-y = main.o +ccflags-y += -I${ZEPHYR_BASE}/subsys/net/ip + +include $(ZEPHYR_BASE)/tests/Makefile.test diff --git a/tests/net/app/src/main.c b/tests/net/app/src/main.c new file mode 100644 index 0000000000000..6d57af31146ee --- /dev/null +++ b/tests/net/app/src/main.c @@ -0,0 +1,818 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#define NET_LOG_ENABLED 1 +#include "net_private.h" + +#if defined(CONFIG_NET_DEBUG_IF) +#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) +#else +#define DBG(fmt, ...) +#endif + +#if defined(CONFIG_NET_IPV6) +/* 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 } } }; + +/* 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 } } }; +#endif + +#if defined(CONFIG_NET_IPV4) +/* Interface 1 addresses IPv4 */ +static struct in_addr my_addr4 = { { { 192, 0, 1, 1 } } }; +#endif + +static struct net_if *iface1; + +static bool test_failed; +static bool test_started; +static struct k_sem wait_data; + +#define WAIT_TIME 250 + +struct net_if_test { + u8_t idx; + u8_t mac_addr[sizeof(struct net_eth_addr)]; + struct net_linkaddr ll_addr; +}; + +static int net_iface_dev_init(struct device *dev) +{ + return 0; +} + +static u8_t *net_iface_get_mac(struct device *dev) +{ + struct net_if_test *data = dev->driver_data; + + if (data->mac_addr[2] == 0x00) { + /* 00-00-5E-00-53-xx Documentation RFC 7042 */ + data->mac_addr[0] = 0x00; + data->mac_addr[1] = 0x00; + data->mac_addr[2] = 0x5E; + data->mac_addr[3] = 0x00; + data->mac_addr[4] = 0x53; + data->mac_addr[5] = sys_rand32_get(); + } + + data->ll_addr.addr = data->mac_addr; + data->ll_addr.len = 6; + + return data->mac_addr; +} + +static void net_iface_init(struct net_if *iface) +{ + u8_t *mac = net_iface_get_mac(net_if_get_device(iface)); + + net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr), + NET_LINK_ETHERNET); +} + +static int sender_iface(struct net_if *iface, struct net_pkt *pkt) +{ + if (!pkt->frags) { + DBG("No data to send!\n"); + return -ENODATA; + } + + if (test_started) { + struct net_if_test *data = iface->dev->driver_data; + + DBG("Sending at iface %d %p\n", net_if_get_by_iface(iface), + iface); + + if (net_pkt_iface(pkt) != iface) { + DBG("Invalid interface %p, expecting %p\n", + net_pkt_iface(pkt), iface); + test_failed = true; + } + + if (net_if_get_by_iface(iface) != data->idx) { + DBG("Invalid interface %d index, expecting %d\n", + data->idx, net_if_get_by_iface(iface)); + test_failed = true; + } + } + + net_pkt_unref(pkt); + + k_sem_give(&wait_data); + + return 0; +} + +struct net_if_test net_iface1_data; + +static struct net_if_api net_iface_api = { + .init = net_iface_init, + .send = sender_iface, +}; + +#define _ETH_L2_LAYER DUMMY_L2 +#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2) + +NET_DEVICE_INIT_INSTANCE(net_iface1_test, + "iface1", + iface1, + net_iface_dev_init, + &net_iface1_data, + NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &net_iface_api, + _ETH_L2_LAYER, + _ETH_L2_CTX_TYPE, + 127); + +static void iface_setup(void) +{ +#if defined(CONFIG_NET_IPV6) + struct net_if_mcast_addr *maddr; +#endif + struct net_if_addr *ifaddr; + int idx; + + /* The semaphore is there to wait the data to be received. */ + k_sem_init(&wait_data, 0, UINT_MAX); + + iface1 = net_if_get_by_index(0); + + ((struct net_if_test *)iface1->dev->driver_data)->idx = 0; + + idx = net_if_get_by_iface(iface1); + zassert_equal(idx, 0, "Invalid index iface1"); + + DBG("Interfaces: [%d] iface1 %p\n", + net_if_get_by_iface(iface1), iface1); + + zassert_not_null(iface1, "Interface 1"); + +#if defined(CONFIG_NET_IPV6) + 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 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"); + } + + 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"); + } +#endif /* IPv6 */ + +#if defined(CONFIG_NET_IPV4) + ifaddr = net_if_ipv4_addr_add(iface1, &my_addr4, + NET_ADDR_MANUAL, 0); + if (!ifaddr) { + DBG("Cannot add IPv4 address %s\n", + net_sprint_ipv4_addr(&my_addr4)); + zassert_not_null(ifaddr, "addr4"); + } +#endif + + net_if_up(iface1); + + /* 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; + + test_started = true; +} + +static void app_init(void) +{ + int ret; + + ret = net_app_init("Test app", 0, 1); + zassert_equal(ret, 0, "app init"); +} + +static struct net_app_ctx udp_server_ctx; +static struct net_app_ctx tcp_server_ctx; + +static void app_udp_server_init(void) +{ + int ret; + + ret = net_app_init_udp_server(&udp_server_ctx, NULL, 42421, NULL); + zassert_equal(ret, 0, "UDP server init"); +} + +static void app_tcp_server_init(void) +{ + int ret; + + ret = net_app_init_tcp_server(&tcp_server_ctx, NULL, 42422, NULL); + zassert_equal(ret, 0, "TCP server init"); +} + +static void app_udp_server_listen(void) +{ + int ret; + + net_app_server_enable(&udp_server_ctx); + + ret = net_app_listen(&udp_server_ctx); + zassert_equal(ret, 0, "UDP listen failed"); +} + +static void app_tcp_server_listen(void) +{ + int ret; + + net_app_server_enable(&tcp_server_ctx); + + ret = net_app_listen(&tcp_server_ctx); + zassert_equal(ret, 0, "TCP listen failed"); +} + +static void app_tcp6_client_peer(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "2001:db8:200::1", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv6 client init"); + + port = ntohs(net_sin6(&ctx.ipv6.remote)->sin6_port); + zassert_equal(port, 42422, "TCP port invalid"); + + ret = net_ipv6_addr_cmp(&net_sin6(&ctx.ipv6.remote)->sin6_addr, + &my_addr2); + zassert_equal(ret, true, "IPv6 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "TCP IPv6 client close"); +#endif +} + +static void app_tcp4_client_peer(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "192.0.1.1", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv4 client init"); + + port = ntohs(net_sin(&ctx.ipv4.remote)->sin_port); + zassert_equal(port, 42422, "TCP port invalid"); + + ret = net_ipv4_addr_cmp(&net_sin(&ctx.ipv4.remote)->sin_addr, + &my_addr4); + zassert_equal(ret, true, "IPv4 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "TCP IPv4 client close"); +#endif +} + +static void app_udp6_client_peer(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "2001:db8:200::1", + 42421, + 0, + NULL); + zassert_equal(ret, 0, "UDP IPv6 client init"); + + port = ntohs(net_sin6(&ctx.ipv6.remote)->sin6_port); + zassert_equal(port, 42421, "UDP port invalid"); + + ret = net_ipv6_addr_cmp(&net_sin6(&ctx.ipv6.remote)->sin6_addr, + &my_addr2); + zassert_equal(ret, true, "IPv6 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "UDP IPv6 client close"); +#endif +} + +static void app_udp4_client_peer(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "192.0.1.1", + 42421, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv4 client init"); + + port = ntohs(net_sin(&ctx.ipv4.remote)->sin_port); + zassert_equal(port, 42421, "UDP port invalid"); + + ret = net_ipv4_addr_cmp(&net_sin(&ctx.ipv4.remote)->sin_addr, + &my_addr4); + zassert_equal(ret, true, "IPv4 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "UDP IPv4 client close"); +#endif +} + +static void app_tcp6_client_peer_with_port(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "[2001:db8:200::1]:1234", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv6 client init"); + + port = ntohs(net_sin6(&ctx.ipv6.remote)->sin6_port); + zassert_equal(port, 1234, "TCP port invalid"); + + ret = net_ipv6_addr_cmp(&net_sin6(&ctx.ipv6.remote)->sin6_addr, + &my_addr2); + zassert_equal(ret, true, "IPv6 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "TCP IPv6 client close"); +#endif +} + +static void app_tcp4_client_peer_with_port(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "192.0.1.1:1234", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv4 client init"); + + port = ntohs(net_sin(&ctx.ipv4.remote)->sin_port); + zassert_equal(port, 1234, "TCP port invalid"); + + ret = net_ipv4_addr_cmp(&net_sin(&ctx.ipv4.remote)->sin_addr, + &my_addr4); + zassert_equal(ret, true, "IPv4 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "TCP IPv4 client close"); +#endif +} + +static void app_udp6_client_peer_with_port(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "[2001:db8:200::1]:9999", + 42421, + 0, + NULL); + zassert_equal(ret, 0, "UDP IPv6 client init"); + + port = ntohs(net_sin6(&ctx.ipv6.remote)->sin6_port); + zassert_equal(port, 9999, "UDP port invalid"); + + ret = net_ipv6_addr_cmp(&net_sin6(&ctx.ipv6.remote)->sin6_addr, + &my_addr2); + zassert_equal(ret, true, "IPv6 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "UDP IPv6 client close"); +#endif +} + +static void app_udp4_client_peer_with_port(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + int port; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "192.0.1.1:9999", + 42421, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv4 client init"); + + port = ntohs(net_sin(&ctx.ipv4.remote)->sin_port); + zassert_equal(port, 9999, "UDP port invalid"); + + ret = net_ipv4_addr_cmp(&net_sin(&ctx.ipv4.remote)->sin_addr, + &my_addr4); + zassert_equal(ret, true, "IPv4 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "UDP IPv4 client close"); +#endif +} + +static void app_tcp6_client_peer_addr(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + struct sockaddr_in6 peer; + int port; + int ret; + + net_ipaddr_copy(&peer.sin6_addr, &my_addr2); + peer.sin6_port = htons(8765); + peer.sin6_family = AF_INET6; + + ret = net_app_init_tcp_client(&ctx, + NULL, + (struct sockaddr *)&peer, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv6 client init"); + + port = ntohs(net_sin6(&ctx.ipv6.remote)->sin6_port); + zassert_equal(port, 8765, "TCP port invalid"); + + ret = net_ipv6_addr_cmp(&net_sin6(&ctx.ipv6.remote)->sin6_addr, + &my_addr2); + zassert_equal(ret, true, "IPv6 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "TCP IPv6 client close"); +#endif +} + +static void app_tcp4_client_peer_addr(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + struct sockaddr_in peer; + int port; + int ret; + + net_ipaddr_copy(&peer.sin_addr, &my_addr4); + peer.sin_port = htons(8765); + peer.sin_family = AF_INET; + + ret = net_app_init_tcp_client(&ctx, + NULL, + (struct sockaddr *)&peer, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "TCP IPv4 client init"); + + port = ntohs(net_sin(&ctx.ipv4.remote)->sin_port); + zassert_equal(port, 8765, "TCP port invalid"); + + ret = net_ipv4_addr_cmp(&net_sin(&ctx.ipv4.remote)->sin_addr, + &my_addr4); + zassert_equal(ret, true, "IPv4 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "TCP IPv4 client close"); +#endif +} + +static void app_udp6_client_peer_addr(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + struct sockaddr_in6 peer; + int port; + int ret; + + net_ipaddr_copy(&peer.sin6_addr, &my_addr2); + peer.sin6_port = htons(8765); + peer.sin6_family = AF_INET6; + + ret = net_app_init_udp_client(&ctx, + NULL, + (struct sockaddr *)&peer, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "UDP IPv6 client init"); + + port = ntohs(net_sin6(&ctx.ipv6.remote)->sin6_port); + zassert_equal(port, 8765, "UDP port invalid"); + + ret = net_ipv6_addr_cmp(&net_sin6(&ctx.ipv6.remote)->sin6_addr, + &my_addr2); + zassert_equal(ret, true, "IPv6 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "UDP IPv6 client close"); +#endif +} + +static void app_udp4_client_peer_addr(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + struct sockaddr_in peer; + int port; + int ret; + + net_ipaddr_copy(&peer.sin_addr, &my_addr4); + peer.sin_port = htons(8765); + peer.sin_family = AF_INET; + + ret = net_app_init_udp_client(&ctx, + NULL, + (struct sockaddr *)&peer, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, 0, "UDP IPv4 client init"); + + port = ntohs(net_sin(&ctx.ipv4.remote)->sin_port); + zassert_equal(port, 8765, "UDP port invalid"); + + ret = net_ipv4_addr_cmp(&net_sin(&ctx.ipv4.remote)->sin_addr, + &my_addr4); + zassert_equal(ret, true, "IPv4 address mismatch"); + + ret = net_app_close(&ctx); + zassert_equal(ret, 0, "UDP IPv4 client close"); +#endif +} + +static void app_tcp6_client_hostname_fail(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, -EINVAL, "TCP IPv6 client init"); +#endif +} + +static void app_tcp4_client_hostname_fail(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, -EINVAL, "TCP IPv4 client init"); +#endif +} + +static void app_udp6_client_hostname_fail(void) +{ +#if defined(CONFIG_NET_IPV6) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, -EINVAL, "UDP IPv6 client init"); +#endif +} + +static void app_udp4_client_hostname_fail(void) +{ +#if defined(CONFIG_NET_IPV4) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + 0, + NULL); + zassert_equal(ret, -EINVAL, "UDP IPv4 client init"); +#endif +} + +static void app_tcp6_client_hostname(void) +{ +#if defined(CONFIG_NET_IPV6) && defined(CONFIG_DNS_RESOLVER) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + MSEC(100), + NULL); + zassert_equal(ret, -ETIMEDOUT, "TCP IPv6 client init"); +#endif +} + +static void app_tcp4_client_hostname(void) +{ +#if defined(CONFIG_NET_IPV4) && defined(CONFIG_DNS_RESOLVER) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_tcp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + MSEC(100), + NULL); + zassert_equal(ret, -ETIMEDOUT, "TCP IPv4 client init"); +#endif +} + +static void app_udp6_client_hostname(void) +{ +#if defined(CONFIG_NET_IPV6) && defined(CONFIG_DNS_RESOLVER) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + MSEC(100), + NULL); + zassert_equal(ret, -ETIMEDOUT, "UDP IPv6 client init"); +#endif +} + +static void app_udp4_client_hostname(void) +{ +#if defined(CONFIG_NET_IPV4) && defined(CONFIG_DNS_RESOLVER) + static struct net_app_ctx ctx; + int ret; + + ret = net_app_init_udp_client(&ctx, + NULL, + NULL, + "foobar", + 42422, + MSEC(100), + NULL); + zassert_equal(ret, -ETIMEDOUT, "UDP IPv4 client init"); +#endif +} + +static void app_close_server(void) +{ + int ret; + + ret = net_app_close(&udp_server_ctx); + zassert_equal(ret, 0, "UDP server close"); + + ret = net_app_close(&tcp_server_ctx); + zassert_equal(ret, 0, "TCP server close"); +} + +void test_main(void) +{ + ztest_test_suite(net_app_test, + ztest_unit_test(iface_setup), + ztest_unit_test(app_init), + ztest_unit_test(app_udp_server_init), + ztest_unit_test(app_tcp_server_init), + ztest_unit_test(app_udp_server_listen), + ztest_unit_test(app_tcp_server_listen), + ztest_unit_test(app_tcp6_client_peer), + ztest_unit_test(app_udp6_client_peer), + ztest_unit_test(app_tcp4_client_peer), + ztest_unit_test(app_udp4_client_peer), + ztest_unit_test(app_tcp6_client_peer_with_port), + ztest_unit_test(app_tcp4_client_peer_with_port), + ztest_unit_test(app_udp6_client_peer_with_port), + ztest_unit_test(app_udp4_client_peer_with_port), + ztest_unit_test(app_tcp6_client_peer_addr), + ztest_unit_test(app_tcp4_client_peer_addr), + ztest_unit_test(app_udp6_client_peer_addr), + ztest_unit_test(app_udp4_client_peer_addr), + ztest_unit_test(app_tcp6_client_hostname_fail), + ztest_unit_test(app_tcp4_client_hostname_fail), + ztest_unit_test(app_udp6_client_hostname_fail), + ztest_unit_test(app_udp4_client_hostname_fail), + ztest_unit_test(app_tcp6_client_hostname), + ztest_unit_test(app_tcp4_client_hostname), + ztest_unit_test(app_udp6_client_hostname), + ztest_unit_test(app_udp4_client_hostname), + ztest_unit_test(app_close_server) + ); + + ztest_run_test_suite(net_app_test); +} diff --git a/tests/net/app/testcase.yaml b/tests/net/app/testcase.yaml new file mode 100644 index 0000000000000..e1a7e1cb6fb3c --- /dev/null +++ b/tests/net/app/testcase.yaml @@ -0,0 +1,16 @@ +tests: + - test: + min_ram: 32 + tags: net + - test-no-ipv6: + extra_args: CONF_FILE=prj-no-ipv6.conf + min_ram: 32 + tags: net + - test-no-ipv4: + extra_args: CONF_FILE=prj-no-ipv4.conf + min_ram: 32 + tags: net + - test-with-dns: + extra_args: CONF_FILE=prj-with-dns.conf + min_ram: 32 + tags: net dns