From b1d875271140da4a598694b2680b9fd150bc05df Mon Sep 17 00:00:00 2001 From: haukepetersen <hauke.petersen@fu-berlin.de> Date: Fri, 24 Apr 2015 15:06:14 +0200 Subject: [PATCH] net: added NG_UDP implementation --- Makefile.dep | 5 + sys/Makefile | 3 + sys/include/net/ng_udp.h | 108 ++++++++++ sys/net/transport_layer/ng_udp/Makefile | 1 + sys/net/transport_layer/ng_udp/ng_udp.c | 270 ++++++++++++++++++++++++ 5 files changed, 387 insertions(+) create mode 100644 sys/include/net/ng_udp.h create mode 100644 sys/net/transport_layer/ng_udp/Makefile create mode 100644 sys/net/transport_layer/ng_udp/ng_udp.c diff --git a/Makefile.dep b/Makefile.dep index 9edb46a86d..c2133a365f 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -91,6 +91,11 @@ ifneq (,$(filter ng_ipv6_netif,$(USEMODULE))) USEMODULE += ng_netif endif +ifneq (,$(filter ng_udp,$(USEMODULE))) + USEMODULE += ng_netbase + USEMODULE += ng_inet_csum +endif + ifneq (,$(filter ng_netbase,$(USEMODULE))) USEMODULE += ng_netapi USEMODULE += ng_netreg diff --git a/sys/Makefile b/sys/Makefile index 56defb83a3..9ac918dd98 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -125,6 +125,9 @@ endif ifneq (,$(filter fib,$(USEMODULE))) DIRS += net/network_layer/fib endif +ifneq (,$(filter ng_udp,$(USEMODULE))) + DIRS += net/transport_layer/ng_udp +endif DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE}))) diff --git a/sys/include/net/ng_udp.h b/sys/include/net/ng_udp.h new file mode 100644 index 0000000000..6fd3862069 --- /dev/null +++ b/sys/include/net/ng_udp.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015 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 sys_net_udp UDP + * @ingroup net + * @brief RIOT's implementation of the UDP protocol + * + * @{ + * + * @file + * @brief UDP interface definition + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + */ + +#ifndef NG_UDP_H_ +#define NG_UDP_H_ + +#include <stdint.h> + +#include "byteorder.h" +#include "net/ng_netbase.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Default message queue size for the UDP thread + */ +#ifndef NG_UDP_MSG_QUEUE_SIZE +#define NG_UDP_MSG_QUEUE_SIZE (8U) +#endif + +/** + * @brief Priority of the pktdump thread + */ +#ifndef NG_UDP_PRIO +#define NG_UDP_PRIO (PRIORITY_MAIN - 2) +#endif + +/** + * @brief Default stack size to use for the UDP thread + */ +#ifndef NG_UDP_STACK_SIZE +#define NG_UDP_STACK_SIZE (KERNEL_CONF_STACKSIZE_DEFAULT) +#endif + +/** + * @brief UDP header definition + */ +typedef struct __attribute__((packed)) { + network_uint16_t src_port; /**< source port, in network byte order */ + network_uint16_t dst_port; /**< destination port, network byte order */ + network_uint16_t length; /**< payload length (including the header), + * network byte order */ + network_uint16_t checksum; /**< checksum */ +} ng_udp_hdr_t; + +/** + * @brief Calculate the checksum for the given packet + * + * @param[in] hdr Pointer to the UDP header + * @param[in] pseudo_hdr Pointer to the network layer header + * + * @return 0 on success + * @return -EBADMSG if @p pkt is not of type NG_NETTYPE_UDP + * @return -EFAULT if @p pkt or @p pseudo_hdr is NULL + * @return -ENOENT if @p pseudo_hdr_type is not known + */ +int ng_udp_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr); + +/** + * @brief Allocate and initialize a fresh UDP header in the packet buffer + * + * @param[in] payload Payload contained in the UDP packet + * @param[in] src Source port in host byte order + * @param[in] src_len Length of @p src, must be 2 + * @param[in] dst Destination port in host byte order + * @param[in] dst_len Length of @p dst, must be 2 + * + * @return pointer to the newly created (and allocated) header + * @return NULL on error + */ +ng_pktsnip_t *ng_udp_hdr_build(ng_pktsnip_t *payload, + uint8_t *src, size_t src_len, + uint8_t *dst, size_t dst_len); + +/** + * @brief Initialize and start UDP + * + * @return PID of the UDP thread + * @return negative value on error + */ +int ng_udp_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_UDP_H_ */ +/** @} */ diff --git a/sys/net/transport_layer/ng_udp/Makefile b/sys/net/transport_layer/ng_udp/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/net/transport_layer/ng_udp/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/transport_layer/ng_udp/ng_udp.c b/sys/net/transport_layer/ng_udp/ng_udp.c new file mode 100644 index 0000000000..a8e7d6c3f5 --- /dev/null +++ b/sys/net/transport_layer/ng_udp/ng_udp.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2015 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. + */ + +/** + * @ingroup net_ng_udp + * @{ + * + * @file + * @brief UDP implementation + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + * @} + */ + +#include <stdint.h> +#include <errno.h> + +#include "kernel.h" +#include "byteorder.h" +#include "msg.h" +#include "thread.h" +#include "utlist.h" +#include "net/ng_udp.h" +#include "net/ng_netbase.h" +#include "net/ng_inet_csum.h" + +#ifdef MODULE_NG_IPV6 +#include "net/ng_ipv6/hdr.h" +#endif + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Save the UDP's thread PID for later reference + */ +static kernel_pid_t _pid = KERNEL_PID_UNDEF; + +/** + * @brief Allocate memory for the UDP thread's stack + */ +static char _stack[NG_UDP_STACK_SIZE]; + +/** + * @brief Calculate the UDP checksum dependent on the network protocol + * + * @note If the checksum turns out to be 0x0000, the function returns 0xffff + * as specified in RFC768 + * + * @param[in] pkt pointer to the packet in the packet buffer + * @param[in] pseudo_hdr pointer to the network layer header + * @param[in] payload pointer to the payload + * + * @return the checksum of the pkt in host byte order + * @return 0 on error + */ +static uint16_t _calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr, + ng_pktsnip_t *payload) +{ + uint16_t csum = 0; + uint16_t len = (uint16_t)hdr->size; + + /* process the payload */ + while (payload && payload != hdr) { + csum = ng_inet_csum(csum, (uint8_t *)(payload->data), payload->size); + len += (uint16_t)payload->size; + payload = payload->next; + } + /* process applicable UDP header bytes */ + csum = ng_inet_csum(csum, (uint8_t *)hdr->data, 6); + + switch (pseudo_hdr->type) { +#ifdef MODULE_NG_IPV6 + case NG_NETTYPE_IPV6: + csum = ng_ipv6_hdr_inet_csum(csum, pseudo_hdr->data, + NG_PROTNUM_UDP, len); + break; +#endif + default: + (void)len; + return 0; + } + /* return inverted results */ + return ~csum; +} + +static void _receive(ng_pktsnip_t *pkt) +{ + ng_pktsnip_t *udp; + ng_udp_hdr_t *hdr; + uint16_t csum; + uint32_t port; + ng_netreg_entry_t *sendto; + + /* mark UDP header */ + udp = ng_pktbuf_start_write(pkt); + if (udp == NULL) { + DEBUG("udp: unable to get write access to packet\n"); + ng_pktbuf_release(pkt); + return; + } + pkt = udp; + udp = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_udp_hdr_t), NG_NETTYPE_UDP); + if (udp == NULL) { + DEBUG("udp: error marking UDP header, dropping packet\n"); + ng_pktbuf_release(pkt); + return; + } + hdr = (ng_udp_hdr_t *)udp->data; + + /* validate checksum */ + csum = _calc_csum(udp, udp->next, pkt); /* TODO: what about extension headers? */ + if (byteorder_ntohs(hdr->checksum) != csum) { + DEBUG("udp: received packet with invalid checksum, dropping it\n"); + ng_pktbuf_release(pkt); + return; + } + + /* get port (netreg demux context) */ + port = (uint32_t)byteorder_ntohs(hdr->dst_port); + + /* send payload to receivers */ + sendto = ng_netreg_lookup(NG_NETTYPE_UDP, port); + if (sendto == NULL) { + DEBUG("udp: unable to forward packet as no one is interested in it\n"); + ng_pktbuf_release(pkt); + return; + } + ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_UDP, port) - 1); + while (sendto != NULL) { + ng_netapi_receive(sendto->pid, pkt); + sendto = ng_netreg_getnext(sendto); + } +} + +static void _send(ng_pktsnip_t *pkt) +{ + ng_udp_hdr_t *hdr; + ng_pktsnip_t *udp_snip; + ng_netreg_entry_t *sendto; + + /* get udp snip and hdr */ + LL_SEARCH_SCALAR(pkt, udp_snip, type, NG_NETTYPE_UDP); + udp_snip = ng_pktbuf_start_write(udp_snip); + if (udp_snip == NULL) { + DEBUG("udp: cannot send packet, no UDP header found\n"); + ng_pktbuf_release(pkt); + return; + } + hdr = (ng_udp_hdr_t *)udp_snip->data; + /* fill in size field */ + hdr->length = byteorder_htons(sizeof(ng_udp_hdr_t) + ng_pkt_len(udp_snip)); + + /* and forward packet to the network layer */ + sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); + /* throw away packet if no one is interested */ + if (sendto == NULL) { + DEBUG("udp: cannot send packet because network layer not found\n"); + ng_pktbuf_release(pkt); + return; + } + /* send packet to network layer */ + ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); + while (sendto != NULL) { + ng_netapi_send(sendto->pid, pkt); + sendto = ng_netreg_getnext(sendto); + } +} + +static void *_event_loop(void *arg) +{ + (void)arg; + msg_t msg, reply; + msg_t msg_queue[NG_UDP_MSG_QUEUE_SIZE]; + ng_netreg_entry_t netreg; + + /* preset reply message */ + reply.type = NG_NETAPI_MSG_TYPE_ACK; + reply.content.value = (uint32_t)-ENOTSUP; + /* initialize message queue */ + msg_init_queue(msg_queue, NG_UDP_MSG_QUEUE_SIZE); + /* register UPD at netreg */ + netreg.demux_ctx = NG_NETREG_DEMUX_CTX_ALL; + netreg.pid = thread_getpid(); + ng_netreg_register(NG_NETTYPE_UDP, &netreg); + + /* dispatch NETAPI messages */ + while (1) { + msg_receive(&msg); + switch (msg.type) { + case NG_NETAPI_MSG_TYPE_RCV: + DEBUG("udp: NG_NETAPI_MSG_TYPE_RCV\n"); + _receive((ng_pktsnip_t *)msg.content.ptr); + break; + case NG_NETAPI_MSG_TYPE_SND: + DEBUG("udp: NG_NETAPI_MSG_TYPE_SND\n"); + _send((ng_pktsnip_t *)msg.content.ptr); + break; + case NG_NETAPI_MSG_TYPE_SET: + case NG_NETAPI_MSG_TYPE_GET: + msg_reply(&msg, &reply); + break; + default: + DEBUG("udp: received unidentified message\n"); + break; + } + } + + /* never reached */ + return NULL; +} + +int ng_udp_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr) +{ + uint16_t csum; + + if (hdr == NULL || hdr->next == NULL) { + return -EFAULT; + } + if (hdr->type != NG_NETTYPE_UDP) { + return -EBADMSG; + } + + csum = _calc_csum(hdr, pseudo_hdr, hdr->next); + if (csum == 0) { + return -ENOENT; + } + ((ng_udp_hdr_t *)hdr->data)->checksum = byteorder_htons(csum); + return 0; +} + +ng_pktsnip_t *ng_udp_hdr_build(ng_pktsnip_t *payload, + uint8_t *src, size_t src_len, + uint8_t *dst, size_t dst_len) { + ng_pktsnip_t *res; + ng_udp_hdr_t *hdr; + + /* check parameters */ + if (src == NULL || dst == NULL || + src_len != sizeof(uint16_t) || dst_len != sizeof(uint16_t)) { + return NULL; + } + /* allocate header */ + res = ng_pktbuf_add(payload, NULL, sizeof(ng_udp_hdr_t), NG_NETTYPE_UDP); + if (res == NULL) { + return NULL; + } + /* initialize header */ + hdr = (ng_udp_hdr_t *)res->data; + hdr->src_port = byteorder_htons(*((uint16_t *)src)); + hdr->dst_port = byteorder_htons(*((uint16_t *)dst)); + hdr->checksum = byteorder_htons(0); + return res; +} + +int ng_udp_init(void) +{ + /* check if thread is already running */ + if (_pid == KERNEL_PID_UNDEF) { + /* start UDP thread */ + _pid = thread_create(_stack, sizeof(_stack), NG_UDP_PRIO, 0, + _event_loop, NULL, "udp"); + } + return _pid; +} -- GitLab