diff --git a/samples/net/echo_client/prj_bt.conf b/samples/net/echo_client/prj_bt.conf index c22af9e8bda..501987e80c6 100644 --- a/samples/net/echo_client/prj_bt.conf +++ b/samples/net/echo_client/prj_bt.conf @@ -31,6 +31,9 @@ CONFIG_NET_MGMT_EVENT=y CONFIG_NET_SHELL=y CONFIG_NET_L2_BLUETOOTH_SHELL=y +CONFIG_NET_APP=y +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_CLIENT=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" diff --git a/samples/net/echo_client/prj_frdm_k64f_cc2520.conf b/samples/net/echo_client/prj_frdm_k64f_cc2520.conf index 14daff549d1..0c6f2f1037d 100644 --- a/samples/net/echo_client/prj_frdm_k64f_cc2520.conf +++ b/samples/net/echo_client/prj_frdm_k64f_cc2520.conf @@ -49,6 +49,9 @@ CONFIG_IEEE802154_CC2520_SPI_DRV_NAME="SPI_0" CONFIG_IEEE802154_CC2520_SPI_FREQ=4000000 CONFIG_IEEE802154_CC2520_SPI_SLAVE=0 +CONFIG_NET_APP=y +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_CLIENT=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" diff --git a/samples/net/echo_client/prj_qemu_x86.conf b/samples/net/echo_client/prj_qemu_x86.conf index 5081c1ded86..faef753d104 100644 --- a/samples/net/echo_client/prj_qemu_x86.conf +++ b/samples/net/echo_client/prj_qemu_x86.conf @@ -13,17 +13,25 @@ CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_INIT_STACKS=y CONFIG_PRINTK=y CONFIG_NET_STATISTICS=y -CONFIG_NET_PKT_RX_COUNT=10 -CONFIG_NET_PKT_TX_COUNT=10 -CONFIG_NET_BUF_RX_COUNT=20 -CONFIG_NET_BUF_TX_COUNT=20 +CONFIG_NET_PKT_RX_COUNT=50 +CONFIG_NET_PKT_TX_COUNT=50 +CONFIG_NET_BUF_RX_COUNT=50 +CONFIG_NET_BUF_TX_COUNT=50 CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 CONFIG_NET_MAX_CONTEXTS=10 CONFIG_NET_SHELL=y +CONFIG_NET_APP=y +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_NEED_IPV4=y +CONFIG_NET_APP_CLIENT=y CONFIG_NET_APP_SETTINGS=y + +# The addresses are selected so that qemu<->qemu connectivity works ok. +# For linux<->qemu connectivity, create a new conf file and swap the +# addresses (so that peer address is ending to 2). CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::2" CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::1" CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.2" diff --git a/samples/net/echo_client/prj_qemu_x86_tls.conf b/samples/net/echo_client/prj_qemu_x86_tls.conf new file mode 100644 index 00000000000..0d35c0dd693 --- /dev/null +++ b/samples/net/echo_client/prj_qemu_x86_tls.conf @@ -0,0 +1,48 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_UDP=n +CONFIG_NET_TCP=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_BUF_LOG=y +CONFIG_SYS_LOG_NET_BUF_LEVEL=2 +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_NET_LEVEL=2 +CONFIG_NET_SLIP_TAP=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_INIT_STACKS=y +CONFIG_PRINTK=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_PKT_RX_COUNT=50 +CONFIG_NET_PKT_TX_COUNT=50 +CONFIG_NET_BUF_RX_COUNT=50 +CONFIG_NET_BUF_TX_COUNT=50 +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=4 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 +CONFIG_NET_MAX_CONTEXTS=10 + +CONFIG_NET_SHELL=y + +CONFIG_NET_APP=y +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_NEED_IPV4=y +CONFIG_NET_APP_CLIENT=y +CONFIG_NET_APP_SETTINGS=y + +# The addresses are selected here so that qemu<->linux connectivity works ok. +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" + +CONFIG_NET_APP_TLS=y + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=30000 +CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h" + +CONFIG_RAM_SIZE=300 + +CONFIG_NET_DEBUG_NET_PKT=y diff --git a/samples/net/echo_client/src/Makefile b/samples/net/echo_client/src/Makefile index db94b14b72b..46b2892f5bc 100644 --- a/samples/net/echo_client/src/Makefile +++ b/samples/net/echo_client/src/Makefile @@ -1,33 +1,11 @@ -obj-y = echo-client.o +# +# Copyright (c) 2017 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# -ifeq ($(CONFIG_IEEE802154_CC2520),y) +include $(ZEPHYR_BASE)/samples/net/common/Makefile.common -ifeq ($(CONFIG_BOARD_ARDUINO_101),y) -ccflags-y +=-I${ZEPHYR_BASE}/include/drivers/ -obj-y += ../../common/cc2520_a101.o -endif - -ifeq ($(CONFIG_BOARD_FRDM_K64F),y) -ccflags-y +=-I${ZEPHYR_BASE}/drivers/ -ccflags-y +=-I${ZEPHYR_BASE}/include/drivers/ -obj-y += ../../common/cc2520_frdm_k64f.o -endif - -endif - -ifeq ($(CONFIG_NET_TESTING), y) -ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/ -ccflags-y +=-DNET_TESTING_SERVER=0 -endif - -ifeq ($(CONFIG_NET_L2_BLUETOOTH), y) -ccflags-y +=-I${ZEPHYR_BASE}/samples/bluetooth/ -obj-y += ../../../bluetooth/gatt/ipss.o -endif - -ifeq ($(CONFIG_NET_L2_IEEE802154), y) -ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/ -ifeq ($(CONFIG_NET_APP_SETTINGS), y) -obj-y += ../../common/ieee802154_settings.o -endif -endif +obj-y += echo-client.o +obj-$(CONFIG_NET_UDP) += udp.o +obj-$(CONFIG_NET_TCP) += tcp.o diff --git a/samples/net/echo_client/src/common.h b/samples/net/echo_client/src/common.h new file mode 100644 index 00000000000..463897734f9 --- /dev/null +++ b/samples/net/echo_client/src/common.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Value of 0 will cause the IP stack to select next free port */ +#define MY_PORT 0 + +#define PEER_PORT 4242 + +#define WAIT_TIME K_SECONDS(10) +#define CONNECT_TIME K_SECONDS(10) + +struct data { + /* Work controlling udp data sending */ + struct k_delayed_work recv; + struct net_app_ctx *udp; + + const char *proto; + u32_t expecting_udp; + u32_t expecting_tcp; + u32_t received_tcp; +}; + +struct configs { + struct data ipv4; + struct data ipv6; +}; + +#if !defined(CONFIG_NET_APP_PEER_IPV4_ADDR) +#define CONFIG_NET_APP_PEER_IPV4_ADDR "" +#endif + +#if !defined(CONFIG_NET_APP_PEER_IPV6_ADDR) +#define CONFIG_NET_APP_PEER_IPV6_ADDR "" +#endif + +extern const char lorem_ipsum[]; +extern int ipsum_len; +extern struct configs conf; +extern struct k_sem tcp_ready; + +void start_udp(void); +void stop_udp(void); + +int start_tcp(void); +void stop_tcp(void); + +struct net_pkt *prepare_send_pkt(struct net_app_ctx *ctx, + const char *name, + int expecting_len); +void panic(const char *msg); diff --git a/samples/net/echo_client/src/echo-client.c b/samples/net/echo_client/src/echo-client.c index 3f1db74ad71..da0a26c9da6 100644 --- a/samples/net/echo_client/src/echo-client.c +++ b/samples/net/echo_client/src/echo-client.c @@ -1,7 +1,7 @@ /* echo-client.c - Networking echo client */ /* - * Copyright (c) 2016 Intel Corporation. + * Copyright (c) 2017 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,9 @@ * and echo-server is run in the host acting as a server. The client will send * either unicast or multicast packets to the server which will reply the packet * back to the originator. + * + * In this sample application we create four threads that start to send data. + * This might not be what you want to do in your app so caveat emptor. */ #if 1 @@ -20,15 +23,14 @@ #endif #include -#include #include #include #include -#include #include #include -#include + +#include #if defined(CONFIG_NET_L2_BLUETOOTH) #include @@ -39,10 +41,14 @@ #include #endif +#include "common.h" + +#define APP_BANNER "Run echo client" + /* Generated by http://www.lipsum.com/ * 3 paragraphs, 176 words, 1230 bytes of Lorem Ipsum */ -static char *lorem_ipsum = +const char lorem_ipsum[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " "Vestibulum id cursus felis, sit amet suscipit velit. Integer " "facilisis malesuada porta. Nunc at accumsan mauris. Etiam vehicula, " @@ -68,871 +74,120 @@ static char *lorem_ipsum = "Phasellus efficitur imperdiet metus." "\n"; -#define STACKSIZE 2048 +int ipsum_len = sizeof(lorem_ipsum) - 1; -static int ipsum_len; - -/* Note that both tcp and udp can share the same pool but in this - * example the UDP context and TCP context have separate pools. - */ -#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) -#if defined(CONFIG_NET_TCP) -NET_PKT_TX_SLAB_DEFINE(echo_tx_tcp, 15); -NET_PKT_DATA_POOL_DEFINE(echo_data_tcp, 30); - -static struct k_mem_slab *tx_tcp_slab(void) -{ - return &echo_tx_tcp; -} - -static struct net_buf_pool *data_tcp_pool(void) -{ - return &echo_data_tcp; -} -#endif - -#if defined(CONFIG_NET_UDP) -NET_PKT_TX_SLAB_DEFINE(echo_tx_udp, 5); -NET_PKT_DATA_POOL_DEFINE(echo_data_udp, 20); - -static struct k_mem_slab *tx_udp_slab(void) -{ - return &echo_tx_udp; -} - -static struct net_buf_pool *data_udp_pool(void) -{ - return &echo_data_udp; -} -#endif -#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ - -#define MY_PORT 8484 -#define PEER_PORT 4242 - -struct data { - u32_t expecting_udp; - u32_t expecting_tcp; - u32_t received_tcp; +struct configs conf = { + .ipv4 = { + .proto = "IPv4", + }, + .ipv6 = { + .proto = "IPv6", + }, }; -static struct { -#if defined(CONFIG_NET_UDP) - /* semaphore for controlling udp data sending */ - struct k_sem recv_ipv6; - struct k_sem recv_ipv4; -#endif /* CONFIG_NET_UDP */ +static struct k_sem quit_lock; +struct k_sem tcp_ready; - struct data ipv4; - struct data ipv6; -} conf; - -#if defined(CONFIG_NET_TCP) -static bool send_tcp_data(struct net_context *ctx, - char *proto, - struct data *data); -#endif /* CONFIG_NET_TCP */ - -#if defined(CONFIG_NET_IPV6) -/* Define the peer IP address where to send messages */ -#define PEER_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0x2 } } } - -#define MY_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0x1 } } } - -#define MY_PREFIX_LEN 64 - -#if defined(CONFIG_NET_APP_SETTINGS) -static struct in6_addr in6addr_my = MY_IP6ADDR; -static struct in6_addr in6addr_peer = PEER_IP6ADDR; -#endif - -static struct sockaddr_in6 my_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = htons(MY_PORT), -}; - -static struct sockaddr_in6 peer_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = htons(PEER_PORT), -}; - -#if defined(CONFIG_NET_UDP) -static K_THREAD_STACK_DEFINE(ipv6_udp_stack, STACKSIZE); -static struct k_thread ipv6_udp_thread_data; -#endif - -#if defined(CONFIG_NET_TCP) -static K_THREAD_STACK_DEFINE(ipv6_tcp_stack, STACKSIZE); -static struct k_thread ipv6_tcp_thread_data; -#endif - -#endif /* CONFIG_NET_IPV6 */ - -#if defined(CONFIG_NET_IPV4) -#define MY_IP4ADDR { { { 192, 0, 2, 1 } } } -#define PEER_IP4ADDR { { { 192, 0, 2, 2 } } } - -#if defined(CONFIG_NET_APP_SETTINGS) -static struct in_addr in4addr_my = MY_IP4ADDR; -static struct in_addr in4addr_peer = PEER_IP4ADDR; -#endif - -static struct sockaddr_in my_addr4 = { - .sin_family = AF_INET, - .sin_port = htons(MY_PORT), -}; - -static struct sockaddr_in peer_addr4 = { - .sin_family = AF_INET, - .sin_port = htons(PEER_PORT), -}; - -#if defined(CONFIG_NET_UDP) -static K_THREAD_STACK_DEFINE(ipv4_udp_stack, STACKSIZE); -static struct k_thread ipv4_udp_thread_data; -#endif - -#if defined(CONFIG_NET_TCP) -static K_THREAD_STACK_DEFINE(ipv4_tcp_stack, STACKSIZE); -static struct k_thread ipv4_tcp_thread_data; -#endif - -#endif /* CONFIG_NET_IPV4 */ - -#define WAIT_TIME (2 * MSEC_PER_SEC) - -#if defined(CONFIG_NET_MGMT_EVENT) -static struct net_mgmt_event_callback cb; -#endif - -static inline void init_app(void) +void panic(const char *msg) { - NET_INFO("Run echo client"); - -#if defined(CONFIG_NET_IPV6) -#if defined(CONFIG_NET_APP_SETTINGS) - if (net_addr_pton(AF_INET6, - CONFIG_NET_APP_MY_IPV6_ADDR, - &my_addr6.sin6_addr) < 0) { - NET_ERR("Invalid IPv6 address %s", - CONFIG_NET_APP_MY_IPV6_ADDR); - - net_ipaddr_copy(&my_addr6.sin6_addr, &in6addr_my); + if (msg) { + NET_ERR("%s", msg); } -#endif -#if defined(CONFIG_NET_APP_SETTINGS) - if (net_addr_pton(AF_INET6, - CONFIG_NET_APP_PEER_IPV6_ADDR, - &peer_addr6.sin6_addr) < 0) { - NET_ERR("Invalid peer IPv6 address %s", - CONFIG_NET_APP_PEER_IPV6_ADDR); + k_sem_give(&quit_lock); - net_ipaddr_copy(&peer_addr6.sin6_addr, &in6addr_peer); + for (;;) { + k_sleep(K_FOREVER); } -#endif - - do { - struct net_if_addr *ifaddr; - - ifaddr = net_if_ipv6_addr_add(net_if_get_default(), - &my_addr6.sin6_addr, - NET_ADDR_MANUAL, 0); - } while (0); - -#if defined(CONFIG_NET_UDP) - k_sem_init(&conf.recv_ipv6, 0, UINT_MAX); -#endif -#endif - -#if defined(CONFIG_NET_IPV4) -#if defined(CONFIG_NET_DHCPV4) - net_dhcpv4_start(net_if_get_default()); -#else -#if defined(CONFIG_NET_APP_SETTINGS) - if (net_addr_pton(AF_INET, - CONFIG_NET_APP_MY_IPV4_ADDR, - &my_addr4.sin_addr) < 0) { - NET_ERR("Invalid IPv4 address %s", - CONFIG_NET_APP_MY_IPV4_ADDR); - - net_ipaddr_copy(&my_addr4.sin_addr, &in4addr_my); - } -#endif - -#if defined(CONFIG_NET_APP_SETTINGS) - if (net_addr_pton(AF_INET, - CONFIG_NET_APP_PEER_IPV4_ADDR, - &peer_addr4.sin_addr) < 0) { - NET_ERR("Invalid peer IPv4 address %s", - CONFIG_NET_APP_PEER_IPV4_ADDR); - - net_ipaddr_copy(&peer_addr4.sin_addr, &in4addr_peer); - } -#endif - - net_if_ipv4_addr_add(net_if_get_default(), &my_addr4.sin_addr, - NET_ADDR_MANUAL, 0); -#endif /* CONFIG_NET_DHCPV4 */ - -#if defined(CONFIG_NET_UDP) - k_sem_init(&conf.recv_ipv4, 0, UINT_MAX); -#endif -#endif } -static inline bool get_context(struct net_context **udp_recv4, - struct net_context **udp_recv6, - struct net_context **tcp_recv4, - struct net_context **tcp_recv6) +static inline int init_app(void) { - int ret; + NET_INFO(APP_BANNER); -#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_UDP) - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, udp_recv6); - if (ret < 0) { - NET_ERR("Cannot get network context for IPv6 UDP (%d)", - ret); - return false; + k_sem_init(&quit_lock, 0, UINT_MAX); + +#if defined(CONFIG_NET_L2_BLUETOOTH) + if (bt_enable(NULL)) { + NET_ERR("Bluetooth init failed"); + return -EFAULT; } + ipss_init(); + ipss_advertise(); +#endif - net_context_setup_pools(*udp_recv6, tx_udp_slab, data_udp_pool); - - ret = net_context_bind(*udp_recv6, (struct sockaddr *)&my_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - NET_ERR("Cannot bind IPv6 UDP port %d (%d)", - ntohs(my_addr6.sin6_port), ret); - return false; +#if defined(CONFIG_NET_L2_IEEE802154) + if (ieee802154_sample_setup()) { + NET_ERR("IEEE 802.15.4 setup failed"); + return -EFAULT; } #endif -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_UDP) - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, udp_recv4); - if (ret < 0) { - NET_ERR("Cannot get network context for IPv4 UDP (%d)", - ret); - return false; - } - - net_context_setup_pools(*udp_recv4, tx_udp_slab, data_udp_pool); - - ret = net_context_bind(*udp_recv4, (struct sockaddr *)&my_addr4, - sizeof(struct sockaddr_in)); - if (ret < 0) { - NET_ERR("Cannot bind IPv4 UDP port %d (%d)", - ntohs(my_addr4.sin_port), ret); - return false; - } -#endif - -#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_TCP) - if (tcp_recv6) { - ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, - tcp_recv6); - if (ret < 0) { - NET_ERR("Cannot get network context " - "for IPv6 TCP (%d)", ret); - return false; - } - - net_context_setup_pools(*tcp_recv6, tx_tcp_slab, data_tcp_pool); - - ret = net_context_bind(*tcp_recv6, - (struct sockaddr *)&my_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - NET_ERR("Cannot bind IPv6 TCP port %d (%d)", - ntohs(my_addr6.sin6_port), ret); - return false; - } - } -#endif - -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_TCP) - if (tcp_recv4) { - ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, - tcp_recv4); - if (ret < 0) { - NET_ERR("Cannot get network context for IPv4 TCP"); - return false; - } - - net_context_setup_pools(*tcp_recv4, tx_tcp_slab, data_tcp_pool); - - ret = net_context_bind(*tcp_recv4, - (struct sockaddr *)&my_addr4, - sizeof(struct sockaddr_in)); - if (ret < 0) { - NET_ERR("Cannot bind IPv4 TCP port %d", - ntohs(my_addr4.sin_port)); - return false; - } - } -#endif - - return true; + return 0; } -static inline bool wait_reply(const char *name, - struct k_sem *sem) -{ - int ret = k_sem_take(sem, WAIT_TIME); - - ARG_UNUSED(name); - - if (!ret) { - return true; - } - - NET_ERR("wait_reply returned %s", - ret == -EAGAIN ? "on time out" : "directly"); - - return false; -} - -static struct net_pkt *prepare_send_pkt(const char *name, - struct net_context *context, - int expecting_len) +struct net_pkt *prepare_send_pkt(struct net_app_ctx *ctx, + const char *name, + int expecting_len) { struct net_pkt *send_pkt; bool status; - send_pkt = net_pkt_get_tx(context, K_FOREVER); + send_pkt = net_app_get_net_pkt(ctx, K_FOREVER); NET_ASSERT(send_pkt); status = net_pkt_append_all(send_pkt, expecting_len, lorem_ipsum, - K_FOREVER); + K_FOREVER); if (!status) { NET_ERR("%s: cannot create send pkt", name); + net_pkt_unref(send_pkt); return NULL; } return send_pkt; } -static inline void udp_sent(struct net_context *context, - int status, - void *bytes_sent, - void *user_data) -{ - ARG_UNUSED(context); - - if (!status) { - NET_INFO("%s: sent %u bytes", (char *)user_data, - POINTER_TO_UINT(bytes_sent)); - } -} - -static inline void set_dst_addr(sa_family_t family, - struct net_pkt *pkt, - struct sockaddr *dst_addr) -{ - ARG_UNUSED(pkt); - -#if defined(CONFIG_NET_IPV6) - if (family == AF_INET6) { - net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, - &peer_addr6.sin6_addr); - net_sin6(dst_addr)->sin6_family = AF_INET6; - net_sin6(dst_addr)->sin6_port = htons(PEER_PORT); - - return; - } -#endif /* CONFIG_NET_IPV6 */ - -#if defined(CONFIG_NET_IPV4) - if (family == AF_INET) { - net_ipaddr_copy(&net_sin(dst_addr)->sin_addr, - &peer_addr4.sin_addr); - net_sin(dst_addr)->sin_family = AF_INET; - net_sin(dst_addr)->sin_port = htons(PEER_PORT); - - return; - } -#endif /* CONFIG_NET_IPV4 */ -} - -#if defined(CONFIG_NET_UDP) -static bool compare_udp_data(struct net_pkt *pkt, int expecting_len) -{ - u8_t *ptr = net_pkt_appdata(pkt); - struct net_buf *frag; - int pos = 0; - int len; - - /* frag will now point to first fragment with IP header - * in it. - */ - frag = pkt->frags; - - /* Do not include the protocol headers in the first fragment. - * The remaining fragments contain only data so the user data - * length is directly the fragment len. - */ - len = frag->len - (ptr - frag->data); - - while (frag) { - if (memcmp(ptr, lorem_ipsum + pos, len)) { - NET_DBG("Invalid data received"); - return false; - } else { - pos += len; - - frag = frag->frags; - if (!frag) { - break; - } - - ptr = frag->data; - len = frag->len; - } - } - - NET_DBG("Compared %d bytes, all ok", expecting_len); - - return true; -} - -static void setup_udp_recv(struct net_context *udp, void *user_data, - net_context_recv_cb_t cb) -{ - int ret; - - ret = net_context_recv(udp, cb, 0, user_data); - if (ret < 0) { - NET_ERR("Cannot receive UDP packets"); - } -} - -static bool send_udp_data(struct net_context *udp, - sa_family_t family, - char *proto, - struct data *data) -{ - bool status = false; - struct net_pkt *send_pkt; - struct sockaddr dst_addr; - socklen_t addrlen; - size_t len; - int ret; - - data->expecting_udp = sys_rand32_get() % ipsum_len; - - send_pkt = prepare_send_pkt(proto, udp, data->expecting_udp); - if (!send_pkt) { - goto out; - } - - len = net_pkt_get_len(send_pkt); - - NET_ASSERT_INFO(data->expecting_udp == len, - "Data to send %d bytes, real len %zu", - data->expecting_udp, len); - - set_dst_addr(family, send_pkt, &dst_addr); - - if (family == AF_INET6) { - addrlen = sizeof(struct sockaddr_in6); - } else { - addrlen = sizeof(struct sockaddr_in); - } - - ret = net_context_sendto(send_pkt, &dst_addr, - addrlen, udp_sent, 0, - UINT_TO_POINTER(len), - proto); - if (ret < 0) { - NET_ERR("Cannot send %s data to peer (%d)", proto, ret); - net_pkt_unref(send_pkt); - } else { - status = true; - } -out: - - return status; -} - -static void udp_received(struct net_context *context, - struct net_pkt *pkt, - int status, - void *user_data) -{ - sa_family_t family = net_pkt_family(pkt); - struct data *data = user_data; - struct k_sem *recv; - - ARG_UNUSED(context); - ARG_UNUSED(status); - - if (family == AF_INET) { - recv = &conf.recv_ipv4; - } else { - recv = &conf.recv_ipv6; - } - - if (data->expecting_udp != net_pkt_appdatalen(pkt)) { - NET_ERR("Sent %d bytes, received %u bytes", - data->expecting_udp, net_pkt_appdatalen(pkt)); - } - - if (!compare_udp_data(pkt, data->expecting_udp)) { - NET_DBG("Data mismatch"); - } - - net_pkt_unref(pkt); - - k_sem_give(recv); -} - -static void send_udp(struct net_context *udp, - sa_family_t family, - char *proto, - struct k_sem *sem, - struct data *data) -{ - setup_udp_recv(udp, data, udp_received); - - NET_INFO("Starting to send %s data", proto); - - do { - /* We first send a packet, then wait for a packet to arrive. - * If the reply does not come in time, we send another packet. - */ - send_udp_data(udp, family, proto, data); - - NET_DBG("Waiting %s packet", proto); - - if (!wait_reply(proto, sem)) { - NET_DBG("Waited %d bytes but did not receive them.", - data->expecting_udp); - } - - k_yield(); - } while (1); -} - -#endif /* CONFIG_NET_UDP */ - -#if defined(CONFIG_NET_TCP) -static bool compare_tcp_data(struct net_pkt *pkt, int expecting_len, - int received_len) -{ - u8_t *ptr = net_pkt_appdata(pkt), *start; - int pos = 0; - struct net_buf *frag; - int len; - - /* frag will point to first fragment with IP header in it. - */ - frag = pkt->frags; - - /* Do not include the protocol headers for the first fragment. - * The remaining fragments contain only data so the user data - * length is directly the fragment len. - */ - len = frag->len - (ptr - frag->data); - - start = lorem_ipsum + received_len; - - while (frag) { - if (memcmp(ptr, start + pos, len)) { - NET_DBG("Invalid data received"); - return false; - } - - pos += len; - - frag = frag->frags; - if (!frag) { - break; - } - - ptr = frag->data; - len = frag->len; - } - - NET_DBG("Compared %d bytes, all ok", net_pkt_appdatalen(pkt)); - - return true; -} - -static void tcp_received(struct net_context *context, - struct net_pkt *pkt, - int status, - void *user_data) -{ - struct data *data = user_data; - char *proto; - - ARG_UNUSED(status); - - if (!pkt || net_pkt_appdatalen(pkt) == 0) { - if (pkt) { - net_pkt_unref(pkt); - } - - return; - } - - if (net_pkt_family(pkt) == AF_INET6) { - proto = "IPv6"; - } else { - proto = "IPv4"; - } - - NET_DBG("Sent %d bytes, received %u bytes", - data->expecting_tcp, net_pkt_appdatalen(pkt)); - - if (!compare_tcp_data(pkt, data->expecting_tcp, data->received_tcp)) { - NET_DBG("Data mismatch"); - } else { - data->received_tcp += net_pkt_appdatalen(pkt); - } - - if (data->expecting_tcp <= data->received_tcp) { - /* Send more data */ - send_tcp_data(context, proto, data); - } - - net_pkt_unref(pkt); -} - -static void setup_tcp_recv(struct net_context *tcp, - net_context_recv_cb_t cb, - void *user_data) -{ - int ret; - - ret = net_context_recv(tcp, cb, 0, user_data); - if (ret < 0) { - NET_ERR("Cannot receive TCP packets (%d)", ret); - } -} - -static void tcp_sent(struct net_context *context, - int status, - void *token, - void *user_data) -{ - u32_t len = POINTER_TO_UINT(token); - - if (len) { - if (status) { - NET_DBG("%s: len %u status %d", (char *)user_data, - len, status); - } else { - NET_DBG("%s: len %u", (char *)user_data, len); - } - } -} - -static bool send_tcp_data(struct net_context *ctx, - char *proto, - struct data *data) -{ - struct net_pkt *send_pkt; - bool status = false; - size_t len; - int ret; - - data->expecting_tcp = sys_rand32_get() % ipsum_len; - data->received_tcp = 0; - - send_pkt = prepare_send_pkt(proto, ctx, data->expecting_tcp); - if (!send_pkt) { - goto out; - } - - len = net_pkt_get_len(send_pkt); - - NET_ASSERT_INFO(data->expecting_tcp == len, - "%s data to send %d bytes, real len %zu", - proto, data->expecting_tcp, len); - - ret = net_context_send(send_pkt, tcp_sent, 0, - UINT_TO_POINTER(len), proto); - if (ret < 0) { - NET_ERR("Cannot send %s data to peer (%d)", proto, ret); - net_pkt_unref(send_pkt); - } else { - status = true; - } - -out: - return status; -} - -static void tcp_connected(struct net_context *context, - int status, - void *user_data) -{ - /* Start to send data */ - sa_family_t family = POINTER_TO_UINT(user_data); - const char *str_family = (family == AF_INET) ? "IPv4" : "IPv6"; - - if (status < 0) { - NET_ERR("Couldn't connect using %s: %d", str_family, status); - return; - } - - NET_DBG("%s connected.", str_family); - - if (family == AF_INET) { -#if defined(CONFIG_NET_IPV4) - setup_tcp_recv(context, tcp_received, &conf.ipv4); - - send_tcp_data(context, "IPv4", &conf.ipv4); -#else - NET_DBG("IPv4 data skipped."); -#endif - } else if (family == AF_INET6) { -#if defined(CONFIG_NET_IPV6) - setup_tcp_recv(context, tcp_received, &conf.ipv6); - - send_tcp_data(context, "IPv6", &conf.ipv6); -#else - NET_DBG("IPv6 data skipped."); -#endif - } -} - -#if defined(CONFIG_NET_IPV4) -static void tcp_connect4(struct net_context *tcp_send) -{ - int ret; - - ret = net_context_connect(tcp_send, - (struct sockaddr *)&peer_addr4, - sizeof(peer_addr4), - tcp_connected, - K_FOREVER, - UINT_TO_POINTER(AF_INET)); - if (ret < 0) { - NET_DBG("Cannot connect to IPv4 peer (%d)", ret); - } -} -#endif - -#if defined(CONFIG_NET_IPV6) -static void tcp_connect6(struct net_context *tcp_send) -{ - int ret; - - ret = net_context_connect(tcp_send, - (struct sockaddr *)&peer_addr6, - sizeof(peer_addr6), - tcp_connected, - K_FOREVER, - UINT_TO_POINTER(AF_INET6)); - if (ret < 0) { - NET_DBG("Cannot connect to IPv6 peer (%d)", ret); - } -} -#endif /* CONFIG_NET_IPV6 */ -#endif /* CONFIG_NET_TCP */ - -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_UDP) -static void send_udp_ipv4(struct net_context *udp) -{ - send_udp(udp, AF_INET, "IPv4", &conf.recv_ipv4, &conf.ipv4); -} -#endif - -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_TCP) -static void send_tcp_ipv4(struct net_context *tcp) -{ - tcp_connect4(tcp); -} -#endif - -#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_UDP) -static void send_udp_ipv6(struct net_context *udp) -{ - send_udp(udp, AF_INET6, "IPv6", &conf.recv_ipv6, &conf.ipv6); -} -#endif - -#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_TCP) -static void send_tcp_ipv6(struct net_context *tcp) -{ - tcp_connect6(tcp); -} -#endif - -static void event_iface_up(struct net_mgmt_event_callback *cb, - u32_t mgmt_event, struct net_if *iface) -{ - struct net_context *udp_send4 = { 0 }; - struct net_context *udp_send6 = { 0 }; - struct net_context *tcp_send4 = { 0 }; - struct net_context *tcp_send6 = { 0 }; - - ipsum_len = strlen(lorem_ipsum); - - if (!get_context(&udp_send4, &udp_send6, - &tcp_send4, &tcp_send6)) { - NET_ERR("Cannot get network contexts"); - return; - } - -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_UDP) - k_thread_create(&ipv4_udp_thread_data, ipv4_udp_stack, STACKSIZE, - (k_thread_entry_t)send_udp_ipv4, - udp_send4, NULL, NULL, K_PRIO_COOP(7), 0, 0); -#endif - -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_TCP) - k_thread_create(&ipv4_tcp_thread_data, ipv4_tcp_stack, STACKSIZE, - (k_thread_entry_t)send_tcp_ipv4, - tcp_send4, NULL, NULL, K_PRIO_COOP(7), 0, 0); -#endif - -#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_UDP) - k_thread_create(&ipv6_udp_thread_data, ipv6_udp_stack, STACKSIZE, - (k_thread_entry_t)send_udp_ipv6, - udp_send6, NULL, NULL, K_PRIO_COOP(7), 0, 0); -#endif - -#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_TCP) - k_thread_create(&ipv6_tcp_thread_data, ipv6_tcp_stack, STACKSIZE, - (k_thread_entry_t)send_tcp_ipv6, - tcp_send6, NULL, NULL, K_PRIO_COOP(7), 0, 0); -#endif -} - void main(void) { - struct net_if *iface = net_if_get_default(); + int ret; init_app(); -#if defined(CONFIG_NET_L2_BLUETOOTH) - if (bt_enable(NULL)) { - NET_ERR("Bluetooth init failed\n"); - return; - } -#endif + if (IS_ENABLED(CONFIG_NET_TCP)) { + if (IS_ENABLED(CONFIG_NET_UDP)) { + k_sem_init(&tcp_ready, 0, 1); + } -#if defined(CONFIG_NET_L2_IEEE802154) - if (ieee802154_sample_setup()) { - NET_ERR("IEEE 802.15.4 setup failed"); - return; - } -#endif + ret = start_tcp(); + if (ret < 0) { + goto quit; + } -#if defined(CONFIG_NET_MGMT_EVENT) - /* Subscribe to NET_IF_UP if interface is not ready */ - if (!atomic_test_bit(iface->flags, NET_IF_UP)) { - net_mgmt_init_event_callback(&cb, event_iface_up, - NET_EVENT_IF_UP); - net_mgmt_add_event_callback(&cb); - return; + /* We start the UDP after the TCP is connected properly. + * This is done like this so that UDP does not use all the + * buffers as it is basically flooding the link with UDP + * data. + */ + if (IS_ENABLED(CONFIG_NET_UDP)) { + k_sem_take(&tcp_ready, K_FOREVER); + } } -#endif - event_iface_up(NULL, NET_EVENT_IF_UP, iface); + if (IS_ENABLED(CONFIG_NET_UDP)) { + start_udp(); + } + + k_sem_take(&quit_lock, K_FOREVER); + +quit: + NET_INFO("Stopping..."); + + if (IS_ENABLED(CONFIG_NET_UDP)) { + stop_udp(); + } + + if (IS_ENABLED(CONFIG_NET_TCP)) { + stop_tcp(); + } } diff --git a/samples/net/echo_client/src/tcp.c b/samples/net/echo_client/src/tcp.c new file mode 100644 index 00000000000..1d643678078 --- /dev/null +++ b/samples/net/echo_client/src/tcp.c @@ -0,0 +1,369 @@ +/* tcp.c - TCP specific code for echo client */ + +/* + * Copyright (c) 2017 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if 1 +#define SYS_LOG_DOMAIN "echo-client" +#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#define NET_LOG_ENABLED 1 +#endif + +#include +#include +#include + +#include +#include +#include + +#include + +#include "common.h" + +static struct net_app_ctx tcp6; +static struct net_app_ctx tcp4; + +static int connected_count; + +/* Note that both tcp and udp can share the same pool but in this + * example the UDP context and TCP context have separate pools. + */ +#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) +NET_PKT_TX_SLAB_DEFINE(echo_tx_tcp, 15); +NET_PKT_DATA_POOL_DEFINE(echo_data_tcp, 30); + +static struct k_mem_slab *tx_tcp_slab(void) +{ + return &echo_tx_tcp; +} + +static struct net_buf_pool *data_tcp_pool(void) +{ + return &echo_data_tcp; +} +#else +#define tx_tcp_slab NULL +#define data_tcp_pool NULL +#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ + +#if defined(CONFIG_NET_APP_TLS) +#define HOSTNAME "localhost" /* for cert verification if that is enabled */ + +/* The result buf size is set to large enough so that we can receive max size + * buf back. Note that mbedtls needs also be configured to have equal size + * value for its buffer size. See MBEDTLS_SSL_MAX_CONTENT_LEN option in TLS + * config file. + */ +#define RESULT_BUF_SIZE 1500 +static u8_t tls_result_ipv6[RESULT_BUF_SIZE]; +static u8_t tls_result_ipv4[RESULT_BUF_SIZE]; + +#if !defined(CONFIG_NET_APP_TLS_STACK_SIZE) +#define CONFIG_NET_APP_TLS_STACK_SIZE 6144 +#endif /* CONFIG_NET_APP_TLS_STACK_SIZE */ + +#define INSTANCE_INFO "Zephyr TLS echo-client #1" + +/* Note that each net_app context needs its own stack as there will be + * a separate thread needed. + */ +NET_STACK_DEFINE(NET_APP_TLS_IPv4, net_app_tls_stack_ipv4, + CONFIG_NET_APP_TLS_STACK_SIZE, CONFIG_NET_APP_TLS_STACK_SIZE); + +NET_STACK_DEFINE(NET_APP_TLS_IPv6, net_app_tls_stack_ipv6, + CONFIG_NET_APP_TLS_STACK_SIZE, CONFIG_NET_APP_TLS_STACK_SIZE); + +NET_APP_TLS_POOL_DEFINE(ssl_pool, 10); +#else +#define tls_result_ipv6 NULL +#define tls_result_ipv4 NULL +#define net_app_tls_stack_ipv4 NULL +#define net_app_tls_stack_ipv6 NULL +#endif /* CONFIG_NET_APP_TLS */ + +#if defined(CONFIG_NET_APP_TLS) +/* Load the certificates and private RSA key. */ + +#include "test_certs.h" + +static int setup_cert(struct net_app_ctx *ctx, void *cert) +{ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + mbedtls_ssl_conf_psk(&ctx->tls.mbedtls.conf, + client_psk, sizeof(client_psk), + (const unsigned char *)client_psk_id, + sizeof(client_psk_id) - 1); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + { + mbedtls_x509_crt *ca_cert = cert; + int ret; + + ret = mbedtls_x509_crt_parse_der(ca_cert, + ca_certificate, + sizeof(ca_certificate)); + if (ret != 0) { + NET_ERR("mbedtls_x509_crt_parse_der failed " + "(-0x%x)", -ret); + return ret; + } + + mbedtls_ssl_conf_ca_chain(&ctx->tls.mbedtls.conf, + ca_cert, NULL); + + /* In this example, we skip the certificate checks. In real + * life scenarios, one should always verify the certificates. + */ + mbedtls_ssl_conf_authmode(&ctx->tls.mbedtls.conf, + MBEDTLS_SSL_VERIFY_REQUIRED); + + mbedtls_ssl_conf_cert_profile(&ctx->tls.mbedtls.conf, + &mbedtls_x509_crt_profile_default); +#define VERIFY_CERTS 0 +#if VERIFY_CERTS + mbedtls_ssl_conf_authmode(&ctx->tls.mbedtls.conf, + MBEDTLS_SSL_VERIFY_OPTIONAL); +#else + ; +#endif /* VERIFY_CERTS */ + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + return 0; +} +#endif /* CONFIG_NET_APP_TLS */ + +static void send_tcp_data(struct net_app_ctx *ctx, + struct data *data) +{ + struct net_pkt *pkt; + size_t len; + int ret; + + do { + data->expecting_tcp = sys_rand32_get() % ipsum_len; + } while (data->expecting_tcp == 0); + + data->received_tcp = 0; + + pkt = prepare_send_pkt(ctx, data->proto, data->expecting_tcp); + if (!pkt) { + return; + } + + len = net_pkt_get_len(pkt); + + NET_ASSERT_INFO(data->expecting_tcp == len, + "%s data to send %d bytes, real len %zu", + data->proto, data->expecting_tcp, len); + + ret = net_app_send_pkt(ctx, pkt, NULL, 0, K_FOREVER, + UINT_TO_POINTER(len)); + if (ret < 0) { + NET_ERR("Cannot send %s data to peer (%d)", data->proto, ret); + net_pkt_unref(pkt); + } +} + +static bool compare_tcp_data(struct net_pkt *pkt, int expecting_len, + int received_len) +{ + u8_t *ptr = net_pkt_appdata(pkt); + const char *start; + int pos = 0; + struct net_buf *frag; + int len; + + /* frag will point to first fragment with IP header in it. + */ + frag = pkt->frags; + + /* Do not include the protocol headers for the first fragment. + * The remaining fragments contain only data so the user data + * length is directly the fragment len. + */ + len = frag->len - (ptr - frag->data); + + start = lorem_ipsum + received_len; + + while (frag) { + if (memcmp(ptr, start + pos, len)) { + NET_DBG("Invalid data received"); + return false; + } + + pos += len; + + frag = frag->frags; + if (!frag) { + break; + } + + ptr = frag->data; + len = frag->len; + } + + NET_DBG("Compared %d bytes, all ok", net_pkt_appdatalen(pkt)); + + return true; +} + +static void tcp_received(struct net_app_ctx *ctx, + struct net_pkt *pkt, + int status, + void *user_data) +{ + struct data *data = ctx->user_data; + + ARG_UNUSED(user_data); + ARG_UNUSED(status); + + if (!pkt || net_pkt_appdatalen(pkt) == 0) { + if (pkt) { + net_pkt_unref(pkt); + } + + return; + } + + NET_DBG("Sent %d bytes, received %u bytes", + data->expecting_tcp, net_pkt_appdatalen(pkt)); + + if (!compare_tcp_data(pkt, data->expecting_tcp, data->received_tcp)) { + NET_DBG("Data mismatch"); + } else { + data->received_tcp += net_pkt_appdatalen(pkt); + } + + if (data->expecting_tcp <= data->received_tcp) { + /* Send more data */ + send_tcp_data(ctx, data); + } + + net_pkt_unref(pkt); +} + +static void tcp_connected(struct net_app_ctx *ctx, + int status, + void *user_data) +{ + if (status < 0) { + return; + } + + connected_count++; + + if (IS_ENABLED(CONFIG_NET_UDP)) { + if (IS_ENABLED(CONFIG_NET_IPV6) && + IS_ENABLED(CONFIG_NET_IPV4)) { + if (connected_count > 1) { + k_sem_give(&tcp_ready); + } + } else { + k_sem_give(&tcp_ready); + } + } + + send_tcp_data(ctx, user_data); +} + +static int connect_tcp(struct net_app_ctx *ctx, const char *peer, + void *user_data, u8_t *result_buf, + size_t result_buf_len, u8_t *stack, size_t stack_size) +{ + struct data *data = user_data; + int ret; + + ret = net_app_init_tcp_client(ctx, NULL, NULL, peer, PEER_PORT, + WAIT_TIME, user_data); + if (ret < 0) { + NET_ERR("Cannot init %s TCP client (%d)", data->proto, ret); + goto fail; + } + +#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) + net_app_set_net_pkt_pool(ctx, tx_tcp_slab, data_tcp_pool); +#endif + + ret = net_app_set_cb(ctx, tcp_connected, tcp_received, NULL, NULL); + if (ret < 0) { + NET_ERR("Cannot set callbacks (%d)", ret); + goto fail; + } + +#if defined(CONFIG_NET_APP_TLS) + ret = net_app_client_tls(ctx, + result_buf, + result_buf_len, + INSTANCE_INFO, + strlen(INSTANCE_INFO), + setup_cert, + HOSTNAME, + NULL, + &ssl_pool, + stack, + stack_size); + if (ret < 0) { + NET_ERR("Cannot init TLS"); + goto fail; + } +#endif + + ret = net_app_connect(ctx, CONNECT_TIME); + if (ret < 0) { + NET_ERR("Cannot connect TCP (%d)", ret); + goto fail; + } + +fail: + return ret; +} + +int start_tcp(void) +{ + int ret = 0; + + if (IS_ENABLED(CONFIG_NET_IPV6)) { + ret = connect_tcp(&tcp6, CONFIG_NET_APP_PEER_IPV6_ADDR, + &conf.ipv6, tls_result_ipv6, + sizeof(tls_result_ipv6), + net_app_tls_stack_ipv6, + K_THREAD_STACK_SIZEOF( + net_app_tls_stack_ipv6)); + if (ret < 0) { + NET_ERR("Cannot init IPv6 TCP client (%d)", ret); + } + } + + if (IS_ENABLED(CONFIG_NET_IPV4)) { + ret = connect_tcp(&tcp4, CONFIG_NET_APP_PEER_IPV4_ADDR, + &conf.ipv4, tls_result_ipv4, + sizeof(tls_result_ipv4), + net_app_tls_stack_ipv4, + K_THREAD_STACK_SIZEOF( + net_app_tls_stack_ipv4)); + if (ret < 0) { + NET_ERR("Cannot init IPv6 TCP client (%d)", ret); + } + } + + return ret; +} + +void stop_tcp(void) +{ + if (IS_ENABLED(CONFIG_NET_IPV6)) { + net_app_close(&tcp6); + net_app_release(&tcp6); + } + + if (IS_ENABLED(CONFIG_NET_IPV4)) { + net_app_close(&tcp4); + net_app_release(&tcp4); + } +} diff --git a/samples/net/echo_client/src/test_certs.h b/samples/net/echo_client/src/test_certs.h new file mode 100644 index 00000000000..2acdf1d84ac --- /dev/null +++ b/samples/net/echo_client/src/test_certs.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __TEST_CERTS_H__ +#define __TEST_CERTS_H__ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* This is the same cert as what is found in net-tools/echo-apps-cert.pem file + */ +static const unsigned char ca_certificate[] = { + 0x30, 0x82, 0x02, 0xfb, 0x30, 0x82, 0x01, 0xe3, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0xee, 0x10, 0x1f, 0xc1, 0xf2, 0x30, 0xe9, 0x11, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x09, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x37, 0x30, 0x36, 0x32, 0x36, 0x31, + 0x30, 0x35, 0x36, 0x31, 0x30, 0x5a, 0x17, 0x0d, + 0x34, 0x34, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, + 0x35, 0x36, 0x31, 0x30, 0x5a, 0x30, 0x14, 0x31, + 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, + 0x6f, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xc6, 0x00, 0x7b, 0x0d, + 0xd1, 0x17, 0x43, 0x6b, 0xa9, 0xa7, 0x79, 0x9c, + 0x0f, 0x8d, 0x77, 0x91, 0xd2, 0xf7, 0x47, 0x35, + 0xb3, 0x17, 0xe2, 0xdd, 0xed, 0x6d, 0x01, 0xf9, + 0xb1, 0x92, 0xc9, 0x48, 0x80, 0xe0, 0x1f, 0xcf, + 0xb7, 0xa4, 0x5f, 0xf0, 0x36, 0xea, 0xbf, 0xe1, + 0x33, 0xf8, 0xa9, 0xc5, 0xe6, 0xd4, 0x19, 0x8b, + 0x82, 0x25, 0xd9, 0x19, 0x74, 0x70, 0x79, 0xec, + 0xc6, 0x68, 0xc9, 0xef, 0xce, 0x1a, 0xa9, 0xf0, + 0xb7, 0x01, 0x35, 0x91, 0xff, 0xd3, 0x75, 0x6e, + 0x02, 0xba, 0x06, 0x9a, 0x2a, 0xac, 0xcf, 0x22, + 0xbf, 0x2b, 0x1f, 0xc1, 0x72, 0x38, 0x22, 0x35, + 0xea, 0xda, 0x6f, 0xdd, 0x67, 0xa2, 0x2b, 0x19, + 0x38, 0x19, 0x0e, 0x44, 0xd1, 0x71, 0x38, 0xb4, + 0x6d, 0x26, 0x85, 0xd6, 0xc6, 0xbe, 0xc1, 0x6f, + 0x3c, 0xee, 0xaf, 0x94, 0x3c, 0x05, 0x56, 0x4e, + 0xad, 0x53, 0x81, 0x8b, 0xd4, 0x23, 0x31, 0x69, + 0x72, 0x27, 0x93, 0xb4, 0x3a, 0xac, 0x23, 0xe8, + 0x10, 0xae, 0xf5, 0x9f, 0x0b, 0xa6, 0x6e, 0xd3, + 0x73, 0xca, 0x18, 0x11, 0xca, 0xbe, 0x71, 0x00, + 0x56, 0x29, 0x34, 0x54, 0xcc, 0xda, 0x29, 0x5b, + 0x26, 0x29, 0x99, 0x4d, 0x5f, 0xa1, 0xa6, 0xb9, + 0xcb, 0x2b, 0xb2, 0x0f, 0x10, 0x00, 0x04, 0xa9, + 0x11, 0x2c, 0x48, 0xb1, 0x99, 0xa5, 0xca, 0x7c, + 0x67, 0xa5, 0xbe, 0x14, 0x20, 0x12, 0xb7, 0x3b, + 0x7a, 0x4f, 0xdc, 0xc7, 0xd5, 0x2d, 0x04, 0x66, + 0xbb, 0xf5, 0x0c, 0xcd, 0xf1, 0x32, 0x39, 0xd7, + 0x51, 0x9b, 0xba, 0xdb, 0xf1, 0xa7, 0xfe, 0x2d, + 0x9a, 0xe6, 0x9c, 0x6b, 0x54, 0xda, 0xf1, 0xdd, + 0x48, 0xf9, 0xd7, 0xf0, 0x35, 0x7c, 0x8e, 0x24, + 0x7e, 0x44, 0x2f, 0xf3, 0xbf, 0x39, 0x0e, 0x96, + 0xab, 0xe1, 0x45, 0x03, 0x8b, 0x54, 0xdc, 0xe1, + 0xb6, 0x11, 0x81, 0x21, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xa4, 0xef, 0x6d, 0xdc, 0x9b, 0x23, 0xc5, 0x3a, + 0xdd, 0x34, 0xd9, 0x01, 0x1c, 0x68, 0x03, 0x53, + 0xae, 0x92, 0xc2, 0xc9, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0xa4, 0xef, 0x6d, 0xdc, 0x9b, 0x23, 0xc5, + 0x3a, 0xdd, 0x34, 0xd9, 0x01, 0x1c, 0x68, 0x03, + 0x53, 0xae, 0x92, 0xc2, 0xc9, 0x30, 0x0c, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x67, + 0x65, 0xbf, 0x93, 0x89, 0xde, 0x4f, 0x71, 0xff, + 0x1c, 0x93, 0x68, 0xa0, 0x64, 0x09, 0x5e, 0x95, + 0x94, 0xf5, 0xd5, 0xf4, 0x6b, 0x20, 0x32, 0xd8, + 0x04, 0x80, 0xac, 0xf8, 0x52, 0x36, 0x7a, 0x38, + 0x83, 0xae, 0xab, 0x29, 0x22, 0x42, 0x71, 0x7e, + 0xea, 0xe5, 0x4f, 0x71, 0xac, 0x44, 0x3f, 0x9e, + 0x5e, 0x49, 0x22, 0x05, 0xee, 0xa6, 0x7b, 0xab, + 0x56, 0x2e, 0xb3, 0x9a, 0x35, 0x1a, 0x88, 0xc3, + 0x54, 0x9b, 0xfd, 0xac, 0x65, 0x54, 0xaf, 0x21, + 0xa7, 0xe0, 0xdd, 0x62, 0x29, 0x8c, 0xae, 0x26, + 0x0b, 0x84, 0x1f, 0x69, 0x78, 0x84, 0xc6, 0x7e, + 0xcf, 0xc8, 0xf5, 0x92, 0x8c, 0x05, 0xa8, 0x13, + 0x38, 0xcd, 0x0b, 0x98, 0x53, 0xfb, 0xdd, 0x8d, + 0x51, 0x90, 0xa8, 0x51, 0xfa, 0x52, 0xbe, 0x28, + 0xd4, 0x71, 0x50, 0x73, 0x1f, 0xb0, 0xb6, 0x0e, + 0x45, 0xb1, 0x47, 0x41, 0x06, 0xd9, 0x1d, 0x7a, + 0x34, 0xe7, 0x80, 0x2e, 0x0c, 0x02, 0x50, 0x97, + 0xde, 0xa8, 0x7a, 0x84, 0x2c, 0x1d, 0xf4, 0x51, + 0x56, 0xa5, 0x52, 0xb5, 0x04, 0x2e, 0xcb, 0xdd, + 0x8b, 0x2e, 0x16, 0xc6, 0xde, 0xc8, 0xe9, 0x8d, + 0xee, 0x5e, 0xb6, 0xa0, 0xe0, 0x2b, 0x85, 0x2a, + 0x89, 0x7b, 0xba, 0x68, 0x80, 0x2b, 0xfb, 0x6e, + 0x2e, 0x80, 0xe7, 0x7a, 0x97, 0x09, 0xb5, 0x2f, + 0x20, 0x8e, 0xed, 0xbc, 0x98, 0x6f, 0x95, 0xd5, + 0x5b, 0x3d, 0x26, 0x19, 0x26, 0x14, 0x39, 0x82, + 0xa8, 0xa8, 0x42, 0x46, 0xab, 0x59, 0x93, 0x47, + 0x83, 0xf7, 0x79, 0xbf, 0x73, 0xb5, 0x5d, 0x5d, + 0x78, 0xfe, 0x62, 0xac, 0xed, 0xb7, 0x1e, 0x4a, + 0xad, 0xc3, 0x99, 0x39, 0x7d, 0x3e, 0x30, 0x21, + 0x26, 0x1d, 0x66, 0xdb, 0x0d, 0xf3, 0xba, 0x87, + 0x46, 0xf0, 0x04, 0xfc, 0xc3, 0xbe, 0x84, 0x85, + 0x3c, 0x01, 0xef, 0xe0, 0x68, 0x65, 0xee, +}; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +const unsigned char client_psk[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; + +const char client_psk_id[] = "Client_identity"; +#endif + +#endif diff --git a/samples/net/echo_client/src/udp.c b/samples/net/echo_client/src/udp.c new file mode 100644 index 00000000000..d3f20ccf974 --- /dev/null +++ b/samples/net/echo_client/src/udp.c @@ -0,0 +1,247 @@ +/* udp.c - UDP specific code for echo client */ + +/* + * Copyright (c) 2017 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if 1 +#define SYS_LOG_DOMAIN "echo-client" +#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#define NET_LOG_ENABLED 1 +#endif + +#include +#include +#include + +#include +#include +#include + +#include + +#include "common.h" + +static struct net_app_ctx udp6; +static struct net_app_ctx udp4; + +#define UDP_SLEEP K_MSEC(150) + +/* Note that both tcp and udp can share the same pool but in this + * example the UDP context and TCP context have separate pools. + */ +#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) +NET_PKT_TX_SLAB_DEFINE(echo_tx_udp, 5); +NET_PKT_DATA_POOL_DEFINE(echo_data_udp, 20); + +static struct k_mem_slab *tx_udp_slab(void) +{ + return &echo_tx_udp; +} + +static struct net_buf_pool *data_udp_pool(void) +{ + return &echo_data_udp; +} +#else +#define tx_udp_slab NULL +#define data_udp_pool NULL +#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ + +static void send_udp_data(struct net_app_ctx *ctx, struct data *data) +{ + struct net_pkt *pkt; + size_t len; + int ret; + + data->expecting_udp = sys_rand32_get() % ipsum_len; + + pkt = prepare_send_pkt(ctx, data->proto, data->expecting_udp); + if (!pkt) { + return; + } + + len = net_pkt_get_len(pkt); + + NET_ASSERT_INFO(data->expecting_udp == len, + "Data to send %d bytes, real len %zu", + data->expecting_udp, len); + + ret = net_app_send_pkt(ctx, pkt, NULL, 0, K_FOREVER, + UINT_TO_POINTER(len)); + if (ret < 0) { + NET_ERR("Cannot send %s data to peer (%d)", data->proto, ret); + + net_pkt_unref(pkt); + } + + k_delayed_work_submit(&data->recv, WAIT_TIME); +} + +static bool compare_udp_data(struct net_pkt *pkt, int expecting_len) +{ + u8_t *ptr = net_pkt_appdata(pkt); + struct net_buf *frag; + int pos = 0; + int len; + + /* frag will now point to first fragment with IP header + * in it. + */ + frag = pkt->frags; + + /* Do not include the protocol headers in the first fragment. + * The remaining fragments contain only data so the user data + * length is directly the fragment len. + */ + len = frag->len - (ptr - frag->data); + + while (frag) { + if (memcmp(ptr, lorem_ipsum + pos, len)) { + NET_DBG("Invalid data received"); + return false; + } else { + pos += len; + + frag = frag->frags; + if (!frag) { + break; + } + + ptr = frag->data; + len = frag->len; + } + } + + NET_DBG("Compared %d bytes, all ok", expecting_len); + + return true; +} + +static void udp_received(struct net_app_ctx *ctx, + struct net_pkt *pkt, + int status, + void *user_data) +{ + struct data *data = ctx->user_data; + + ARG_UNUSED(user_data); + ARG_UNUSED(status); + + if (data->expecting_udp != net_pkt_appdatalen(pkt)) { + NET_ERR("Sent %d bytes, received %u bytes", + data->expecting_udp, net_pkt_appdatalen(pkt)); + } + + if (!compare_udp_data(pkt, data->expecting_udp)) { + NET_DBG("Data mismatch"); + } + + net_pkt_unref(pkt); + + k_delayed_work_cancel(&data->recv); + + /* Do not flood the link if we have also TCP configured */ + if (IS_ENABLED(CONFIG_NET_TCP)) { + k_sleep(UDP_SLEEP); + } + + send_udp_data(ctx, data); +} + +/* We can start to send data when UDP is "connected" */ +static void udp_connected(struct net_app_ctx *ctx, + int status, + void *user_data) +{ + struct data *data = user_data; + + data->udp = ctx; + + send_udp_data(ctx, data); +} + +static int connect_udp(struct net_app_ctx *ctx, const char *peer, + void *user_data) +{ + struct data *data = user_data; + int ret; + + ret = net_app_init_udp_client(ctx, NULL, NULL, peer, PEER_PORT, + WAIT_TIME, user_data); + if (ret < 0) { + NET_ERR("Cannot init %s UDP client (%d)", data->proto, ret); + goto fail; + } + +#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) + net_app_set_net_pkt_pool(ctx, tx_udp_slab, data_udp_pool); +#endif + + ret = net_app_set_cb(ctx, udp_connected, udp_received, NULL, NULL); + if (ret < 0) { + NET_ERR("Cannot set callbacks (%d)", ret); + goto fail; + } + + ret = net_app_connect(ctx, CONNECT_TIME); + if (ret < 0) { + NET_ERR("Cannot connect UDP (%d)", ret); + goto fail; + } + +fail: + return ret; +} + +static void wait_reply(struct k_work *work) +{ + /* This means that we did not receive response in time. */ + struct data *data = CONTAINER_OF(work, struct data, recv); + + NET_ERR("Data packet not received"); + + /* Send a new packet at this point */ + send_udp_data(data->udp, data); +} + +void start_udp(void) +{ + int ret; + + if (IS_ENABLED(CONFIG_NET_IPV6)) { + k_delayed_work_init(&conf.ipv6.recv, wait_reply); + + ret = connect_udp(&udp6, CONFIG_NET_APP_PEER_IPV6_ADDR, + &conf.ipv6); + if (ret < 0) { + NET_ERR("Cannot init IPv6 UDP client (%d)", ret); + } + } + + if (IS_ENABLED(CONFIG_NET_IPV4)) { + k_delayed_work_init(&conf.ipv4.recv, wait_reply); + + ret = connect_udp(&udp4, CONFIG_NET_APP_PEER_IPV4_ADDR, + &conf.ipv4); + if (ret < 0) { + NET_ERR("Cannot init IPv4 UDP client (%d)", ret); + } + } + +} + +void stop_udp(void) +{ + if (IS_ENABLED(CONFIG_NET_IPV6)) { + net_app_close(&udp6); + net_app_release(&udp6); + } + + if (IS_ENABLED(CONFIG_NET_IPV4)) { + net_app_close(&udp4); + net_app_release(&udp4); + } +}