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