summaryrefslogtreecommitdiff
path: root/samples/net/coaps_client/src/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'samples/net/coaps_client/src/udp.c')
-rw-r--r--samples/net/coaps_client/src/udp.c202
1 files changed, 202 insertions, 0 deletions
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;
+}