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 2f3500c967..ab68cf1977 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -95,9 +95,15 @@ 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 +ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE))) + DIRS += net/network_layer/ng_sixlowpan/netif +endif ifneq (,$(filter netapi,$(USEMODULE))) DIRS += net/crosslayer/netapi 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 + * + * 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 + */ +#ifndef NG_SIXLOWPAN_H_ +#define NG_SIXLOWPAN_H_ + +#include + +#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/include/net/ng_sixlowpan/netif.h b/sys/include/net/ng_sixlowpan/netif.h new file mode 100644 index 0000000000..11d845eb43 --- /dev/null +++ b/sys/include/net/ng_sixlowpan/netif.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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_netif 6LoWPAN network interfaces + * @ingroup net_ng_sixlowpan + * @brief 6LoWPAN specific information on @ref net_ng_netif + * @{ + * + * @file + * @brief Definitions for 6LoWPAN specific information of network interfaces. + * + * @author Martine Lenders + */ +#ifndef NG_SIXLOWPAN_NETIF_H_ +#define NG_SIXLOWPAN_NETIF_H_ + +#include "kernel_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Definition of 6LoWPAN interface type. + */ +typedef struct { + kernel_pid_t pid; /**< PID of the interface */ + uint16_t max_frag_size; /**< Maximum fragment size for this interface */ +} ng_sixlowpan_netif_t; + +/** + * @brief Initializes the module + */ +void ng_sixlowpan_netif_init(void); + +/** + * @brief Add interface to 6LoWPAN. + * + * @param[in] pid The PID to the interface. + * @param[in] max_frag_size The maximum fragment size for this interface. + */ +void ng_sixlowpan_netif_add(kernel_pid_t pid, uint16_t max_frag_size); + +/** + * @brief REmove interface from 6LoWPAN. + * + * @param[in] pid The PID to the interface. + */ +void ng_sixlowpan_netif_remove(kernel_pid_t pid); + +/** + * @brief Get interface. + * + * @param[in] pid The PID to the interface + * + * @return The interface describing structure, on success. + * @return NULL, if there is no interface with PID @p pid. + */ +ng_sixlowpan_netif_t *ng_sixlowpan_netif_get(kernel_pid_t pid); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_SIXLOWPAN_NETIF_H_ */ +/** @} */ diff --git a/sys/net/network_layer/ng_ipv6/ng_ipv6.c b/sys/net/network_layer/ng_ipv6/ng_ipv6.c index 0496d77981..e1f4d2e5f9 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/netif/Makefile b/sys/net/network_layer/ng_sixlowpan/netif/Makefile new file mode 100644 index 0000000000..b86f9e154c --- /dev/null +++ b/sys/net/network_layer/ng_sixlowpan/netif/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_sixlowpan_netif + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c b/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c new file mode 100644 index 0000000000..0428106c5f --- /dev/null +++ b/sys/net/network_layer/ng_sixlowpan/netif/ng_sixlowpan_netif.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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_netif.h" +#include "net/ng_sixlowpan/netif.h" + +static ng_sixlowpan_netif_t sixlow_ifs[NG_NETIF_NUMOF]; + +void ng_sixlowpan_netif_init(void) +{ + for (int i = 0; i < NG_NETIF_NUMOF; i++) { + sixlow_ifs[i].pid = KERNEL_PID_UNDEF; + sixlow_ifs[i].max_frag_size = 0; + } +} + +void ng_sixlowpan_netif_add(kernel_pid_t pid, uint16_t max_frag_size) +{ + for (int i = 0; i < NG_NETIF_NUMOF; i++) { + if (sixlow_ifs[i].pid == pid) { + return; + } + + if (sixlow_ifs[i].pid == KERNEL_PID_UNDEF) { + sixlow_ifs[i].pid = pid; + sixlow_ifs[i].max_frag_size = max_frag_size; + return; + } + } +} + +void ng_sixlowpan_netif_remove(kernel_pid_t pid) +{ + ng_sixlowpan_netif_t *entry = ng_sixlowpan_netif_get(pid); + + entry->pid = KERNEL_PID_UNDEF; +} + +ng_sixlowpan_netif_t *ng_sixlowpan_netif_get(kernel_pid_t pid) +{ + for (int i = 0; i < NG_NETIF_NUMOF; i++) { + if (sixlow_ifs[i].pid == pid) { + return sixlow_ifs + i; + } + } + + return NULL; +} + +/** @} */ 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 + * + * 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; +} + +/** @} */