From 26a526eaee569c4e8a974a580b33ff3712783494 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Wed, 6 Feb 2019 14:48:13 +0100 Subject: [PATCH] gnrc_sixlowpan_frag: initial import of the VRB VRB = virtual reassembly buffer --- sys/include/net/gnrc/sixlowpan/config.h | 31 ++++ sys/include/net/gnrc/sixlowpan/frag/vrb.h | 149 ++++++++++++++++++ sys/net/gnrc/Makefile | 3 + .../sixlowpan/frag/gnrc_sixlowpan_frag.c | 2 +- .../network_layer/sixlowpan/frag/vrb/Makefile | 3 + .../frag/vrb/gnrc_sixlowpan_frag_vrb.c | 137 ++++++++++++++++ 6 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 sys/include/net/gnrc/sixlowpan/frag/vrb.h create mode 100644 sys/net/gnrc/network_layer/sixlowpan/frag/vrb/Makefile create mode 100644 sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c diff --git a/sys/include/net/gnrc/sixlowpan/config.h b/sys/include/net/gnrc/sixlowpan/config.h index d6cc3e44bb..84a825c135 100644 --- a/sys/include/net/gnrc/sixlowpan/config.h +++ b/sys/include/net/gnrc/sixlowpan/config.h @@ -115,6 +115,37 @@ extern "C" { #define GNRC_SIXLOWPAN_ND_AR_LTIME (15U) #endif +/** + * @brief Size of the virtual reassembly buffer + * + * @see https://tools.ietf.org/html/draft-ietf-lwig-6lowpan-virtual-reassembly-01 + * + * @note Only applicable with + * [gnrc_sixlowpan_frag_vrb](@ref net_gnrc_sixlowpan_frag_vrb) module, + * but has also a direct influence on the number of available + * gnrc_sixlowpan_rbuf_int_t entries (even when + * `gnrc_sixlowpan_frag_vrb` is not compiled in). + */ +#ifndef GNRC_SIXLOWPAN_FRAG_VRB_SIZE +#if defined(MODULE_GNRC_SIXLOWPAN_FRAG_VRB) || defined(DOXYGEN) +#define GNRC_SIXLOWPAN_FRAG_VRB_SIZE (16U) +#else /* defined(MODULE_GNRC_SIXLOWPAN_FRAG_VRB) || defined(DOXYGEN) */ +#define GNRC_SIXLOWPAN_FRAG_VRB_SIZE (0U) +#endif /* defined(MODULE_GNRC_SIXLOWPAN_FRAG_VRB) || defined(DOXYGEN) */ +#endif /* GNRC_SIXLOWPAN_FRAG_VRB_SIZE */ + +/** + * @brief Timeout for a VRB entry in microseconds + * + * @see https://tools.ietf.org/html/draft-ietf-lwig-6lowpan-virtual-reassembly-01 + * + * @note Only applicable with + * [gnrc_sixlowpan_frag_vrb](@ref net_gnrc_sixlowpan_frag_vrb) module. + */ +#ifndef GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US +#define GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US (GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US) +#endif /* GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US */ + #ifdef __cplusplus } #endif diff --git a/sys/include/net/gnrc/sixlowpan/frag/vrb.h b/sys/include/net/gnrc/sixlowpan/frag/vrb.h new file mode 100644 index 0000000000..29409e5c87 --- /dev/null +++ b/sys/include/net/gnrc/sixlowpan/frag/vrb.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2019 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 net_gnrc_sixlowpan_frag_vrb Virtual reassembly buffer + * @ingroup net_gnrc_sixlowpan_frag + * @brief Virtual reassembly buffer + * @{ + * + * @file + * @brief Virtual reassembly buffer definitions + * @see https://tools.ietf.org/html/draft-ietf-lwig-6lowpan-virtual-reassembly-01 + * + * @author Martine Lenders + */ +#ifndef NET_GNRC_SIXLOWPAN_FRAG_VRB_H +#define NET_GNRC_SIXLOWPAN_FRAG_VRB_H + +#include +#include +#include + +#include "net/gnrc/netif.h" +#include "net/gnrc/sixlowpan/config.h" +#include "net/gnrc/sixlowpan/frag.h" +#include "timex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Representation of the virtual reassembly buffer entry + */ +typedef struct { + gnrc_sixlowpan_rbuf_base_t super; /**< base type */ + + /** + * @brief Link-layer destination address to which the fragments are + * supposed to be forwarded to + */ + uint8_t out_dst[IEEE802154_LONG_ADDRESS_LEN]; + /** + * @brief Outgoing interface to gnrc_sixlowpan_frag_vrb_t::out_dst + */ + gnrc_netif_t *out_netif; + /** + * @brief Outgoing tag to gnrc_sixlowpan_frag_vrb_t::out_dst + */ + uint16_t out_tag; + /** + * @brief Length of gnrc_sixlowpan_frag_vrb_t::out_dst + */ + uint8_t out_dst_len; +} gnrc_sixlowpan_frag_vrb_t; + +/** + * @brief Adds a new reassembly buffer entry + * + * @param[in] base Base data of the datagram. Must not be `NULL`. + * @param[in] out_netif Network interface that is out-going to @p out_dst. + * @param[in] out_dst Link-layer destination address to which to forward + * fragments identified by @p base. Must not be `NULL`. + * @param[in] out_dst_len Length of @p out_dst. Must be greater than 0. + * + * @pre `base != NULL` + * @pre `out_dst != NULL` + * @pre `out_dst_len > 0` + * + * @return A new VRB entry. + * @return NULL, if VRB is full. + */ +gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_add( + const gnrc_sixlowpan_rbuf_base_t *base, + gnrc_netif_t *out_netif, const uint8_t *out_dst, size_t out_dst_len); + +/** + * @brief Checks timeouts and removes entries if necessary + */ +void gnrc_sixlowpan_frag_vrb_gc(void); + +/** + * @brief Gets a VRB entry + * + * @param[in] src Link-layer source address of the original fragment. + * @param[in] src_len Length of @p src. + * @param[in] dst Link-layer destination address of the original + * fragment. + * @param[in] dst_len Length of @p dst. + * @param[in] datagram_size The original fragment's datagram size. + * @param[in] src_tag Tag of the original fragment. + * + * @return The VRB entry identified by the given parameters. + * @return NULL, if there is no entry in the VRB that could be identified + * by the given parameters. + */ +gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get( + const uint8_t *src, size_t src_len, + const uint8_t *dst, size_t dst_len, + size_t datagram_size, unsigned src_tag); + +/** + * @brief Removes an entry from the VRB + * + * @param[in] vrb A VRB entry + */ +static inline void gnrc_sixlowpan_frag_vrb_rm(gnrc_sixlowpan_frag_vrb_t *vrb) +{ +#ifdef MODULE_GNRC_SIXLOWPAN_FRAG + gnrc_sixlowpan_frag_rbuf_base_rm(&vrb->super); +#elif defined(TEST_SUITES) + /* for testing just zero datagram_size */ + vrb->super.datagram_size = 0; +#endif /* MODULE_GNRC_SIXLOWPAN_FRAG */ +} + +/** + * @brief Determines if a VRB entry is empty + * + * @param[in] vrb A VRB entry + * + * @return true, if @p vrb entry is empty. + * @return false, if @p vrb entry is not empty. + */ +static inline bool gnrc_sixlowpan_frag_vrb_entry_empty(gnrc_sixlowpan_frag_vrb_t *vrb) +{ + return (vrb->super.datagram_size == 0); +} + +#if defined(TEST_SUITES) || defined(DOXYGEN) +/** + * @brief Resets the VRB to a clean state + * + * @note Only available when @ref TEST_SUITES is defined + */ +void gnrc_sixlowpan_frag_vrb_reset(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* NET_GNRC_SIXLOWPAN_FRAG_VRB_H */ +/** @} */ diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index 349b8ca4a9..434f234ee3 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -88,6 +88,9 @@ endif ifneq (,$(filter gnrc_sixlowpan_frag,$(USEMODULE))) DIRS += network_layer/sixlowpan/frag endif +ifneq (,$(filter gnrc_sixlowpan_frag_vrb,$(USEMODULE))) + DIRS += network_layer/sixlowpan/frag/vrb +endif ifneq (,$(filter gnrc_sixlowpan_iphc,$(USEMODULE))) DIRS += network_layer/sixlowpan/iphc endif diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c b/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c index 496c661007..8d552bedc8 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c @@ -358,7 +358,7 @@ void gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(gnrc_sixlowpan_rbuf_t *rbuf { assert(rbuf); assert(netif_hdr); - if (rbuf->super.current_size == rbuf->pkt->size) { + if (rbuf->super.current_size == rbuf->super.datagram_size) { gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(rbuf->super.src, rbuf->super.src_len, rbuf->super.dst, diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/Makefile b/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/Makefile new file mode 100644 index 0000000000..e884112e3b --- /dev/null +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/Makefile @@ -0,0 +1,3 @@ +MODULE := gnrc_sixlowpan_frag_vrb + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c b/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c new file mode 100644 index 0000000000..18ddf349d0 --- /dev/null +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2019 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. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders + */ + +#include "net/ieee802154.h" +#include "xtimer.h" + +#include "net/gnrc/sixlowpan/frag/vrb.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static gnrc_sixlowpan_frag_vrb_t _vrb[GNRC_SIXLOWPAN_FRAG_VRB_SIZE]; +static char l2addr_str[3 * IEEE802154_LONG_ADDRESS_LEN]; + +#if !defined(MODULE_GNRC_SIXLOWPAN_FRAG) && defined(TEST_SUITES) +/* mock for e.g. testing */ +uint16_t tag = 0; + +uint16_t gnrc_sixlowpan_frag_next_tag(void) +{ + return tag++; +} +#endif /* !defined(MODULE_GNRC_SIXLOWPAN_FRAG) && defined(TEST_SUITES) */ + +gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_add( + const gnrc_sixlowpan_rbuf_base_t *base, + gnrc_netif_t *out_netif, const uint8_t *out_dst, size_t out_dst_len) +{ + gnrc_sixlowpan_frag_vrb_t *vrbe = NULL; + + assert(base != NULL); + assert(out_netif != NULL); + assert(out_dst != NULL); + assert(out_dst_len > 0); + for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) { + gnrc_sixlowpan_frag_vrb_t *ptr = &_vrb[i]; + + if (gnrc_sixlowpan_frag_vrb_entry_empty(ptr) || + (memcmp(&ptr->super, base, sizeof(ptr->super)) == 0)) { + vrbe = ptr; + if (gnrc_sixlowpan_frag_vrb_entry_empty(vrbe)) { + vrbe->super = *base; + vrbe->out_netif = out_netif; + memcpy(vrbe->out_dst, out_dst, out_dst_len); + vrbe->out_tag = gnrc_sixlowpan_frag_next_tag(); + vrbe->out_dst_len = out_dst_len; + DEBUG("6lo vrb: creating entry (%s, ", + gnrc_netif_addr_to_str(vrbe->super.src, + vrbe->super.src_len, + l2addr_str)); + DEBUG("%s, %u, %u) => ", + gnrc_netif_addr_to_str(vrbe->super.dst, + vrbe->super.dst_len, + l2addr_str), + (unsigned)vrbe->super.datagram_size, vrbe->super.tag); + DEBUG("(%s, %u)\n", + gnrc_netif_addr_to_str(vrbe->out_dst, + vrbe->out_dst_len, + l2addr_str), vrbe->out_tag); + } + break; + } + } + return vrbe; +} + +gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get( + const uint8_t *src, size_t src_len, + const uint8_t *dst, size_t dst_len, + size_t datagram_size, unsigned src_tag) +{ + DEBUG("6lo vrb: trying to get entry for (%s, ", + gnrc_netif_addr_to_str(src, src_len, l2addr_str)); + DEBUG("%s, %u, %u)\n", + gnrc_netif_addr_to_str(dst, dst_len, l2addr_str), + (unsigned)datagram_size, src_tag); + for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) { + gnrc_sixlowpan_frag_vrb_t *vrbe = &_vrb[i]; + + if ((vrbe->super.datagram_size == datagram_size) && + (vrbe->super.tag == src_tag) && + (vrbe->super.src_len == src_len) && + (vrbe->super.dst_len == dst_len) && + (memcmp(vrbe->super.src, src, src_len) == 0) && + (memcmp(vrbe->super.dst, dst, dst_len) == 0)) { + DEBUG("6lo vrb: got VRB to (%s, %u)\n", + gnrc_netif_addr_to_str(vrbe->out_dst, + vrbe->out_dst_len, + l2addr_str), vrbe->out_tag); + return vrbe; + } + } + DEBUG("6lo vrb: no entry found\n"); + return NULL; +} + +void gnrc_sixlowpan_frag_vrb_gc(void) +{ + uint32_t now_usec = xtimer_now_usec(); + + for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) { + if (!gnrc_sixlowpan_frag_vrb_entry_empty(&_vrb[i]) && + (now_usec - _vrb[i].super.arrival) > GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US) { + DEBUG("6lo vrb: entry (%s, ", + gnrc_netif_addr_to_str(_vrb[i].super.src, + _vrb[i].super.src_len, + l2addr_str)); + DEBUG("%s, %u, %u) timed out\n", + gnrc_netif_addr_to_str(_vrb[i].super.dst, + _vrb[i].super.dst_len, + l2addr_str), + (unsigned)_vrb[i].super.datagram_size, _vrb[i].super.tag); + gnrc_sixlowpan_frag_vrb_rm(&_vrb[i]); + } + } +} + +#ifdef TEST_SUITES +void gnrc_sixlowpan_frag_vrb_reset(void) +{ + memset(_vrb, 0, sizeof(_vrb)); +} +#endif + +/** @} */