From 5412e0e68b7ce77294897506e127dfb31f023307 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mail@martine-lenders.eu>
Date: Mon, 16 Mar 2015 17:52:19 +0100
Subject: [PATCH] ng_sixlowpan: initial import

---
 Makefile.dep                                  |   5 +
 sys/Makefile                                  |   3 +
 sys/auto_init/auto_init.c                     |   8 +
 sys/include/net/ng_ipv6.h                     |   2 +-
 sys/include/net/ng_ipv6/netif.h               |   9 +
 sys/include/net/ng_sixlowpan.h                |  83 ++++++
 sys/net/network_layer/ng_ipv6/ng_ipv6.c       |  41 ++-
 sys/net/network_layer/ng_sixlowpan/Makefile   |   1 +
 .../network_layer/ng_sixlowpan/ng_sixlowpan.c | 253 ++++++++++++++++++
 9 files changed, 402 insertions(+), 3 deletions(-)
 create mode 100644 sys/include/net/ng_sixlowpan.h
 create mode 100644 sys/net/network_layer/ng_sixlowpan/Makefile
 create mode 100644 sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c

diff --git a/Makefile.dep b/Makefile.dep
index 61498f9d8e..0dcbe17d48 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -48,6 +48,11 @@ ifneq (,$(filter sixlowpan,$(USEMODULE)))
   USEMODULE += vtimer
 endif
 
+ifneq (,$(filter ng_sixlowpan,$(USEMODULE)))
+  USEMODULE += ng_sixlowpan_netif
+  USEMODULE += ng_netbase
+endif
+
 ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
   USEMODULE += ng_ipv6_addr
   USEMODULE += vtimer
diff --git a/sys/Makefile b/sys/Makefile
index 7a30b1539f..ab68cf1977 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -95,6 +95,9 @@ endif
 ifneq (,$(filter ng_pktbuf,$(USEMODULE)))
     DIRS += net/crosslayer/ng_pktbuf
 endif
+ifneq (,$(filter ng_sixlowpan,$(USEMODULE)))
+    DIRS += net/network_layer/ng_sixlowpan
+endif
 ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
     DIRS += net/network_layer/ng_sixlowpan/ctx
 endif
diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c
index a2ec8feebb..12a8830081 100644
--- a/sys/auto_init/auto_init.c
+++ b/sys/auto_init/auto_init.c
@@ -82,6 +82,10 @@
 #include "periph/cpuid.h"
 #endif
 
+#ifdef MODULE_NG_SIXLOWPAN
+#include "net/ng_sixlowpan.h"
+#endif
+
 #ifdef MODULE_NG_IPV6
 #include "net/ng_ipv6.h"
 #endif
@@ -284,6 +288,10 @@ void auto_init(void)
     DEBUG("Auto init ng_pktdump module.\n");
     ng_pktdump_init();
 #endif
+#ifdef MODULE_NG_SIXLOWPAN
+    DEBUG("Auto init ng_sixlowpan module.\n");
+    ng_sixlowpan_init();
+#endif
 #ifdef MODULE_NG_IPV6
     DEBUG("Auto init ng_ipv6 module.\n");
     ng_ipv6_init();
