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