From ef9acf6aeee42647f7a11eb1538b393b8aa8afab Mon Sep 17 00:00:00 2001 From: Martine Lenders <mlenders@inf.fu-berlin.de> Date: Wed, 12 Aug 2015 05:41:02 +0200 Subject: [PATCH] gnrc: add GNRC-specific conn implementation --- Makefile.dep | 8 ++ sys/include/net/conn/ip.h | 4 + sys/include/net/conn/tcp.h | 4 + sys/include/net/conn/udp.h | 4 + sys/include/net/gnrc/conn.h | 130 +++++++++++++++++++++++++ sys/net/gnrc/Makefile | 9 ++ sys/net/gnrc/conn/Makefile | 3 + sys/net/gnrc/conn/gnrc_conn.c | 115 ++++++++++++++++++++++ sys/net/gnrc/conn/ip/Makefile | 3 + sys/net/gnrc/conn/ip/gnrc_conn_ip.c | 128 ++++++++++++++++++++++++ sys/net/gnrc/conn/udp/Makefile | 3 + sys/net/gnrc/conn/udp/gnrc_conn_udp.c | 135 ++++++++++++++++++++++++++ 12 files changed, 546 insertions(+) create mode 100644 sys/include/net/gnrc/conn.h create mode 100644 sys/net/gnrc/conn/Makefile create mode 100644 sys/net/gnrc/conn/gnrc_conn.c create mode 100644 sys/net/gnrc/conn/ip/Makefile create mode 100644 sys/net/gnrc/conn/ip/gnrc_conn_ip.c create mode 100644 sys/net/gnrc/conn/udp/Makefile create mode 100644 sys/net/gnrc/conn/udp/gnrc_conn_udp.c diff --git a/Makefile.dep b/Makefile.dep index 28af0d2319..3f6ef658a8 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -10,6 +10,14 @@ ifneq (,$(filter gnrc_%,$(filter-out gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pk USEMODULE += gnrc endif +ifneq (,$(filter gnrc_conn_%,$(USEMODULE))) + USEMODULE += gnrc_conn +endif + +ifneq (,$(filter gnrc_conn_udp,$(USEMODULE))) + USEMODULE += gnrc_udp +endif + ifneq (,$(filter schedstatistics,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/sys/include/net/conn/ip.h b/sys/include/net/conn/ip.h index 061ed967ed..ee7cf92081 100644 --- a/sys/include/net/conn/ip.h +++ b/sys/include/net/conn/ip.h @@ -23,6 +23,10 @@ #include <stdint.h> #include <stdlib.h> +#ifdef MODULE_GNRC_CONN_IP +#include "net/gnrc/conn.h" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/sys/include/net/conn/tcp.h b/sys/include/net/conn/tcp.h index 508e9e7478..aa02fa7e04 100644 --- a/sys/include/net/conn/tcp.h +++ b/sys/include/net/conn/tcp.h @@ -23,6 +23,10 @@ #include <stdint.h> #include <stdlib.h> +#ifdef MODULE_GNRC_CONN_TCP +#include "net/gnrc/conn.h" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/sys/include/net/conn/udp.h b/sys/include/net/conn/udp.h index a91c9f4346..68b40323fa 100644 --- a/sys/include/net/conn/udp.h +++ b/sys/include/net/conn/udp.h @@ -23,6 +23,10 @@ #include <stdint.h> #include <stdlib.h> +#ifdef MODULE_GNRC_CONN_UDP +#include "net/gnrc/conn.h" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/sys/include/net/gnrc/conn.h b/sys/include/net/gnrc/conn.h new file mode 100644 index 0000000000..f8e53efd0f --- /dev/null +++ b/sys/include/net/gnrc/conn.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * 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 net_gnrc_conn GNRC-specific @ref net_conn implementation + * @ingroup net_gnrc + * @brief GNRC-specific @ref net_conn implementation + * @{ + * + * @file + * @brief GNRC-specific types and function definitions + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef GNRC_CONN_H_ +#define GNRC_CONN_H_ + +#include <stdbool.h> +#include <stdint.h> +#include "net/ipv6/addr.h" +#include "net/gnrc.h" +#include "sched.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Connection base class + * @internal + */ +typedef struct { + gnrc_nettype_t l3_type; /**< Network layer type of the connection */ + gnrc_nettype_t l4_type; /**< Transport layer type of the connection */ + gnrc_netreg_entry_t netreg_entry; /**< @p net_ng_netreg entry for the connection */ +} conn_t; + +/** + * @brief Raw connection type + * @internal + * @extends conn_t + */ +struct conn_ip { + gnrc_nettype_t l3_type; /**< Network layer type of the connection. */ + gnrc_nettype_t l4_type; /**< Transport layer type of the connection. + * Always GNRC_NETTYPE_UNDEF */ + gnrc_netreg_entry_t netreg_entry; /**< @p net_ng_netreg entry for the connection */ + uint8_t local_addr[sizeof(ipv6_addr_t)]; /**< local IP address */ + size_t local_addr_len; /**< length of struct conn_ip::local_addr */ +}; + +/** + * @brief UDP connection type + * @internal + * @extends conn_t + */ +struct conn_udp { + gnrc_nettype_t l3_type; /**< Network layer type of the connection. + * Always GNRC_NETTYPE_IPV6 */ + gnrc_nettype_t l4_type; /**< Transport layer type of the connection. + * Always GNRC_NETTYPE_UDP */ + gnrc_netreg_entry_t netreg_entry; /**< @p net_ng_netreg entry for the connection */ + uint8_t local_addr[sizeof(ipv6_addr_t)]; /**< local IP address */ + size_t local_addr_len; /**< length of struct conn_ip::local_addr */ +}; + +/** + * @brief Bind connection to demux context + * + * @internal + * + * @param[out] entry @ref net_ng_netreg entry. + * @param[in] type @ref net_ng_nettype. + * @param[in] demux_ctx demux context (port or proto) for the connection. + */ +static inline void gnrc_conn_reg(gnrc_netreg_entry_t *entry, gnrc_nettype_t type, + uint32_t demux_ctx) +{ + entry->pid = sched_active_pid; + entry->demux_ctx = demux_ctx; + gnrc_netreg_register(type, entry); +} + +/** + * @brief Sets local address for a connection + * + * @internal + * + * @param[out] conn_addr Pointer to the local address on the connection. + * @param[in] addr An IPv6 address. + * + * @return true, if @p addr was a legal address (`::`, `::1` or an address assigned to any + * interface of this node) for the connection. + * @return false if @p addr was not a legal address for the connection. + */ +bool gnrc_conn6_set_local_addr(uint8_t *conn_addr, const ipv6_addr_t *addr); + +/** + * @brief Generic recvfrom + * + * @internal + * + * @param[in] conn Connection object. + * @param[out] data Pointer where the received data should be stored. + * @param[in] max_len Maximum space available at @p data. + * @param[out] addr NULL pointer or the sender's IP address. Must fit address of connection's + * family if not NULL. + * @param[out] addr_len Length of @p addr. May be NULL if @p addr is NULL. + * @param[out] port NULL pointer or the sender's port. + * + * @return The number of bytes received on success. + * @return 0, if no received data is available, but everything is in order. + * @return -ENOMEM, if received data was more than max_len. + * @returne -ETIMEDOUT, if more than 3 IPC messages were not @ref net_ng_netapi receive commands + * with the required headers in the packet + */ +int gnrc_conn_recvfrom(conn_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len, + uint16_t *port); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_CONN_H_ */ +/** @} */ diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index 0b577bdd88..cc7f891353 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -1,3 +1,12 @@ +ifneq (,$(filter gnrc_conn,$(USEMODULE))) + DIRS += conn +endif +ifneq (,$(filter gnrc_conn_ip,$(USEMODULE))) + DIRS += conn/ip +endif +ifneq (,$(filter gnrc_conn_udp,$(USEMODULE))) + DIRS += conn/udp +endif ifneq (,$(filter gnrc_icmpv6,$(USEMODULE))) DIRS += network_layer/icmpv6 endif diff --git a/sys/net/gnrc/conn/Makefile b/sys/net/gnrc/conn/Makefile new file mode 100644 index 0000000000..a9b8d3687a --- /dev/null +++ b/sys/net/gnrc/conn/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_conn + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/conn/gnrc_conn.c b/sys/net/gnrc/conn/gnrc_conn.c new file mode 100644 index 0000000000..dfe0648327 --- /dev/null +++ b/sys/net/gnrc/conn/gnrc_conn.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * 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 "net/conn.h" +#include "net/ipv6/hdr.h" +#include "net/gnrc/conn.h" +#include "net/gnrc/ipv6/hdr.h" +#include "net/gnrc/ipv6/netif.h" +#include "net/udp.h" + +static inline size_t _srcaddr(void *addr, gnrc_pktsnip_t *hdr) +{ + switch (hdr->type) { +#ifdef MODULE_GNRC_IPV6 + case GNRC_NETTYPE_IPV6: + memcpy(addr, &((ipv6_hdr_t *)hdr->data)->src, sizeof(ipv6_addr_t)); + return sizeof(ipv6_addr_t); +#endif + default: + (void)addr; + return 0; + } +} + +static inline void _srcport(uint16_t *port, gnrc_pktsnip_t *hdr) +{ + switch (hdr->type) { +#ifdef MODULE_GNRC_UDP + case GNRC_NETTYPE_UDP: + memcpy(port, &((udp_hdr_t *)hdr->data)->src_port, sizeof(uint16_t)); + break; +#endif + default: + (void)port; + (void)hdr; + break; + } +} + +int gnrc_conn_recvfrom(conn_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len, + uint16_t *port) +{ + msg_t msg; + int timeout = 3; + while ((timeout--) > 0) { + gnrc_pktsnip_t *pkt, *l3hdr; + msg_receive(&msg); + switch (msg.type) { + case GNRC_NETAPI_MSG_TYPE_RCV: + pkt = (gnrc_pktsnip_t *)msg.content.ptr; + if (pkt->size > max_len) { + return -ENOMEM; + } + LL_SEARCH_SCALAR(pkt, l3hdr, type, conn->l3_type); + if (l3hdr == NULL) { + msg_send_to_self(&msg); /* requeue invalid messages */ + continue; + } +#if defined(MODULE_CONN_UDP) || defined(MODULE_CONN_TCP) + if ((conn->l4_type != GNRC_NETTYPE_UNDEF) && (port != NULL)) { + gnrc_pktsnip_t *l4hdr; + LL_SEARCH_SCALAR(pkt, l4hdr, type, conn->l4_type); + if (l4hdr == NULL) { + msg_send_to_self(&msg); /* requeue invalid messages */ + continue; + } + _srcport(port, l4hdr); + } +#endif /* defined(MODULE_CONN_UDP) */ + if (addr != NULL) { + *addr_len = _srcaddr(addr, l3hdr); + } + memcpy(data, pkt->data, pkt->size); + return pkt->size; + default: + (void)port; + msg_send_to_self(&msg); /* requeue invalid messages */ + break; + } + } + return -ETIMEDOUT; +} + +#ifdef MODULE_GNRC_IPV6 +bool gnrc_conn6_set_local_addr(uint8_t *conn_addr, const ipv6_addr_t *addr) +{ + ipv6_addr_t *tmp; + if (!ipv6_addr_is_unspecified(addr) && + !ipv6_addr_is_loopback(addr) && + gnrc_ipv6_netif_find_by_addr(&tmp, addr) == KERNEL_PID_UNDEF) { + return false; + } + else if (ipv6_addr_is_loopback(addr) || ipv6_addr_is_unspecified(addr)) { + ipv6_addr_set_unspecified((ipv6_addr_t *)conn_addr); + } + else { + memcpy(conn_addr, addr, sizeof(ipv6_addr_t)); + } + return true; +} +#endif + +/** @} */ diff --git a/sys/net/gnrc/conn/ip/Makefile b/sys/net/gnrc/conn/ip/Makefile new file mode 100644 index 0000000000..bf3473a0b1 --- /dev/null +++ b/sys/net/gnrc/conn/ip/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_conn_ip + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/conn/ip/gnrc_conn_ip.c b/sys/net/gnrc/conn/ip/gnrc_conn_ip.c new file mode 100644 index 0000000000..52896703f4 --- /dev/null +++ b/sys/net/gnrc/conn/ip/gnrc_conn_ip.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * 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 <errno.h> +#include "net/af.h" +#include "net/gnrc/conn.h" +#include "net/gnrc/ipv6.h" + +#include "net/conn/ip.h" + +int conn_ip_create(conn_ip_t *conn, const void *addr, size_t addr_len, int family, int proto) +{ + switch (family) { +#ifdef MODULE_GNRC_IPV6 + case AF_INET6: + if (addr_len != sizeof(ipv6_addr_t)) { + return -EINVAL; + } + if (gnrc_conn6_set_local_addr(conn->local_addr, addr)) { + conn->l3_type = GNRC_NETTYPE_IPV6; + conn->local_addr_len = addr_len; + conn_ip_close(conn); /* unregister possibly registered netreg entry */ + gnrc_conn_reg(&conn->netreg_entry, conn->l3_type, (uint32_t)proto); + } + else { + return -EADDRNOTAVAIL; + } + break; +#endif + default: + (void)addr; + (void)addr_len; + (void)proto; + return -EAFNOSUPPORT; + } + conn->l4_type = GNRC_NETTYPE_UNDEF; + return 0; +} + +void conn_ip_close(conn_ip_t *conn) +{ + assert(conn->l4_type == GNRC_NETTYPE_UNDEF); + if (conn->netreg_entry.pid != KERNEL_PID_UNDEF) { + gnrc_netreg_unregister(conn->l3_type, &conn->netreg_entry); + } +} + +int conn_ip_getlocaladdr(conn_ip_t *conn, void *addr) +{ + assert(conn->l4_type == GNRC_NETTYPE_UNDEF); + memcpy(addr, &conn->local_addr, conn->local_addr_len); + return conn->local_addr_len; +} + +int conn_ip_recvfrom(conn_ip_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len) +{ + assert(conn->l4_type == GNRC_NETTYPE_UNDEF); + switch (conn->l3_type) { +#ifdef MODULE_GNRC_IPV6 + case GNRC_NETTYPE_IPV6: + return gnrc_conn_recvfrom((conn_t *)conn, data, max_len, addr, addr_len, NULL); +#endif + default: + (void)data; + (void)max_len; + (void)addr; + (void)addr_len; + return -EBADF; + } +} + +int conn_ip_sendto(const void *data, size_t len, const void *src, size_t src_len, + void *dst, size_t dst_len, int family, int proto) +{ + gnrc_pktsnip_t *pkt, *hdr = NULL; + gnrc_nettype_t l3_type; + + pkt = gnrc_pktbuf_add(NULL, (void *)data, len, GNRC_NETTYPE_UNDEF); /* data will only be copied */ + + switch (family) { +#ifdef MODULE_GNRC_IPV6 + case AF_INET6: + if (((src != NULL) && (src_len != sizeof(ipv6_addr_t))) || + (dst_len != sizeof(ipv6_addr_t)) || + (((unsigned)proto) > 256U)) { + gnrc_pktbuf_release(pkt); + return -EINVAL; + } + /* addr will only be copied */ + hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst, dst_len); + if (hdr == NULL) { + gnrc_pktbuf_release(pkt); + return -ENOMEM; + } + /* set next header to connection's proto */ + ipv6_hdr_t *ipv6_hdr = hdr->data; + ipv6_hdr->nh = (uint8_t)proto; + pkt = hdr; + l3_type = GNRC_NETTYPE_IPV6; + break; +#endif /* MODULE_GNRC_IPV6 */ + default: + (void)src; + (void)src_len; + (void)dst; + (void)dst_len; + (void)proto; + (void)hdr; + gnrc_pktbuf_release(pkt); + return -EAFNOSUPPORT; + } + + gnrc_netapi_dispatch_send(l3_type, GNRC_NETREG_DEMUX_CTX_ALL, pkt); + + return len; +} diff --git a/sys/net/gnrc/conn/udp/Makefile b/sys/net/gnrc/conn/udp/Makefile new file mode 100644 index 0000000000..ed44cc6afd --- /dev/null +++ b/sys/net/gnrc/conn/udp/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_conn_udp + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/conn/udp/gnrc_conn_udp.c b/sys/net/gnrc/conn/udp/gnrc_conn_udp.c new file mode 100644 index 0000000000..0aa9212173 --- /dev/null +++ b/sys/net/gnrc/conn/udp/gnrc_conn_udp.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * 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 <errno.h> +#include "net/af.h" +#include "net/gnrc/conn.h" +#include "net/gnrc/ipv6.h" +#include "net/gnrc/udp.h" + +#include "net/conn/udp.h" + +int conn_udp_create(conn_udp_t *conn, const void *addr, size_t addr_len, + int family, uint16_t port) +{ + conn->l4_type = GNRC_NETTYPE_UDP; + switch (family) { +#ifdef MODULE_GNRC_IPV6 + case AF_INET6: + if (addr_len != sizeof(ipv6_addr_t)) { + return -EINVAL; + } + if (gnrc_conn6_set_local_addr(conn->local_addr, addr)) { + conn->l3_type = GNRC_NETTYPE_IPV6; + conn->local_addr_len = addr_len; + conn_udp_close(conn); /* unregister possibly registered netreg entry */ + gnrc_conn_reg(&conn->netreg_entry, conn->l4_type, (uint32_t)port); + } + else { + return -EADDRNOTAVAIL; + } + break; +#endif + default: + (void)addr; + (void)addr_len; + (void)port; + return -EAFNOSUPPORT; + } + return 0; +} + +void conn_udp_close(conn_udp_t *conn) +{ + assert(conn->l4_type == GNRC_NETTYPE_UDP); + if (conn->netreg_entry.pid != KERNEL_PID_UNDEF) { + gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &conn->netreg_entry); + } +} + +int conn_udp_getlocaladdr(conn_udp_t *conn, void *addr, uint16_t *port) +{ + assert(conn->l4_type == GNRC_NETTYPE_UDP); + memcpy(addr, &conn->local_addr, conn->local_addr_len); + *port = (uint16_t)conn->netreg_entry.demux_ctx; + return conn->local_addr_len; +} + +int conn_udp_recvfrom(conn_udp_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len, + uint16_t *port) +{ + assert(conn->l4_type == GNRC_NETTYPE_UDP); + switch (conn->l3_type) { +#ifdef MODULE_GNRC_IPV6 + case GNRC_NETTYPE_IPV6: + return gnrc_conn_recvfrom((conn_t *)conn, data, max_len, addr, addr_len, port); +#endif + default: + (void)data; + (void)max_len; + (void)addr; + (void)addr_len; + (void)port; + return -EBADF; + } +} + +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) +{ + gnrc_pktsnip_t *pkt, *hdr = NULL; + + pkt = gnrc_pktbuf_add(NULL, (void *)data, len, GNRC_NETTYPE_UNDEF); /* data will only be copied */ + hdr = gnrc_udp_hdr_build(pkt, (uint8_t *)&sport, sizeof(uint16_t), (uint8_t *)&dport, + sizeof(uint16_t)); + if (hdr == NULL) { + gnrc_pktbuf_release(pkt); + return -ENOMEM; + } + pkt = hdr; + switch (family) { +#ifdef MODULE_GNRC_IPV6 + case AF_INET6: + if (((src != NULL) && (src_len != sizeof(ipv6_addr_t))) || + (dst_len != sizeof(ipv6_addr_t))) { + gnrc_pktbuf_release(pkt); + return -EINVAL; + } + /* addr will only be copied */ + hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst, dst_len); + if (hdr == NULL) { + gnrc_pktbuf_release(pkt); + return -ENOMEM; + } + pkt = hdr; + break; +#endif /* MODULE_GNRC_IPV6 */ + default: + (void)hdr; + (void)src; + (void)src_len; + (void)dst; + (void)dst_len; + gnrc_pktbuf_release(pkt); + return -EAFNOSUPPORT; + } + + gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, pkt); + + return len; +} + +/** @} */ -- GitLab