diff --git a/sys/include/net/ng_ipv6.h b/sys/include/net/ng_ipv6.h
index 657a3d14f1..15300e10d0 100644
--- a/sys/include/net/ng_ipv6.h
+++ b/sys/include/net/ng_ipv6.h
@@ -49,7 +49,7 @@ extern "C" {
 #endif
 
 /**
- * @brief   Default name for the IPv6 thread
+ * @brief   Default priority for the IPv6 thread
  */
 #ifndef NG_IPV6_PRIO
 #define NG_IPV6_PRIO            (PRIORITY_MAIN - 3)
diff --git a/sys/include/net/ng_ipv6/netif.h b/sys/include/net/ng_ipv6/netif.h
index da65053cc3..5144ed0e1f 100644
--- a/sys/include/net/ng_ipv6/netif.h
+++ b/sys/include/net/ng_ipv6/netif.h
@@ -83,6 +83,15 @@ extern "C" {
  * @}
  */
 
+/**
+ * @{
+ * @name Flags for the interfaces
+ */
+#define NG_IPV6_NETIF_FLAGS_SIXLOWPAN   (0x01)  /**< interface is 6LoWPAN interface */
+/**
+ * @}
+ */
+
 /**
  * @brief   Type to represent an IPv6 address registered to an interface.
  */
diff --git a/sys/include/net/ng_sixlowpan.h b/sys/include/net/ng_sixlowpan.h
new file mode 100644
index 0000000000..edc09a46a4
--- /dev/null
+++ b/sys/include/net/ng_sixlowpan.h
@@ -0,0 +1,83 @@
+/*
+ * 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_ng_sixlowpan    6LoWPAN
+ * @ingroup     net
+ * @brief       6LoWPAN implementation
+ * @{
+ *
+ * @file
+ * @brief   Definitions for 6LoWPAN
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_SIXLOWPAN_H_
+#define NG_SIXLOWPAN_H_
+
+#include <stdbool.h>
+
+#include "kernel_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Default stack size to use for the 6LoWPAN thread
+ */
+#ifndef NG_SIXLOWPAN_STACK_SIZE
+#define NG_SIXLOWPAN_STACK_SIZE  (KERNEL_CONF_STACKSIZE_DEFAULT)
+#endif
+
+/**
+ * @brief   Default priority for the 6LoWPAN thread
+ */
+#ifndef NG_SIXLOWPAN_PRIO
+#define NG_SIXLOWPAN_PRIO   (PRIORITY_MAIN - 4)
+#endif
+
+/**
+ * @brief   Default message queue size to use for the 6LoWPAN thread.
+ */
+#ifndef NG_SIXLOWPAN_MSG_QUEUE_SIZE
+#define NG_SIXLOWPAN_MSG_QUEUE_SIZE (8U)
+#endif
+
+/**
+ * @brief   Dispatch for uncompressed 6LoWPAN frame.
+ */
+#define NG_SIXLOWPAN_UNCOMPRESSED   (0x41)
+
+/**
+ * @brief   Checks if dispatch indicats that fram is not a 6LoWPAN (NALP) frame.
+ *
+ * @param[in] disp  The first byte of a frame.
+ *
+ * @return  true, if frame is a NALP.
+ * @return  false, if frame is not a NALP.
+ */
+static inline bool ng_sixlowpan_nalp(uint8_t disp)
+{
+    return (disp & 0x3f);
+}
+
+/**
+ * @brief   Initialization of the 6LoWPAN thread.
+ *
+ * @return  The PID to the 6LoWPAN thread, on success.
+ * @return  -EOVERFLOW, if there are too many threads running already
+ */
+kernel_pid_t ng_sixlowpan_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_SIXLOWPAN_H_ */
+/** @} */
diff --git a/sys/net/network_layer/ng_ipv6/ng_ipv6.c b/sys/net/network_layer/ng_ipv6/ng_ipv6.c
index b53d5d3b2c..824ac441de 100644
--- a/sys/net/network_layer/ng_ipv6/ng_ipv6.c
+++ b/sys/net/network_layer/ng_ipv6/ng_ipv6.c
@@ -135,6 +135,43 @@ static void *_event_loop(void *args)
     return NULL;
 }
 
+#ifdef MODULE_NG_SIXLOWPAN
+static void _send_to_iface(kernel_pid_t iface, ng_pktsnip_t *pkt)
+{
+    ng_ipv6_netif_t *if_entry = ng_ipv6_netif_get(iface);
+
+    ((ng_netif_hdr_t *)pkt->data)->if_pid = iface;
+
+    if ((if_entry != NULL) && (if_entry->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
+        DEBUG("ipv6: send to 6LoWPAN instead\n");
+        ng_netreg_entry_t *reg = ng_netreg_lookup(NG_NETTYPE_SIXLOWPAN,
+                                                  NG_NETREG_DEMUX_CTX_ALL);
+
+        if (reg != NULL) {
+            ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_SIXLOWPAN,
+                                              NG_NETREG_DEMUX_CTX_ALL) - 1);
+        }
+        else {
+            DEBUG("ipv6: no 6LoWPAN thread found");
+        }
+
+        while (reg) {
+            ng_netapi_send(reg->pid, pkt);
+            reg = ng_netreg_getnext(reg);
+        }
+    }
+    else {
+        ng_netapi_send(iface, pkt);
+    }
+}
+#else
+static inline void _send_to_iface(kernel_pid_t iface, ng_pktsnip_t *pkt)
+{
+    ((ng_netif_hdr_t *)pkt->data)->if_pid = iface;
+    ng_netapi_send(iface, pkt);
+}
+#endif
+
 /* functions for sending */
 static void _send_unicast(kernel_pid_t iface, uint8_t *dst_l2addr,
                           uint16_t dst_l2addr_len, ng_pktsnip_t *pkt)
