From 0ab8aae5292e8bb0586df696cdd5b48421e25ce2 Mon Sep 17 00:00:00 2001 From: Martine Lenders <mlenders@inf.fu-berlin.de> Date: Sun, 7 Feb 2016 19:50:51 +0100 Subject: [PATCH] emb6: add conn_udp wrapper --- Makefile.dep | 23 ++ pkg/emb6/Makefile.include | 4 + pkg/emb6/contrib/conn/udp/Makefile | 3 + pkg/emb6/contrib/conn/udp/emb6_conn_udp.c | 244 ++++++++++++++++++++++ pkg/emb6/include/emb6/conn/udp.h | 62 ++++++ sys/include/net/conn/udp.h | 4 + 6 files changed, 340 insertions(+) create mode 100644 pkg/emb6/contrib/conn/udp/Makefile create mode 100644 pkg/emb6/contrib/conn/udp/emb6_conn_udp.c create mode 100644 pkg/emb6/include/emb6/conn/udp.h diff --git a/Makefile.dep b/Makefile.dep index 9aa67841c8..90c3ec01eb 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -357,6 +357,10 @@ ifneq (,$(filter posix_semaphore,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter emb6_conn_udp,$(USEMODULE))) + USEMODULE += emb6_sock +endif + ifneq (,$(filter emb6_%,$(USEMODULE))) USEMODULE += emb6 endif @@ -430,6 +434,25 @@ ifneq (,$(filter lwip_contrib,$(USEMODULE))) USEMODULE += sema endif +ifneq (,$(filter emb6_%,$(USEMODULE))) + USEMODULE += emb6 +endif + +ifneq (,$(filter emb6,$(USEMODULE))) + USEPKG += emb6 + USEMODULE += emb6_bsp + USEMODULE += emb6_common + USEMODULE += emb6_contrib + USEMODULE += emb6_ipv6 + USEMODULE += emb6_ipv6_multicast + USEMODULE += emb6_llsec + USEMODULE += emb6_mac + USEMODULE += emb6_netdev2 + USEMODULE += emb6_rpl + USEMODULE += emb6_sicslowpan + USEMODULE += emb6_utils +endif + ifneq (,$(filter sema,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/pkg/emb6/Makefile.include b/pkg/emb6/Makefile.include index e1236c8b8d..090cebac9c 100644 --- a/pkg/emb6/Makefile.include +++ b/pkg/emb6/Makefile.include @@ -22,6 +22,10 @@ ifneq (,$(filter emb6_contrib,$(USEMODULE))) DIRS += $(EMB6_CONTRIB) endif +ifneq (,$(filter emb6_conn_udp,$(USEMODULE))) + DIRS += $(EMB6_CONTRIB)/conn/udp +endif + ifneq (,$(filter emb6_ipv6,$(USEMODULE))) DIRS += $(EMB6_DIR)/emb6/src/net/ipv6 INCLUDES += -I$(EMB6_DIR)/emb6/inc/net/ipv6 diff --git a/pkg/emb6/contrib/conn/udp/Makefile b/pkg/emb6/contrib/conn/udp/Makefile new file mode 100644 index 0000000000..e5dbafaedd --- /dev/null +++ b/pkg/emb6/contrib/conn/udp/Makefile @@ -0,0 +1,3 @@ +MODULE = emb6_conn_udp + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/emb6/contrib/conn/udp/emb6_conn_udp.c b/pkg/emb6/contrib/conn/udp/emb6_conn_udp.c new file mode 100644 index 0000000000..bbd488edfe --- /dev/null +++ b/pkg/emb6/contrib/conn/udp/emb6_conn_udp.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> + +#include "evproc.h" +#include "msg.h" +#include "mutex.h" +#include "net/af.h" +#include "net/conn/udp.h" +#include "net/ipv6/hdr.h" +#include "sched.h" +#include "uip.h" + +#define _MSG_TYPE_CLOSE (0x4123) +#define _MSG_TYPE_RCV (0x4124) + +/* struct to describe a sendto command for emb6 thread */ +typedef struct { + struct udp_socket sock; + mutex_t mutex; + const void *data; + int res; + uint16_t data_len; +} _send_cmd_t; + +extern uint16_t uip_slen; + +static bool send_registered = false; + +static void _input_callback(struct udp_socket *c, void *ptr, + const uip_ipaddr_t *src_addr, uint16_t src_port, + const uip_ipaddr_t *dst_addr, uint16_t dst_port, + const uint8_t *data, uint16_t datalen); +static void _output_callback(c_event_t c_event, p_data_t p_data); + +static int _reg_and_bind(struct udp_socket *c, void *ptr, + udp_socket_input_callback_t cb, uint16_t port) +{ + if (udp_socket_register(c, ptr, cb) < 0) { + return -EMFILE; + } + if (udp_socket_bind(c, port) < 0) { + udp_socket_close(c); + return -EALREADY; + } + return 0; +} + +int conn_udp_create(conn_udp_t *conn, const void *addr, size_t addr_len, + int family, uint16_t port) +{ + int res; + + (void)addr; + (void)addr_len; + if (family != AF_INET6) { + return -EAFNOSUPPORT; + } + if (conn->sock.input_callback != NULL) { + return -EINVAL; + } + mutex_init(&conn->mutex); + mutex_lock(&conn->mutex); + if ((res = _reg_and_bind(&conn->sock, conn, _input_callback, port)) < 0) { + conn->sock.input_callback = NULL; + mutex_unlock(&conn->mutex); + return res; + } + conn->waiting_thread = KERNEL_PID_UNDEF; + mutex_unlock(&conn->mutex); + return 0; +} + +void conn_udp_close(conn_udp_t *conn) +{ + if (conn->sock.input_callback != NULL) { + mutex_lock(&conn->mutex); + if (conn->waiting_thread != KERNEL_PID_UNDEF) { + msg_t msg; + msg.type = _MSG_TYPE_CLOSE; + msg.content.ptr = (char *)conn; + mutex_unlock(&conn->mutex); + msg_send(&msg, conn->waiting_thread); + mutex_lock(&conn->mutex); + } + udp_socket_close(&conn->sock); + conn->sock.input_callback = NULL; + mutex_unlock(&conn->mutex); + } +} + +int conn_udp_getlocaladdr(conn_udp_t *conn, void *addr, uint16_t *port) +{ + if (conn->sock.input_callback != NULL) { + mutex_lock(&conn->mutex); + memset(addr, 0, sizeof(ipv6_addr_t)); + *port = NTOHS(conn->sock.udp_conn->lport); + mutex_unlock(&conn->mutex); + return sizeof(ipv6_addr_t); + } + return -EBADF; +} + +int conn_udp_recvfrom(conn_udp_t *conn, void *data, size_t max_len, void *addr, + size_t *addr_len, uint16_t *port) +{ + int res = -EIO; + msg_t msg; + + if (conn->sock.input_callback == NULL) { + return -ENOTSOCK; + } + mutex_lock(&conn->mutex); + if (conn->waiting_thread != KERNEL_PID_UNDEF) { + mutex_unlock(&conn->mutex); + return -EALREADY; + } + conn->waiting_thread = sched_active_pid; + mutex_unlock(&conn->mutex); + msg_receive(&msg); + if (msg.type == _MSG_TYPE_CLOSE) { + conn->waiting_thread = KERNEL_PID_UNDEF; + return -EINTR; + } + else if (msg.type == _MSG_TYPE_RCV) { + mutex_lock(&conn->mutex); + if (msg.content.ptr == (char *)conn) { + if (max_len < conn->recv_info.datalen) { + conn->waiting_thread = KERNEL_PID_UNDEF; + mutex_unlock(&conn->mutex); + return -ENOBUFS; + } + memcpy(data, conn->recv_info.data, conn->recv_info.datalen); + memcpy(addr, conn->recv_info.src, sizeof(ipv6_addr_t)); + *addr_len = sizeof(ipv6_addr_t); + *port = conn->recv_info.src_port; + res = (int)conn->recv_info.datalen; + } + conn->waiting_thread = KERNEL_PID_UNDEF; + mutex_unlock(&conn->mutex); + } + return res; +} + +int conn_udp_sendto(const void *data, size_t len, const void *src, size_t src_len, + const void *dst, size_t dst_len, int family, uint16_t sport, + uint16_t dport) +{ + int res; + _send_cmd_t send_cmd; + + if (!send_registered) { + if (evproc_regCallback(EVENT_TYPE_CONN_SEND, _output_callback) != E_SUCCESS) { + return -EIO; + } + else { + send_registered = true; + } + } + mutex_init(&send_cmd.mutex); + if ((len > (UIP_BUFSIZE - (UIP_LLH_LEN + UIP_IPUDPH_LEN))) || + (len > UINT16_MAX)) { + return -EMSGSIZE; + } + if ((dst_len > sizeof(ipv6_addr_t)) || (family != AF_INET6)) { + return -EAFNOSUPPORT; + } + mutex_lock(&send_cmd.mutex); + send_cmd.data = data; + send_cmd.data_len = (uint16_t)len; + if ((res = _reg_and_bind(&send_cmd.sock, NULL, NULL, sport)) < 0) { + mutex_unlock(&send_cmd.mutex); + return res; + } + udp_socket_connect(&send_cmd.sock, (uip_ipaddr_t *)dst, dport); /* can't fail at this point */ + /* change to emb6 thread context */ + if (evproc_putEvent(E_EVPROC_TAIL, EVENT_TYPE_CONN_SEND, &send_cmd) != E_SUCCESS) { + udp_socket_close(&send_cmd.sock); + mutex_unlock(&send_cmd.mutex); + return -EIO; + } + /* block thread until data was send */ + mutex_lock(&send_cmd.mutex); + udp_socket_close(&send_cmd.sock); + mutex_unlock(&send_cmd.mutex); + + return send_cmd.res; +} + +static void _input_callback(struct udp_socket *c, void *ptr, + const uip_ipaddr_t *src_addr, uint16_t src_port, + const uip_ipaddr_t *dst_addr, uint16_t dst_port, + const uint8_t *data, uint16_t datalen) +{ + conn_udp_t *conn = ptr; + + (void)dst_addr; + (void)dst_port; + mutex_lock(&conn->mutex); + if (conn->waiting_thread != KERNEL_PID_UNDEF) { + msg_t msg; + conn->recv_info.src_port = src_port; + conn->recv_info.src = (const ipv6_addr_t *)src_addr; + conn->recv_info.data = data; + conn->recv_info.datalen = datalen - sizeof(ipv6_hdr_t); + msg.type = _MSG_TYPE_RCV; + msg.content.ptr = (char *)conn; + mutex_unlock(&conn->mutex); + msg_send(&msg, conn->waiting_thread); + } + else { + mutex_unlock(&conn->mutex); + } +} + +static void _output_callback(c_event_t c_event, p_data_t p_data) +{ + _send_cmd_t *send_cmd = (_send_cmd_t *)p_data; + + if ((c_event != EVENT_TYPE_CONN_SEND) || (p_data == NULL)) { + return; + } + if ((send_cmd->res = udp_socket_send(&send_cmd->sock, send_cmd->data, send_cmd->data_len)) < 0) { + send_cmd->res = -EHOSTUNREACH; + } + mutex_unlock(&send_cmd->mutex); +} + +/** @} */ diff --git a/pkg/emb6/include/emb6/conn/udp.h b/pkg/emb6/include/emb6/conn/udp.h new file mode 100644 index 0000000000..dc835ca06b --- /dev/null +++ b/pkg/emb6/include/emb6/conn/udp.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup emb6_conn_udp udp_conn wrapper for emb6 + * @ingroup emb6 + * @brief UDP conn for emb6 + * + * For this implementation to receive with an open connection only with one + * thread at once. If you use @ref conn_udp_recvfrom() with more than one thread + * simultaneously, it will return `-EALREADY`. + * + * @{ + * + * @file + * @brief UDP conn definitions + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef EMB6_CONN_UDP_H_ +#define EMB6_CONN_UDP_H_ + +#include <stdint.h> + +#include "kernel_types.h" +#include "mutex.h" +#include "net/ipv6/addr.h" + +#include "uip.h" +#include "udp-socket.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief @ref net_conn_udp definition for emb6 + */ +struct conn_udp { + struct udp_socket sock; /**< emb6 internal socket */ + mutex_t mutex; /**< mutex for the connection */ + kernel_pid_t waiting_thread; /**< thread waiting for an incoming packet + * on this connection */ + struct { + uint16_t src_port; /**< source port */ + const ipv6_addr_t *src; /**< source address */ + const void *data; /**< data of received packet */ + size_t datalen; /**< length of received packet data */ + } recv_info; /**< info on received packet */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EMB6_CONN_UDP_H_ */ +/** @} */ diff --git a/sys/include/net/conn/udp.h b/sys/include/net/conn/udp.h index 2e400a0cf7..b59ac07ce4 100644 --- a/sys/include/net/conn/udp.h +++ b/sys/include/net/conn/udp.h @@ -31,6 +31,10 @@ #include "lwip/conn.h" #endif +#ifdef MODULE_EMB6_CONN_UDP +#include "emb6/conn/udp.h" +#endif + #ifdef __cplusplus extern "C" { #endif -- GitLab