summaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
authorSergio Rodriguez <sergio.sf.rodriguez@intel.com>2017-01-23 14:42:29 -0800
committerJukka Rissanen <jukka.rissanen@linux.intel.com>2017-01-27 12:35:53 +0200
commit98d7ff00136ce366160b9feb67b3d68558cb3a61 (patch)
tree36cf3561e99c929b489689fc93d82acf6162da99 /samples
parent3818af4a7b12bf17e481efa8ba626347d4ca9d74 (diff)
samples/coaps_client CoAP over DTLS client example app using mbedTLS
Jira: ZEP-941 Change-Id: Ia49087b75b33bcedb1b77b6a062368281c41e479 Signed-off-by: Sergio Rodriguez <sergio.sf.rodriguez@intel.com>
Diffstat (limited to 'samples')
-rw-r--r--samples/net/coaps_client/Makefile14
-rw-r--r--samples/net/coaps_client/README.rst53
-rw-r--r--samples/net/coaps_client/prj_qemu_x86.conf27
-rw-r--r--samples/net/coaps_client/src/Makefile7
-rw-r--r--samples/net/coaps_client/src/coaps_client.c447
-rw-r--r--samples/net/coaps_client/src/udp.c202
-rw-r--r--samples/net/coaps_client/src/udp.h23
-rw-r--r--samples/net/coaps_client/src/udp_cfg.h21
-rw-r--r--samples/net/coaps_client/testcase.ini4
9 files changed, 798 insertions, 0 deletions
diff --git a/samples/net/coaps_client/Makefile b/samples/net/coaps_client/Makefile
new file mode 100644
index 000000000..8e54ca81d
--- /dev/null
+++ b/samples/net/coaps_client/Makefile
@@ -0,0 +1,14 @@
+# Makefile - CoAP secure client test application
+
+#
+# Copyright (c) 2015 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+BOARD ?= qemu_x86
+CONF_FILE ?= prj_$(BOARD).conf
+
+include $(ZEPHYR_BASE)/Makefile.inc
+
+include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
diff --git a/samples/net/coaps_client/README.rst b/samples/net/coaps_client/README.rst
new file mode 100644
index 000000000..bdc1696cd
--- /dev/null
+++ b/samples/net/coaps_client/README.rst
@@ -0,0 +1,53 @@
+CoAP over DTLS sample client
+############################
+
+Overview
+========
+This sample code shows a CoAP over DTLS client using mbedTLS on top of Zephyr.
+
+Building and Running
+====================
+
+Follow the steps for testing :ref:`networking with Qemu <networking_with_qemu>`.
+
+Run the server application at samples/net/coaps_server, with the following
+command:
+
+.. code-block:: console
+
+ make server
+
+In other terminal window, run this client application at samples/net/coaps_client:
+
+.. code-block:: console
+
+ make client
+
+You will get the following output:
+
+.. code-block:: console
+
+ reply: 60 45 00 01 ff 54 79 70 65 3a 20 30 0a 43 6f 64 65 3a 20 31 0a 4d
+ 49 44 3a 20 31 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 (123 bytes)
+
+From the server application directory the screen should display
+
+.. code-block:: console
+
+ *******
+ type: 0 code 1 id 1
+ *******
+ connection was closed gracefully
+ done
+
+If the server does not receive the messages, restart the app and try to connect
+the client again.
+
+References
+==========
+
+* https://wiki.zephyrproject.org/view/Networking-with-Qemu
diff --git a/samples/net/coaps_client/prj_qemu_x86.conf b/samples/net/coaps_client/prj_qemu_x86.conf
new file mode 100644
index 000000000..209dd3698
--- /dev/null
+++ b/samples/net/coaps_client/prj_qemu_x86.conf
@@ -0,0 +1,27 @@
+CONFIG_NETWORKING=y
+CONFIG_NET_IPV6=y
+CONFIG_NET_UDP=y
+CONFIG_TEST_RANDOM_GENERATOR=y
+CONFIG_NET_BUF_LOG=y
+CONFIG_NET_LOG=y
+CONFIG_NET_SLIP_TAP=y
+CONFIG_SYS_LOG_SHOW_COLOR=y
+CONFIG_INIT_STACKS=y
+CONFIG_PRINTK=y
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_NBUF_RX_COUNT=14
+CONFIG_NET_NBUF_TX_COUNT=14
+CONFIG_NET_NBUF_DATA_COUNT=30
+CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
+CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2
+CONFIG_NET_MAX_CONTEXTS=10
+
+CONFIG_MBEDTLS=y
+CONFIG_MBEDTLS_BUILTIN=y
+CONFIG_MBEDTLS_CFG_FILE="config-coap.h"
+
+CONFIG_ZOAP=y
+
+CONFIG_NET_SAMPLES_IP_ADDRESSES=y
+CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::3"
+CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::1"
diff --git a/samples/net/coaps_client/src/Makefile b/samples/net/coaps_client/src/Makefile
new file mode 100644
index 000000000..788664861
--- /dev/null
+++ b/samples/net/coaps_client/src/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+obj-y += coaps_client.o udp.o
diff --git a/samples/net/coaps_client/src/coaps_client.c b/samples/net/coaps_client/src/coaps_client.c
new file mode 100644
index 000000000..84f875f74
--- /dev/null
+++ b/samples/net/coaps_client/src/coaps_client.c
@@ -0,0 +1,447 @@
+/* Sample CoAP over DTLS client using mbedTLS.
+ * (Meant to be used with config-coap.h)
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#include <zephyr.h>
+#include <stdio.h>
+#include <errno.h>
+#include <misc/printk.h>
+
+#if !defined(CONFIG_MBEDTLS_CFG_FILE)
+#include "mbedtls/config.h"
+#else
+#include CONFIG_MBEDTLS_CFG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdlib.h>
+#define mbedtls_time_t time_t
+#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
+#endif
+
+#include <string.h>
+#include <net/net_context.h>
+#include <net/net_if.h>
+#include <net/buf.h>
+#include <net/nbuf.h>
+#include "udp.h"
+#include "udp_cfg.h"
+
+#include "mbedtls/net.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+
+#include <net/zoap.h>
+
+#if defined(MBEDTLS_DEBUG_C)
+#include "mbedtls/debug.h"
+#define DEBUG_THRESHOLD 0
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#include "mbedtls/memory_buffer_alloc.h"
+static unsigned char heap[8192];
+#endif
+
+/*
+ * Hardcoded values for server host and port
+ */
+
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
+const unsigned char psk[] = "passwd\0";
+const char psk_id[] = "Client_identity\0";
+#endif
+
+const char *pers = "mini_client";
+static unsigned char payload[128];
+
+#define NUM_REPLIES 3
+struct zoap_reply replies[NUM_REPLIES];
+
+#define ZOAP_BUF_SIZE 128
+
+NET_BUF_POOL_DEFINE(zoap_nbuf_pool, 4, 0, sizeof(struct net_nbuf), NULL);
+NET_BUF_POOL_DEFINE(zoap_data_pool, 4, ZOAP_BUF_SIZE, 0, NULL);
+
+static const char *const test_path[] = { "test", NULL };
+
+static struct in6_addr mcast_addr = MCAST_IP_ADDR;
+
+struct dtls_timing_context {
+ uint32_t snapshot;
+ uint32_t int_ms;
+ uint32_t fin_ms;
+};
+
+static void msg_dump(const char *s, uint8_t *data, unsigned int len)
+{
+ unsigned int i;
+
+ printk("%s: ", s);
+ for (i = 0; i < len; i++) {
+ printk("%02x ", data[i]);
+ }
+
+ printk("(%u bytes)\n", len);
+}
+
+static int resource_reply_cb(const struct zoap_packet *response,
+ struct zoap_reply *reply,
+ const struct sockaddr *from)
+{
+
+ struct net_buf *frag = response->buf->frags;
+
+ while (frag) {
+ msg_dump("reply", frag->data, frag->len);
+ frag = frag->frags;
+ }
+
+ return 0;
+}
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line, const char *str)
+{
+ const char *p, *basename;
+
+ /* Extract basename from file */
+ for (p = basename = file; *p != '\0'; p++) {
+ if (*p == '/' || *p == '\\') {
+ basename = p + 1;
+ }
+ }
+
+ mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
+}
+
+void dtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
+{
+ struct dtls_timing_context *ctx = (struct dtls_timing_context *)data;
+
+ ctx->int_ms = int_ms;
+ ctx->fin_ms = fin_ms;
+
+ if (fin_ms != 0) {
+ ctx->snapshot = k_uptime_get_32();
+ }
+}
+
+int dtls_timing_get_delay(void *data)
+{
+ struct dtls_timing_context *ctx = (struct dtls_timing_context *)data;
+ unsigned long elapsed_ms;
+
+ if (ctx->fin_ms == 0) {
+ return -1;
+ }
+
+ elapsed_ms = k_uptime_get_32() - ctx->snapshot;
+
+ if (elapsed_ms >= ctx->fin_ms) {
+ return 2;
+ }
+
+ if (elapsed_ms >= ctx->int_ms) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int entropy_source(void *data, unsigned char *output, size_t len,
+ size_t *olen)
+{
+ uint32_t seed;
+ char *ptr = data;
+
+ seed = sys_rand32_get();
+
+ if (!seed) {
+ seed = 7;
+ }
+
+ for (int i = 0; i < len; i++) {
+ seed ^= seed << 13;
+ seed ^= seed >> 17;
+ seed ^= seed << 5;
+ *ptr++ = (char)seed;
+ }
+
+ *olen = len;
+ return 0;
+}
+
+void dtls_client(void)
+{
+ int ret;
+ struct udp_context ctx;
+ struct dtls_timing_context timer;
+ struct zoap_packet request, pkt;
+ struct zoap_reply *reply;
+ struct net_buf *nbuf, *frag;
+ uint8_t observe = 0;
+ const char *const *p;
+ uint16_t len;
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_platform_set_printf(printk);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_entropy_init(&entropy);
+ mbedtls_entropy_add_source(&entropy, entropy_source, NULL,
+ MBEDTLS_ENTROPY_MAX_GATHER,
+ MBEDTLS_ENTROPY_SOURCE_STRONG);
+
+ ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *)pers, strlen(pers));
+ if (ret != 0) {
+ mbedtls_printf("mbedtls_ctr_drbg_seed failed returned -0x%x\n",
+ -ret);
+ goto exit;
+ }
+
+ ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_DATAGRAM,
+ MBEDTLS_SSL_PRESET_DEFAULT);
+ if (ret != 0) {
+ mbedtls_printf("mbedtls_ssl_config_defaults"
+ " failed! returned -0x%x\n", -ret);
+ goto exit;
+ }
+
+/* Modify this to change the default timeouts for the DTLS handshake */
+/* mbedtls_ssl_conf_handshake_timeout( &conf, min, max ); */
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(DEBUG_THRESHOLD);
+#endif
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ mbedtls_memory_buffer_alloc_init(heap, sizeof(heap));
+#endif
+
+ ret = mbedtls_ssl_setup(&ssl, &conf);
+
+ if (ret != 0) {
+ mbedtls_printf("mbedtls_ssl_setup failed returned -0x%x\n",
+ -ret);
+ goto exit;
+ }
+
+ ret = udp_init(&ctx);
+ if (ret != 0) {
+ mbedtls_printf("udp_init failed returned 0x%x\n", ret);
+ goto exit;
+ }
+
+ udp_tx(&ctx, payload, 32);
+
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
+ ret = mbedtls_ssl_conf_psk(&conf, psk, strlen(psk), psk_id,
+ strlen(psk_id));
+ if (ret != 0) {
+ mbedtls_printf(" failed\n mbedtls_ssl_conf_psk"
+ " returned -0x%x\n", -ret);
+ goto exit;
+ }
+#endif
+
+ mbedtls_ssl_set_timer_cb(&ssl, &timer, dtls_timing_set_delay,
+ dtls_timing_get_delay);
+
+ mbedtls_ssl_set_bio(&ssl, &ctx, udp_tx, NULL, udp_rx);
+
+ do {
+ ret = mbedtls_ssl_handshake(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret != 0) {
+ mbedtls_printf("mbedtls_ssl_handshake failed returned -0x%x\n",
+ -ret);
+ goto exit;
+ }
+
+ /* Write to server */
+retry:
+ nbuf = net_buf_alloc(&zoap_nbuf_pool, K_NO_WAIT);
+ if (!nbuf) {
+ goto exit;
+ }
+
+ frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT);
+ if (!frag) {
+ goto exit;
+ }
+
+ net_buf_frag_add(nbuf, frag);
+
+ ret = zoap_packet_init(&request, nbuf);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ zoap_header_set_version(&request, 1);
+ zoap_header_set_type(&request, ZOAP_TYPE_CON);
+ zoap_header_set_code(&request, ZOAP_METHOD_GET);
+ zoap_header_set_id(&request, zoap_next_id());
+ zoap_header_set_token(&request, zoap_next_token(), 0);
+
+ /* Enable observing the resource. */
+ ret = zoap_add_option(&request, ZOAP_OPTION_OBSERVE,
+ &observe, sizeof(observe));
+ if (ret < 0) {
+ mbedtls_printf("Unable add option to request.\n");
+ goto exit;
+ }
+
+ for (p = test_path; p && *p; p++) {
+ ret = zoap_add_option(&request, ZOAP_OPTION_URI_PATH,
+ *p, strlen(*p));
+ if (ret < 0) {
+ mbedtls_printf("Unable add option/path to request.\n");
+ goto exit;
+ }
+ }
+
+ reply = zoap_reply_next_unused(replies, NUM_REPLIES);
+ if (!reply) {
+ mbedtls_printf("No resources for waiting for replies.\n");
+ goto exit;
+ }
+
+ zoap_reply_init(reply, &request);
+ reply->reply = resource_reply_cb;
+ len = frag->len;
+
+ do {
+ ret = mbedtls_ssl_write(&ssl, frag->data, len);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ net_buf_unref(nbuf);
+
+ if (ret <= 0) {
+ mbedtls_printf("mbedtls_ssl_write failed returned 0x%x\n",
+ -ret);
+ goto exit;
+ }
+
+ nbuf = net_buf_alloc(&zoap_nbuf_pool, K_NO_WAIT);
+ if (!nbuf) {
+ mbedtls_printf("Could not get buffer from pool\n");
+ goto exit;
+ }
+
+ frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT);
+ if (!frag) {
+ mbedtls_printf("Could not get frag from pool\n");
+ goto exit;
+ }
+
+ net_buf_frag_add(nbuf, frag);
+ len = ZOAP_BUF_SIZE - 1;
+ memset(frag->data, 0, ZOAP_BUF_SIZE);
+
+ do {
+ ret = mbedtls_ssl_read(&ssl, frag->data, ZOAP_BUF_SIZE - 1);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret <= 0) {
+ net_buf_unref(nbuf);
+
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_TIMEOUT:
+ mbedtls_printf(" timeout\n");
+ goto retry;
+
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed"
+ " gracefully\n");
+ goto exit;
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read"
+ " returned -0x%x\n", -ret);
+ goto exit;
+ }
+ }
+
+ len = ret;
+ frag->len = len;
+
+ ret = zoap_packet_parse(&pkt, nbuf);
+ if (ret) {
+ mbedtls_printf("Could not parse packet\n");
+ goto exit;
+ }
+
+ reply = zoap_response_received(&pkt, NULL, replies, NUM_REPLIES);
+ if (!reply) {
+ mbedtls_printf("No handler for response (%d)\n", ret);
+ }
+
+ net_buf_unref(nbuf);
+ mbedtls_ssl_close_notify(&ssl);
+exit:
+
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+}
+
+#define STACK_SIZE 4096
+uint8_t stack[STACK_SIZE];
+
+static inline int init_app(void)
+{
+#if defined(CONFIG_NET_SAMPLES_MY_IPV6_ADDR)
+ if (net_addr_pton(AF_INET6,
+ CONFIG_NET_SAMPLES_MY_IPV6_ADDR,
+ (struct sockaddr *)&client_addr) < 0) {
+ mbedtls_printf("Invalid IPv6 address %s",
+ CONFIG_NET_SAMPLES_MY_IPV6_ADDR);
+ }
+#endif
+ if (!net_if_ipv6_addr_add(net_if_get_default(), &client_addr,
+ NET_ADDR_MANUAL, 0)) {
+ return -EIO;
+ }
+
+ net_if_ipv6_maddr_add(net_if_get_default(), &mcast_addr);
+
+ return 0;
+}
+
+void main(void)
+{
+ if (init_app() != 0) {
+ printk("Cannot initialize network\n");
+ return;
+ }
+
+ k_thread_spawn(stack, STACK_SIZE, (k_thread_entry_t) dtls_client,
+ NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0);
+}
diff --git a/samples/net/coaps_client/src/udp.c b/samples/net/coaps_client/src/udp.c
new file mode 100644
index 000000000..2663c79a0
--- /dev/null
+++ b/samples/net/coaps_client/src/udp.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <net/net_core.h>
+#include <net/net_context.h>
+#include <net/nbuf.h>
+#include <net/net_if.h>
+#include <string.h>
+#include <errno.h>
+#include <misc/printk.h>
+
+#if !defined(CONFIG_MBEDTLS_CFG_FILE)
+#include "mbedtls/config.h"
+#else
+#include CONFIG_MBEDTLS_CFG_FILE
+#endif
+#include "mbedtls/ssl.h"
+
+#include "udp_cfg.h"
+#include "udp.h"
+
+static struct in6_addr server_addr;
+static struct in6_addr mcast_addr = MCAST_IP_ADDR;
+static const socklen_t addrlen = sizeof(struct sockaddr_in6);
+
+static void set_destination(struct sockaddr *addr)
+{
+ struct sockaddr_in6 *dst_addr = (struct sockaddr_in6 *)addr;
+
+ net_ipaddr_copy(&dst_addr->sin6_addr, &server_addr);
+ dst_addr->sin6_family = AF_INET6;
+ dst_addr->sin6_port = htons(SERVER_PORT);
+}
+
+static void udp_received(struct net_context *context,
+ struct net_buf *buf, int status, void *user_data)
+{
+ struct udp_context *ctx = user_data;
+
+ ARG_UNUSED(context);
+ ARG_UNUSED(status);
+
+ ctx->rx_nbuf = buf;
+ k_sem_give(&ctx->rx_sem);
+}
+
+int udp_tx(void *context, const unsigned char *buf, size_t size)
+{
+ struct udp_context *ctx = context;
+ struct net_context *udp_ctx;
+ struct net_buf *send_buf;
+ struct sockaddr dst_addr;
+ int rc, len;
+
+ udp_ctx = ctx->net_ctx;
+
+ send_buf = net_nbuf_get_tx(udp_ctx);
+ if (!send_buf) {
+ return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ }
+
+ rc = net_nbuf_append(send_buf, size, (uint8_t *) buf);
+ if (!rc) {
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
+
+ set_destination(&dst_addr);
+ len = net_buf_frags_len(send_buf);
+ k_sleep(UDP_TX_TIMEOUT);
+
+ rc = net_context_sendto(send_buf, &dst_addr,
+ addrlen, NULL, K_FOREVER, NULL, NULL);
+ if (rc < 0) {
+ net_nbuf_unref(send_buf);
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ } else {
+ return len;
+ }
+}
+
+int udp_rx(void *context, unsigned char *buf, size_t size, uint32_t timeout)
+{
+ struct udp_context *ctx = context;
+ struct net_buf *rx_buf = NULL;
+ uint16_t read_bytes;
+ uint8_t *ptr;
+ int pos;
+ int len;
+ int rc;
+
+ rc = k_sem_take(&ctx->rx_sem, timeout == 0 ? K_FOREVER : timeout);
+ if (rc != 0) {
+ return MBEDTLS_ERR_SSL_TIMEOUT;
+ }
+
+ read_bytes = net_nbuf_appdatalen(ctx->rx_nbuf);
+ if (read_bytes > size) {
+ return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ }
+
+ ptr = net_nbuf_appdata(ctx->rx_nbuf);
+ rx_buf = ctx->rx_nbuf->frags;
+ len = rx_buf->len - (ptr - rx_buf->data);
+ pos = 0;
+
+ while (rx_buf) {
+ memcpy(buf + pos, ptr, len);
+ pos += len;
+
+ rx_buf = rx_buf->frags;
+ if (!rx_buf) {
+ break;
+ }
+
+ ptr = rx_buf->data;
+ len = rx_buf->len;
+ }
+
+ net_nbuf_unref(ctx->rx_nbuf);
+ ctx->rx_nbuf = NULL;
+
+ if (read_bytes != pos) {
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
+
+ rc = read_bytes;
+ ctx->remaining = 0;
+
+ return rc;
+}
+
+int udp_init(struct udp_context *ctx)
+{
+ struct net_context *udp_ctx = { 0 };
+ struct net_context *mcast_ctx = { 0 };
+ struct sockaddr_in6 my_addr = { 0 };
+ struct sockaddr_in6 my_mcast_addr = { 0 };
+ int rc;
+
+ k_sem_init(&ctx->rx_sem, 0, UINT_MAX);
+
+ net_ipaddr_copy(&my_mcast_addr.sin6_addr, &mcast_addr);
+ my_mcast_addr.sin6_family = AF_INET6;
+
+ net_ipaddr_copy(&my_addr.sin6_addr, &client_addr);
+ my_addr.sin6_family = AF_INET6;
+ my_addr.sin6_port = htons(CLIENT_PORT);
+
+ rc = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &udp_ctx);
+ if (rc < 0) {
+ printk("Cannot get network context for IPv6 UDP (%d)", rc);
+ return -EIO;
+ }
+
+ rc = net_context_bind(udp_ctx, (struct sockaddr *)&my_addr,
+ sizeof(struct sockaddr_in6));
+ if (rc < 0) {
+ printk("Cannot bind IPv6 UDP port %d (%d)", CLIENT_PORT, rc);
+ goto error;
+ }
+
+ rc = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &mcast_ctx);
+ if (rc < 0) {
+ printk("Cannot get receiving IPv6 mcast (%d)", rc);
+ goto error;
+ }
+
+ rc = net_context_bind(mcast_ctx, (struct sockaddr *)&my_mcast_addr,
+ sizeof(struct sockaddr_in6));
+ if (rc < 0) {
+ printk("Cannot get bind IPv6 mcast (%d)", rc);
+ goto error;
+ }
+
+ ctx->rx_nbuf = NULL;
+ ctx->remaining = 0;
+ ctx->net_ctx = udp_ctx;
+
+#if defined(CONFIG_NET_SAMPLES_PEER_IPV6_ADDR)
+ if (net_addr_pton(AF_INET6,
+ CONFIG_NET_SAMPLES_PEER_IPV6_ADDR,
+ (struct sockaddr *)&server_addr) < 0) {
+ printk("Invalid peer IPv6 address %s",
+ CONFIG_NET_SAMPLES_PEER_IPV6_ADDR);
+ }
+#endif
+
+ rc = net_context_recv(ctx->net_ctx, udp_received, K_NO_WAIT, ctx);
+ if (rc != 0) {
+ return -EIO;
+ }
+
+ return 0;
+
+error:
+ net_context_put(udp_ctx);
+ return -EINVAL;
+}
diff --git a/samples/net/coaps_client/src/udp.h b/samples/net/coaps_client/src/udp.h
new file mode 100644
index 000000000..7d96b3045
--- /dev/null
+++ b/samples/net/coaps_client/src/udp.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#include <net/net_core.h>
+
+struct udp_context {
+ struct net_context *net_ctx;
+ struct net_buf *rx_nbuf;
+ struct k_sem rx_sem;
+ int remaining;
+};
+
+int udp_init(struct udp_context *ctx);
+int udp_tx(void *ctx, const unsigned char *buf, size_t size);
+int udp_rx(void *ctx, unsigned char *buf, size_t size, uint32_t timeout);
+
+#endif
diff --git a/samples/net/coaps_client/src/udp_cfg.h b/samples/net/coaps_client/src/udp_cfg.h
new file mode 100644
index 000000000..d6cc6b6c6
--- /dev/null
+++ b/samples/net/coaps_client/src/udp_cfg.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef UDP_CONFIG_H_
+#define UDP_CONFIG_H_
+
+/* admin-local, dynamically allocated multicast address */
+#define MCAST_IP_ADDR { { { 0xff, 0x84, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0x2 } } }
+
+static struct in6_addr client_addr;
+
+#define SERVER_PORT 5684
+#define CLIENT_PORT 8484
+
+#define UDP_TX_TIMEOUT 100 /* Timeout in milliseconds */
+
+#endif
diff --git a/samples/net/coaps_client/testcase.ini b/samples/net/coaps_client/testcase.ini
new file mode 100644
index 000000000..bd398cafe
--- /dev/null
+++ b/samples/net/coaps_client/testcase.ini
@@ -0,0 +1,4 @@
+[test]
+tags = net
+build_only = true
+arch_whitelist = qemu_x86 arduino_101