@@ -165,7 +202,7 @@ static void _send_unicast(kernel_pid_t iface, uint8_t *dst_l2addr,
 
     DEBUG("ipv6: send unicast over interface %" PRIkernel_pid "\n", iface);
     /* and send to interface */
-    ng_netapi_send(iface, pkt);
+    _send_to_iface(iface, pkt);
 }
 
 static int _fill_ipv6_hdr(kernel_pid_t iface, ng_pktsnip_t *ipv6,
@@ -243,7 +280,7 @@ static inline void _send_multicast_over_iface(kernel_pid_t iface, ng_pktsnip_t *
     /* mark as multicast */
     ((ng_netif_hdr_t *)netif->data)->flags |= NG_NETIF_HDR_FLAGS_MULTICAST;
     /* and send to interface */
-    ng_netapi_send(iface, pkt);
+    _send_to_iface(iface, pkt);
 }
 
 static void _send_multicast(kernel_pid_t iface, ng_pktsnip_t *pkt,
diff --git a/sys/net/network_layer/ng_sixlowpan/Makefile b/sys/net/network_layer/ng_sixlowpan/Makefile
new file mode 100644
index 0000000000..48422e909a
--- /dev/null
+++ b/sys/net/network_layer/ng_sixlowpan/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
new file mode 100644
index 0000000000..af9f973878
--- /dev/null
+++ b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
@@ -0,0 +1,253 @@
+/*
+ * 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
+ */
+
+#include "kernel_types.h"
+#include "net/ng_netbase.h"
+#include "thread.h"
+#include "utlist.h"
+
+#include "net/ng_sixlowpan.h"
+#include "net/ng_sixlowpan/netif.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+static kernel_pid_t _pid = KERNEL_PID_UNDEF;
+static char _stack[NG_SIXLOWPAN_STACK_SIZE];
+
+/* handles NG_NETAPI_MSG_TYPE_RCV commands */
+void _receive(ng_pktsnip_t *pkt);
+/* handles NG_NETAPI_MSG_TYPE_SND commands */
+void _send(ng_pktsnip_t *pkt);
+/* Main event loop for 6LoWPAN */
+static void *_event_loop(void *args);
+
+kernel_pid_t ng_sixlowpan_init(void)
+{
+    if (_pid > KERNEL_PID_UNDEF) {
+        return _pid;
+    }
+
+    _pid = thread_create(_stack, NG_SIXLOWPAN_STACK_SIZE, NG_SIXLOWPAN_PRIO,
+                         CREATE_STACKTEST, _event_loop, NULL, "6lo");
+
+    return _pid;
+}
+
+void _receive(ng_pktsnip_t *pkt)
+{
+    ng_pktsnip_t *payload;
+    uint8_t *dispatch;
+    ng_netreg_entry_t *entry;
+
+    LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_SIXLOWPAN);
+
+    if ((payload == NULL) || (payload->size < 1)) {
+        DEBUG("6lo: Received packet has no 6LoWPAN payload\n");
+        ng_pktbuf_release(pkt);
+    }
+
+    dispatch = payload->data;
+
+    if (dispatch[0] == NG_SIXLOWPAN_UNCOMPRESSED) {
+        ng_pktsnip_t *sixlowpan;
+        DEBUG("6lo: received uncompressed IPv6 packet\n");
+        payload = ng_pktbuf_start_write(payload);
+
+        if (payload == NULL) {
+            DEBUG("6lo: can not get write access on received packet\n");
+#if defined(DEVELHELP) && defined(ENABLE_DEBUG)
+            ng_pktbuf_stats();
+#endif
+            ng_pktbuf_release(pkt);
+            return;
+        }
+
+        /* packet is uncompressed: just mark and remove the dispatch */
+        sixlowpan = ng_pktbuf_add(payload, payload->data, sizeof(uint8_t),
+                                  NG_NETTYPE_SIXLOWPAN);
+        LL_DELETE(pkt, sixlowpan);
+        ng_pktbuf_release(sixlowpan);
+    }
+    else {
+        DEBUG("6lo: dispatch %02x ... is not supported\n",
+              dispatch[0]);
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    payload->type = NG_NETTYPE_IPV6;
+
+    entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);
+
+    if (entry == NULL) {
+        DEBUG("ipv6: No receivers for this packet found\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1);
+
+    while (entry) {
+        DEBUG("6lo: Send receive command for %p to %" PRIu16 "\n",
+              (void *)pkt, entry->pid);
+        ng_netapi_receive(entry->pid, pkt);
+        entry = ng_netreg_getnext(entry);
+    }
+}
+
+void _send(ng_pktsnip_t *pkt)
+{
+    ng_netif_hdr_t *hdr;
+    ng_pktsnip_t *ipv6, *sixlowpan;
+    ng_sixlowpan_netif_t *iface;
+    /* cppcheck: datagram_size will be read by frag */
+    /* cppcheck-suppress unreadVariable */
+    size_t payload_len, datagram_size;
+    uint16_t max_frag_size;
+    uint8_t *disp;
+
+    if ((pkt == NULL) || (pkt->size < sizeof(ng_netif_hdr_t))) {
+        DEBUG("6lo: Sending packet has no netif header\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    hdr = pkt->data;
+    ipv6 = pkt->next;
+
+    if ((ipv6 == NULL) || (ipv6->type != NG_NETTYPE_IPV6)) {
+        DEBUG("6lo: Sending packet has no IPv6 header\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    /* payload length and datagram size are different in that the payload
+     * length is the length of the IPv6 datagram + 6LoWPAN dispatches,
+     * while the datagram size is the size of only the IPv6 datagram */
+    payload_len = ng_pkt_len(ipv6);
+    /* cppcheck: datagram_size will be read by ng_sixlowpan_frag implementation */
+    /* cppcheck-suppress unreadVariable */
+    datagram_size = (uint16_t)payload_len;
+
+    /* use sixlowpan packet snip as temporary one */
+    sixlowpan = ng_pktbuf_start_write(pkt);
+
+    if (sixlowpan == NULL) {
+        DEBUG("6lo: no space left in packet buffer\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    pkt = sixlowpan;
+
+    DEBUG("6lo: Send uncompressed\n");
+
+    sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
+
+    if (sixlowpan == NULL) {
+        DEBUG("6lo: no space left in packet buffer\n");
+        ng_pktbuf_release(pkt);
+        return;
+    }
+
+    sixlowpan->next = ipv6;
+    pkt->next = sixlowpan;
+    disp = sixlowpan->data;
+    disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
+    payload_len++;
+
+    iface = ng_sixlowpan_netif_get(hdr->if_pid);
+
+    if (iface == NULL) {
+        if (ng_netapi_get(hdr->if_pid, NETCONF_OPT_MAX_PACKET_SIZE,
+                          0, &max_frag_size, sizeof(max_frag_size)) < 0) {
+            /* if error we assume it works */
+            DEBUG("6lo: can not get max packet size from interface %"
+                  PRIkernel_pid "\n", hdr->if_pid);
+            max_frag_size = UINT16_MAX;
+        }
+
+        ng_sixlowpan_netif_add(hdr->if_pid, max_frag_size);
+    }
+    else {
+        max_frag_size = iface->max_frag_size;
+    }
+
+    DEBUG("6lo: max_frag_size = %" PRIu16 " for interface %"
+          PRIkernel_pid "\n", max_frag_size, hdr->if_pid);
+
+    /* IP should not send anything here if it is not a 6LoWPAN interface,
+     * so we don't need to check for NULL pointers */
+    if (payload_len <= max_frag_size) {
+        DEBUG("6lo: Send SND command for %p to %" PRIu16 "\n",
+              (void *)pkt, hdr->if_pid);
+        ng_netapi_send(hdr->if_pid, pkt);
+
+        return;
+    }
+    DEBUG("6lo: packet too big (%u> %" PRIu16 ")\n",
+          (unsigned int)payload_len, max_frag_size);
+}
+
+static void *_event_loop(void *args)
+{
+    msg_t msg, reply, msg_q[NG_SIXLOWPAN_MSG_QUEUE_SIZE];
+    ng_netreg_entry_t me_reg;
+
+    (void)args;
+    msg_init_queue(msg_q, NG_SIXLOWPAN_MSG_QUEUE_SIZE);
+
+    me_reg.demux_ctx = NG_NETREG_DEMUX_CTX_ALL;
+    me_reg.pid = thread_getpid();
+
+    /* register interest in all 6LoWPAN packets */
+    ng_netreg_register(NG_NETTYPE_SIXLOWPAN, &me_reg);
+
+    /* preinitialize ACK */
+    reply.type = NG_NETAPI_MSG_TYPE_ACK;
+
+    /* start event loop */
+    while (1) {
+        DEBUG("6lo: waiting for incoming message.\n");
+        msg_receive(&msg);
+
+        switch (msg.type) {
+            case NG_NETAPI_MSG_TYPE_RCV:
+                DEBUG("6lo: NG_NETDEV_MSG_TYPE_RCV received\n");
+                _receive((ng_pktsnip_t *)msg.content.ptr);
+                break;
+
+            case NG_NETAPI_MSG_TYPE_SND:
+                DEBUG("6lo: NG_NETDEV_MSG_TYPE_SND received\n");
+                _send((ng_pktsnip_t *)msg.content.ptr);
+                break;
+
+            case NG_NETAPI_MSG_TYPE_GET:
+            case NG_NETAPI_MSG_TYPE_SET:
+                DEBUG("6lo: reply to unsupported get/set\n");
+                reply.content.value = -ENOTSUP;
+                msg_reply(&msg, &reply);
+                break;
+
+            default:
+                DEBUG("6lo: operation not supported\n");
+                break;
+        }
+    }
+
+    return NULL;
+}
+
+/** @} */
-- 
GitLab