1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #12648 from miri64/gnrc_sixlowpan_frag_sfr/feat/initial

gnrc_sixlowpan_frag: initial import of Selective Fragment Recovery
This commit is contained in:
Martine Lenders 2020-12-14 14:32:04 +01:00 committed by GitHub
commit 41a844f323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 5699 additions and 95 deletions

View File

@ -56,6 +56,7 @@ PSEUDOMODULES += gnrc_sixloenc
PSEUDOMODULES += gnrc_sixlowpan_border_router_default
PSEUDOMODULES += gnrc_sixlowpan_default
PSEUDOMODULES += gnrc_sixlowpan_frag_hint
PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_stats
PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc
PSEUDOMODULES += gnrc_sixlowpan_nd_border_router
PSEUDOMODULES += gnrc_sixlowpan_router_default

View File

@ -280,20 +280,26 @@ endif
ifneq (,$(filter gnrc_sixlowpan_default,$(USEMODULE)))
USEMODULE += gnrc_ipv6_nib_6ln
USEMODULE += gnrc_sixlowpan
USEMODULE += gnrc_sixlowpan_frag
ifeq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan_frag
endif
USEMODULE += gnrc_sixlowpan_iphc
endif
ifneq (,$(filter gnrc_sixlowpan_router_default,$(USEMODULE)))
USEMODULE += gnrc_ipv6_nib_6lr
USEMODULE += gnrc_sixlowpan_frag
ifeq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan_frag
endif
USEMODULE += gnrc_sixlowpan_iphc
endif
ifneq (,$(filter gnrc_sixlowpan_border_router_default,$(USEMODULE)))
USEMODULE += gnrc_ipv6_nib_6lbr
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_sixlowpan_frag
ifeq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan_frag
endif
USEMODULE += gnrc_sixlowpan_iphc
endif
@ -318,6 +324,19 @@ ifneq (,$(filter gnrc_sixlowpan_frag_rb,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan
USEMODULE += gnrc_sixlowpan_frag_fb
USEMODULE += gnrc_sixlowpan_frag_vrb
USEMODULE += gnrc_sixlowpan_frag_rb
USEMODULE += evtimer
USEMODULE += xtimer
endif
ifneq (,$(filter gnrc_sixlowpan_frag_sfr_stats,$(USEMODULE)))
USEMODULE += gnrc_sixlowpan_frag_sfr
endif
ifneq (,$(filter gnrc_sixlowpan_frag_vrb,$(USEMODULE)))
USEMODULE += xtimer
USEMODULE += gnrc_sixlowpan_frag_fb

View File

@ -18,12 +18,34 @@
#ifndef NET_GNRC_NETIF_6LO_H
#define NET_GNRC_NETIF_6LO_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Local 6LoWPAN capability flags
* @anchor net_gnrc_netif_6lo_local_flags
* @see gnrc_netif_6lo_t::local_flags
*
* Like the the capability flags in the [6LoWPAN Capability Indication Option
* (6CIO)](https://tools.ietf.org/html/rfc7400#section-3.3) are less about
* hardware capabilities than about the implementation status within the
* network. For the flags in this group it is currently undefined how to
* exchange the capabilities between nodes, but they might be added to the 6CIO
* at a later point. Once the 6CIO is implemented in GNRC and the flag is
* supported by it, the corresponding flag in these local flags can be removed.
* @{
*/
/**
* @brief Selective Fragment Recovery enabled
* @see [RFC 8931](https://tools.ietf.org/html/rfc8931)
*/
#define GNRC_NETIF_6LO_LOCAL_FLAGS_SFR (0x01)
/** @} */
/**
* @brief 6Lo component of @ref gnrc_netif_t
*/
@ -35,6 +57,15 @@ typedef struct {
* @ref net_gnrc_sixlowpan_frag "gnrc_sixlowpan_frag".
*/
uint16_t max_frag_size;
/**
* @brief 6LoWPAN capability flags beyond the ones advertised in
* [6LoWPAN Capability Indication Option
* (6CIO)](https://tools.ietf.org/html/rfc7400#section-3.3)
*
* @see [Local 6LoWPAN capability flags](@ref
* net_gnrc_netif_6lo_local_flags)
*/
uint8_t local_flags;
} gnrc_netif_6lo_t;
#ifdef __cplusplus

View File

@ -63,7 +63,11 @@ extern "C" {
* [gnrc_sixlowpan_frag_fb](@ref net_gnrc_sixlowpan_frag_fb) module
*/
#ifndef CONFIG_GNRC_SIXLOWPAN_FRAG_FB_SIZE
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
#define CONFIG_GNRC_SIXLOWPAN_FRAG_FB_SIZE (4U)
#else /* defined(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
#define CONFIG_GNRC_SIXLOWPAN_FRAG_FB_SIZE (1U)
#endif /* defined(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
#endif
/**
@ -163,16 +167,16 @@ extern "C" {
/**
* @name Selective fragment recovery configuration
* @see [draft-ietf-6lo-fragment-recovery-07, section 7.1]
* (https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-07#section-7.1)
* @see [RFC 8931, section 7.1]
* (https://tools.ietf.org/html/rfc8931#section-7.1)
* @note Only applicable with gnrc_sixlowpan_frag_sfr module
* @{
*/
/**
* @brief Default minimum value for fragment size (MinFragmentSize)
*/
#ifndef GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE
#define GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE (96U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE
#define CONFIG_GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE 96U
#endif
/**
@ -182,32 +186,37 @@ extern "C" {
* the chances of buffer bloat and transmission loss. The value must be less
* than 512 if the unit is defined for the PHY layer is the octet.
*/
#ifndef GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE
#define GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE (112U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE
#define CONFIG_GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE 112U
#endif
/**
* @brief Default value for fragment size that the sender should use to start
* with (OptFragmentSize)
*
* @pre Must be inclusively between
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE and
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE
*/
#ifndef GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE
#define GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE (GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE
#define CONFIG_GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE CONFIG_GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE
#endif
/**
* @brief Indicates whether the sender should react to ECN (UseECN)
*
* When the sender reacts to ECN its window size will vary between @ref
* GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE and @ref GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE.
* When the sender reacts to Explicit Congestion Notification (ECN) its window
* size will vary between @ref CONFIG_GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE and @ref
* CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE.
*/
#define GNRC_SIXLOWPAN_SFR_USE_ECN (0U)
#define CONFIG_GNRC_SIXLOWPAN_SFR_USE_ECN 0U
/**
* @brief Default minimum value of window size that the sender can use
* (MinWindowSize)
*/
#ifndef GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE
#define GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE (1U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE
#define CONFIG_GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE 1U
#endif
/**
@ -216,16 +225,20 @@ extern "C" {
*
* @warning **Must** be lesser than 32.
*/
#ifndef GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE
#define GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE (16U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE
#define CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE 16U
#endif
/**
* @brief Default value of window size that the sender should start with
* (OptWindowSize)
*
* @pre Must be inclusively between
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE and
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE
*/
#ifndef GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE
#define GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE (16U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE
#define CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE 16U
#endif
/**
@ -240,51 +253,53 @@ extern "C" {
* ratio of air and memory in intermediate nodes that a particular datagram will
* use.
*/
#ifndef GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US
#define GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US (100U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US
#define CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US 100U
#endif
/**
* @brief Default minimum amount of time in milliseconds a node should wait
* for an RFRAG Acknowledgment before it takes a next action
* @brief Minimum RFRAG-ACK timeout in msec before a node takes a next action
* (MinARQTimeOut)
*/
#ifndef GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS
#define GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS (350U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS
#define CONFIG_GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS 350U
#endif
/**
* @brief Default maximum amount of time in milliseconds a node should wait
* for an RFRAG Acknowledgment before it takes a next action
* @brief Maximum RFRAG-ACK timeout in msec before a node takes a next action
* (MaxARQTimeOut)
*/
#ifndef GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS
#define GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS (700U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS
#define CONFIG_GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS 700U
#endif
/**
* @brief Default starting point of the value of the amount of time in
* milliseconds that a sender should wait for an RFRAG Acknowledgment
* before it takes a next action (OptARQTimeOut)
* @brief Default RFRAG-ACK timeout in msec before a node takes a next action
* (OptARQTimeOut)
*
* @pre Must be inclusively between
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS and
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS
*/
#ifndef GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS
#define GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS (GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS
#define CONFIG_GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS \
CONFIG_GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS
#endif
/**
* @brief The maximum number of retries for a particular fragment
* (MaxFragRetries)
*/
#ifndef GNRC_SIXLOWPAN_SFR_FRAG_RETRIES
#define GNRC_SIXLOWPAN_SFR_FRAG_RETRIES (2U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES
#define CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES 2U
#endif
/**
* @brief The maximum number of retries from scratch for a particular
* datagram (MaxDatagramRetries)
*/
#ifndef GNRC_SIXLOWPAN_SFR_DG_RETRIES
#define GNRC_SIXLOWPAN_SFR_DG_RETRIES (0U)
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_DG_RETRIES
#define CONFIG_GNRC_SIXLOWPAN_SFR_DG_RETRIES 0U
#endif
/** @} */

View File

@ -28,6 +28,7 @@
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
#include "net/gnrc/sixlowpan/frag/hint.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
#include "net/gnrc/sixlowpan/frag/sfr_types.h"
#ifdef __cplusplus
extern "C" {
@ -43,10 +44,22 @@ extern "C" {
*/
typedef struct {
gnrc_pktsnip_t *pkt; /**< Pointer to the IPv6 packet to be fragmented */
uint16_t datagram_size; /**< Length of just the (uncompressed) IPv6 packet to be fragmented */
/**
* @brief Length of just the (uncompressed) IPv6 packet to be fragmented
*
* @note With @ref net_gnrc_sixlowpan_frag_sfr this denotes the
* _compressed form_ of the datagram
*/
uint16_t datagram_size;
uint16_t tag; /**< Tag used for the fragment */
uint16_t offset; /**< Offset of the Nth fragment from the beginning of the
* payload datagram */
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
/**
* @brief Extension for selective fragment recovery.
*/
gnrc_sixlowpan_frag_sfr_fb_t sfr;
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
/**
* @brief Hint for the size (smaller than link-layer PDU) for the next

View File

@ -25,6 +25,9 @@
#include "net/gnrc/netif/hdr.h"
#include "net/gnrc/pkt.h"
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
#include "net/sixlowpan/sfr.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
#include "net/gnrc/sixlowpan/config.h"
@ -96,6 +99,17 @@ typedef struct {
* @brief The reassembled packet in the packet buffer
*/
gnrc_pktsnip_t *pkt;
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
/**
* @brief Bitmap for received fragments
*
* @note Only available with module `gnrc_sixlowpan_frag_sfr` compiled
* in.
*/
BITFIELD(received, SIXLOWPAN_SFR_ACK_BITMAP_SIZE);
int8_t offset_diff; /**< offset change due to
* recompression */
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
} gnrc_sixlowpan_frag_rb_t;
/**
@ -118,6 +132,29 @@ gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_add(gnrc_netif_hdr_t *netif_hdr
gnrc_pktsnip_t *frag,
size_t offset, unsigned page);
/**
* @brief Gets a reassembly buffer entry with a given link-layer address
* pair and tag.
*
* @pre `netif_hdr != NULL`
*
* @param[in] netif_hdr An interface header to provide the (source, destination)
* link-layer address pair. Must not be NULL.
* @param[in] tag Tag to search for.
*
* @note datagram_size is not a search parameter as the primary use case
* for this function is [Selective Fragment Recovery]
* (https://tools.ietf.org/html/rfc8931) where this information only
* exists in the first fragment.
*
* @return The reassembly buffer entry identified by the source and destination
* address in the @p netif_hdr and @p tag, if any such entry exist.
* @return NULL, if no entry with the given identifying tuple exist.
*/
gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_get_by_datagram(
const gnrc_netif_hdr_t *netif_hdr,
uint16_t tag);
/**
* @brief Checks if a reassembly buffer entry with a given link-layer address
* pair and tag exists
@ -130,8 +167,8 @@ gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_add(gnrc_netif_hdr_t *netif_hdr
*
* @note datagram_size is not a search parameter as the primary use case
* for this function is [Selective Fragment Recovery]
* (https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05)
* where this information only exists in the first fragment.
* (https://tools.ietf.org/html/rfc8931) where this information only
* exists in the first fragment.
*
* @return true, if an entry with the given tuple exist.
* @return false, if no entry with the given tuple exist.
@ -151,8 +188,8 @@ bool gnrc_sixlowpan_frag_rb_exists(const gnrc_netif_hdr_t *netif_hdr,
*
* @note datagram_size is not a search parameter as the primary use case
* for this function is [Selective Fragment Recovery]
* (https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05)
* where this information only exists in the first fragment.
* (https://tools.ietf.org/html/rfc8931) where this information only
* exists in the first fragment.
*/
void gnrc_sixlowpan_frag_rb_rm_by_datagram(const gnrc_netif_hdr_t *netif_hdr,
uint16_t tag);
@ -251,6 +288,27 @@ static inline void gnrc_sixlowpan_frag_rb_remove(gnrc_sixlowpan_frag_rb_t *rbuf)
}
#endif
#if defined(TEST_SUITES) || defined(DOXYGEN)
/**
* @brief Check if pool of fragment intervals is empty
*
* @see @ref gnrc_sixlowpan_frag_rb_int_t
* @note Returns only non-true values if @ref TEST_SUITES is defined.
*
* @return true, if pool of fragment intervals is empty
* @return false, if pool of fragment intervals is not empty
*/
bool gnrc_sixlowpan_frag_rb_ints_empty(void);
#else /* defined(TEST_SUITES) || defined(DOXYGEN) */
/* always true without TEST_SUITES defined to optimize out when not testing,
* as checking the status of the fragment interval pool is unnecessary in
* production */
static inline bool gnrc_sixlowpan_frag_rb_ints_empty(void)
{
return true;
}
#endif /* defined(TEST_SUITES) || defined(DOXYGEN) */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,202 @@
/*
* 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_sfr 6LoWPAN selective fragment recovery
* @ingroup net_gnrc_sixlowpan
* @brief 6LoWPAN selective fragment recovery implementation for GNRC
*
* 6LoWPAN selective fragment recovery is an alternative fragmentation
* specification to [classic 6LoWPAN fragmentation](@ref
* net_gnrc_sixlowpan_frag). It can be run in parallel to classic fragmentation,
* but is incompatible with its message formats.
*
* How nodes can exchange that they are able to communicate using selective
* fragment recovery is currently not specified, so this feature should only be
* used if the operator of a network can ensure that all 6LoWPAN nodes within
* that network can communicate using selective fragment recovery.
*
* @see [RFC 8931](https://tools.ietf.org/html/rfc8931)
* @{
*
* @file
* @brief 6LoWPAN selective fragment recovery definitions for GNRC
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NET_GNRC_SIXLOWPAN_FRAG_SFR_H
#define NET_GNRC_SIXLOWPAN_FRAG_SFR_H
#include "assert.h"
#include "bitfield.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/sixlowpan/config.h"
#include "net/gnrc/sixlowpan/frag/fb.h"
#include "net/gnrc/sixlowpan/frag/vrb.h"
#include "net/gnrc/sixlowpan/frag/sfr_types.h"
#include "net/sixlowpan/sfr.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Message type to signal an acknowledgement request timeout.
*/
#define GNRC_SIXLOWPAN_FRAG_SFR_ARQ_TIMEOUT_MSG (0x0227)
/**
* @brief Message type to signal the sending of the next frame.
*/
#define GNRC_SIXLOWPAN_FRAG_SFR_INTER_FRAG_GAP_MSG (0x0228)
/**
* @brief Stats on selective fragment recovery
*/
typedef struct {
uint32_t datagram_resends; /**< datagrams resent */
struct {
uint32_t usual; /**< non-abort fragments sent */
uint32_t aborts; /**< abort pseudo-fragments sent */
uint32_t forwarded; /**< forwarded fragments */
} fragments_sent; /**< RFRAG packets sent */
struct {
uint32_t by_nack; /**< fragments resent due to a 0 in ACK's bitmap */
uint32_t by_timeout; /**< fragments resent due to an ARQ timeout */
} fragment_resends; /**< fragments resent */
struct {
uint32_t full; /**< full RFRAGs ACKs sent */
uint32_t partly; /**< partly ACKing RFRAGs sent */
uint32_t aborts; /**< abort RFRAG ACKs sent */
uint32_t forwarded; /**< forwarded ACKs */
} acks; /**< ACKs stats */
} gnrc_sixlowpan_frag_sfr_stats_t;
/**
* @brief Initialize selective fragment recovery
*/
void gnrc_sixlowpan_frag_sfr_init(void);
/**
* @brief Initialize a network interface for selective fragment recovery
*
* @note This is a NOP without module `gnrc_sixlowpan_frag_sfr`
*
* @param[in] netif A network interface
*/
static inline void gnrc_sixlowpan_frag_sfr_init_iface(gnrc_netif_t *netif)
{
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
gnrc_netif_is_6lo(netif)) {
#if IS_USED(MODULE_GNRC_NETIF_6LO)
netif->sixlo.local_flags |= GNRC_NETIF_6LO_LOCAL_FLAGS_SFR;
netif->sixlo.max_frag_size =
(netif->sixlo.max_frag_size > CONFIG_GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE)
? CONFIG_GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE
: netif->sixlo.max_frag_size;
assert(netif->sixlo.max_frag_size >= CONFIG_GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE);
#endif
}
}
/**
* @brief Checks if a network interface is configured for selective fragment
* recovery
*
* @param[in] netif A network interface.
*
* @return true, if @p netif supports selective fragment recovery and has it
* enabled.
* @return false, if @p netif does not support selective fragment recovery or
* does not have it enabled.
*/
static inline bool gnrc_sixlowpan_frag_sfr_netif(gnrc_netif_t *netif)
{
#if IS_USED(MODULE_GNRC_NETIF_6LO)
return IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
gnrc_netif_is_6lo(netif) &&
(netif->sixlo.local_flags & GNRC_NETIF_6LO_LOCAL_FLAGS_SFR);
#else
(void)netif;
return false;
#endif
}
/**
* @brief Sends a packet via selective fragment recovery
*
* @pre `ctx != NULL`
* @pre gnrc_sixlowpan_frag_fb_t::pkt of @p ctx is equal to @p pkt or
* `pkt == NULL`.
*
* @param[in] pkt A packet. May be NULL.
* @param[in] ctx Fragmentation buffer entry of. Expected to be of type
* @ref gnrc_sixlowpan_frag_fb_t, with gnrc_sixlowpan_frag_fb_t
* set to @p pkt. Must not be NULL.
* @param[in] page Current 6Lo dispatch parsing page.
*/
void gnrc_sixlowpan_frag_sfr_send(gnrc_pktsnip_t *pkt, void *ctx,
unsigned page);
/**
* @brief Handles a packet containing a selective fragment recovery header
*
* @param[in] pkt The packet to handle.
* @param[in] ctx Context for the packet. May be NULL.
* @param[in] page Current 6Lo dispatch parsing page.
*/
void gnrc_sixlowpan_frag_sfr_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page);
/**
* @brief Forward a fragment via selective fragment recovery
*
* @param[in] pkt The fragment to forward (without RFRAG header).
* Is consumed by this function.
* @param[in] rfrag The originally received RFRAG header.
* @param[in] vrbe Virtual reassembly buffer containing the forwarding
* information.
* @param[in] page Current 6Lo dispatch parsing page.
*
* @return 0, on success.
* @return -ENOMEM, when packet buffer is too full to prepare packet for
* forwarding. @p pkt is released in that case.
*/
int gnrc_sixlowpan_frag_sfr_forward(gnrc_pktsnip_t *pkt,
sixlowpan_sfr_rfrag_t *rfrag,
gnrc_sixlowpan_frag_vrb_t *vrbe,
unsigned page);
/**
* @brief Handles an Acknowledgment request timeout
*
* @param[in] fbuf The fragmentation buffer representing the datagram for which
* fragments the Acknowledgment request timed out.
*/
void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf);
/**
* @brief Handles inter frame gap
*/
void gnrc_sixlowpan_frag_sfr_inter_frame_gap(void);
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)
/**
* @brief Fetch current stats for selective fragment recovery
*
* @param[out] stats The current stats. Must not be NULL.
*/
void gnrc_sixlowpan_frag_sfr_stats_get(gnrc_sixlowpan_frag_sfr_stats_t *stats);
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS) */
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_SIXLOWPAN_FRAG_SFR_H */
/** @} */

View File

@ -0,0 +1,65 @@
/*
* 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.
*/
/**
* @addtogroup net_gnrc_sixlowpan_frag_sfr
* @{
*
* @file
* @brief 6LoWPAN selective fragment recovery type definitions for GNRC
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NET_GNRC_SIXLOWPAN_FRAG_SFR_TYPES_H
#define NET_GNRC_SIXLOWPAN_FRAG_SFR_TYPES_H
#include <stdint.h>
#include "bitfield.h"
#include "clist.h"
#include "evtimer_msg.h"
#include "msg.h"
#include "xtimer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Bitmap type to simplify comparisons
*/
typedef union {
uint32_t u32; /**< numerical version of bitmap */
BITFIELD(bf, 32U); /**< bitfield version of bitmap */
} gnrc_sixlowpan_frag_sfr_bitmap_t;
/**
* @brief Extension for @ref net_gnrc_sixlowpan_frag_fb for selective
* fragment recovery
*/
typedef struct gnrc_sixlowpan_frag_sfr_fb {
/**
* @brief Acknowledgment request timeout event
*/
evtimer_msg_event_t arq_timeout_event;
uint32_t arq_timeout; /**< Time in microseconds the sender should
* wait for an RFRAG Acknowledgment */
uint8_t cur_seq; /**< Sequence number for next fragment */
uint8_t frags_sent; /**< Number of fragments sent */
uint8_t window_size; /**< Current window size in number of
* fragments */
uint8_t retrans; /**< Datagram retransmissions */
clist_node_t window; /**< Sent fragments of the current window */
} gnrc_sixlowpan_frag_sfr_fb_t;
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_SIXLOWPAN_FRAG_SFR_TYPES_H */
/** @} */

View File

@ -54,6 +54,13 @@ typedef struct {
* @brief Outgoing tag to gnrc_sixlowpan_frag_rb_base_t::dst
*/
uint16_t out_tag;
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
int16_t offset_diff; /**< offset change due to recompression */
/**
* @brief Incoming interface to gnrc_sixlowpan_frag_rb_base_t::src
*/
gnrc_netif_t *in_netif;
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
} gnrc_sixlowpan_frag_vrb_t;
/**
@ -117,6 +124,23 @@ void gnrc_sixlowpan_frag_vrb_gc(void);
gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get(
const uint8_t *src, size_t src_len, unsigned src_tag);
/**
* @brief Reverse VRB lookup
*
* @param[in] netif Network interface the reverse label-switched packet
* came over
* @param[in] src Link-layer source address of reverse label-switched
* packet.
* @param[in] src_len Length of @p src.
* @param[in] tag Tag of the reverse label-switched packet.
*
* @return The VRB entry with `vrb->super.dst == src` and `vrb->out_tag == tag`.
* @return NULL, if there is no entry in the VRB that has these values.
*/
gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_reverse(
const gnrc_netif_t *netif, const uint8_t *src, size_t src_len,
unsigned tag);
/**
* @brief Removes an entry from the VRB
*

View File

@ -63,22 +63,19 @@ extern "C" {
/**
* @brief Dispatch mask for 6LoWPAN selective fragment recovery
* @see [draft-ietf-6lo-fragment-recovery-05,
* section 5](https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05#section-5)
* @see [RFC 8931, section 5](https://tools.ietf.org/html/rfc8931#section-5)
*/
#define SIXLOWPAN_SFR_DISP_MASK (0xfe)
/**
* @brief Dispatch for 6LoWPAN recoverable fragment
* @see [draft-ietf-6lo-fragment-recovery-05, section
* 5.1](https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05#section-5.1)
* @see [RFC 8931, section 5.1](https://tools.ietf.org/html/rfc8931#section-5.1)
*/
#define SIXLOWPAN_SFR_RFRAG_DISP (0xe8)
/**
* @brief Dispatch for 6LoWPAN recoverable fragment acknowledgment
* @see [draft-ietf-6lo-fragment-recovery-05, section
* 5.2](https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05#section-5.2)
* @see [RFC 8931, section 5.2](https://tools.ietf.org/html/rfc8931#section-5.2)
*/
#define SIXLOWPAN_SFR_ACK_DISP (0xea)

View File

@ -57,8 +57,7 @@ extern "C" {
/**
* @brief Generic type for selective fragment recovery headers
*
* @see [draft-ietf-6lo-fragment-recovery-05, section
* 5](https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05#section-5)
* @see [RFC 8931, section 5](https://tools.ietf.org/html/rfc8931#section-5)
*/
typedef struct __attribute__((packed)) {
/**
@ -92,8 +91,7 @@ typedef struct __attribute__((packed)) {
/**
* @brief Recoverable fragment header
*
* @see [draft-ietf-6lo-fragment-recovery-05, section
* 5.1](https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05#section-5.1)
* @see [RFC 8931, section 5.1](https://tools.ietf.org/html/rfc8931#section-5.1)
*/
typedef struct __attribute__((packed)) {
sixlowpan_sfr_t base; /**< generic part */
@ -137,8 +135,7 @@ typedef struct __attribute__((packed)) {
/**
* @brief Recoverable fragment (RFRAG) acknowledgment header
*
* @see [draft-ietf-6lo-fragment-recovery-05, section
* 5.2](https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05#section-5.2)
* @see [RFC 8931, section 5.2](https://tools.ietf.org/html/rfc8931#section-5.2)
*/
typedef struct __attribute__((packed)) {
sixlowpan_sfr_t base; /**< generic part */

View File

@ -106,6 +106,9 @@ endif
ifneq (,$(filter gnrc_sixlowpan_frag_rb,$(USEMODULE)))
DIRS += network_layer/sixlowpan/frag/rb
endif
ifneq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE)))
DIRS += network_layer/sixlowpan/frag/sfr
endif
ifneq (,$(filter gnrc_sixlowpan_frag_stats,$(USEMODULE)))
DIRS += network_layer/sixlowpan/frag/stats
endif

View File

@ -32,6 +32,9 @@
#if IS_USED(MODULE_GNRC_NETIF_PKTQ)
#include "net/gnrc/netif/pktq.h"
#endif /* IS_USED(MODULE_GNRC_NETIF_PKTQ) */
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
#include "net/gnrc/sixlowpan/frag/sfr.h"
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
#if IS_USED(MODULE_NETSTATS)
#include "net/netstats.h"
#endif /* IS_USED(MODULE_NETSTATS) */
@ -1389,6 +1392,9 @@ void gnrc_netif_default_init(gnrc_netif_t *netif)
_init_from_device(netif);
#ifdef DEVELHELP
_test_options(netif);
#endif
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
gnrc_sixlowpan_frag_sfr_init_iface(netif);
#endif
netif->cur_hl = CONFIG_GNRC_NETIF_DEFAULT_HL;
#ifdef MODULE_GNRC_IPV6_NIB

View File

@ -5,10 +5,16 @@
# directory for more details.
#
if USEMODULE_GNRC_SIXLOWPAN_FRAG
if USEMODULE_GNRC_SIXLOWPAN_FRAG || USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR
rsource "fb/Kconfig"
rsource "rb/Kconfig"
rsource "vrb/Kconfig"
endif # USEMODULE_GNRC_SIXLOWPAN_FRAG
endif # USEMODULE_GNRC_SIXLOWPAN_FRAG || USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR
if USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR
rsource "sfr/Kconfig"
endif # USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR

View File

@ -14,6 +14,7 @@ if KCONFIG_USEMODULE_GNRC_SIXLOWPAN_FRAG_FB
config GNRC_SIXLOWPAN_FRAG_FB_SIZE
int "Number of datagrams that can be fragmented simultaneously"
default 4 if MODULE_GNRC_SIXLOWPAN_FRAG_SFR
default 1
help
This determines the number of @ref gnrc_sixlowpan_frag_fb_t instances

View File

@ -29,6 +29,7 @@
#include "net/gnrc/sixlowpan/frag/minfwd.h"
#include "net/gnrc/sixlowpan/frag/vrb.h"
#include "net/sixlowpan.h"
#include "net/sixlowpan/sfr.h"
#include "thread.h"
#include "xtimer.h"
#include "utlist.h"
@ -153,7 +154,12 @@ gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_add(gnrc_netif_hdr_t *netif_hdr
return (res < 0) ? NULL : &rbuf[res];
}
gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_get_by_datagram(
const gnrc_netif_hdr_t *netif_hdr,
uint16_t tag)
{
return _rbuf_get_by_tag(netif_hdr, tag);
}
bool gnrc_sixlowpan_frag_rb_exists(const gnrc_netif_hdr_t *netif_hdr,
uint16_t tag)
@ -200,9 +206,18 @@ static gnrc_sixlowpan_frag_rb_t *_rbuf_get_by_tag(const gnrc_netif_hdr_t *netif_
#ifndef NDEBUG
static bool _valid_offset(gnrc_pktsnip_t *pkt, size_t offset)
{
return (sixlowpan_frag_1_is(pkt->data) && (offset == 0)) ||
(sixlowpan_frag_n_is(pkt->data) &&
(offset == sixlowpan_frag_offset(pkt->data)));
return (
IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG) &&
((sixlowpan_frag_1_is(pkt->data) && (offset == 0)) ||
(sixlowpan_frag_n_is(pkt->data) &&
(offset == sixlowpan_frag_offset(pkt->data))))
) || (
IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
/* offset == 0 is an abort condition that should not be handed to the
* reassembly buffer */
sixlowpan_sfr_rfrag_is(pkt->data) &&
(sixlowpan_sfr_rfrag_get_offset(pkt->data) != 0)
);
}
#endif
@ -234,6 +249,42 @@ static size_t _6lo_frag_size(gnrc_pktsnip_t *pkt, size_t offset, uint8_t *data)
return frag_size;
}
static uint16_t _6lo_sfr_datagram_size(gnrc_pktsnip_t *pkt, size_t offset)
{
/* offset doubles as datagram size in RFRAG header when sequence number is 0
* see https://tools.ietf.org/html/rfc8931#section-5.1 */
return (offset == 0) ? sixlowpan_sfr_rfrag_get_offset(pkt->data) : 0;
}
static uint8_t *_6lo_sfr_payload(gnrc_pktsnip_t *pkt)
{
return ((uint8_t *)pkt->data) + sizeof(sixlowpan_sfr_rfrag_t);
}
static size_t _6lo_sfr_frag_size(gnrc_pktsnip_t *pkt)
{
/* TODO: if necessary check MAC layer here,
* see https://tools.ietf.org/html/rfc8931#section-5.1 */
return sixlowpan_sfr_rfrag_get_frag_size(pkt->data);
}
static gnrc_pktsnip_t *_mark_frag_hdr(gnrc_pktsnip_t *pkt)
{
if (IS_USED(MODULE_GNRC_SIXLOWPAN_IPHC)) {
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
sixlowpan_sfr_rfrag_is(pkt->data)) {
return gnrc_pktbuf_mark(pkt, sizeof(sixlowpan_sfr_rfrag_t),
GNRC_NETTYPE_SIXLOWPAN);
}
else if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG) &&
sixlowpan_frag_is(pkt->data)) {
return gnrc_pktbuf_mark(pkt, sizeof(sixlowpan_frag_t),
GNRC_NETTYPE_SIXLOWPAN);
}
}
return NULL;
}
static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
size_t offset, unsigned page)
{
@ -244,18 +295,37 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
} entry;
const uint8_t *src = gnrc_netif_hdr_get_src_addr(netif_hdr);
const uint8_t *dst = gnrc_netif_hdr_get_dst_addr(netif_hdr);
uint8_t *data;
size_t frag_size;
uint8_t *data = NULL;
size_t frag_size = 0; /* assign 0, otherwise cppcheck complains ;-) */
int res;
uint16_t datagram_size;
uint16_t datagram_tag;
/* check if provided offset is the same as in fragment */
assert(_valid_offset(pkt, offset));
data = _6lo_frag_payload(pkt);
frag_size = _6lo_frag_size(pkt, offset, data);
datagram_size = sixlowpan_frag_datagram_size(pkt->data);
datagram_tag = sixlowpan_frag_datagram_tag(pkt->data);
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG) && sixlowpan_frag_is(pkt->data)) {
data = _6lo_frag_payload(pkt);
frag_size = _6lo_frag_size(pkt, offset, data);
datagram_size = sixlowpan_frag_datagram_size(pkt->data);
datagram_tag = sixlowpan_frag_datagram_tag(pkt->data);
}
else if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
sixlowpan_sfr_rfrag_is(pkt->data)) {
sixlowpan_sfr_rfrag_t *rfrag = pkt->data;
data = _6lo_sfr_payload(pkt);
frag_size = _6lo_sfr_frag_size(pkt);
/* offset doubles as datagram size in RFRAG header when sequence number
* is 0 */
datagram_size = _6lo_sfr_datagram_size(pkt, offset);
datagram_tag = rfrag->base.tag;
}
else {
/* either one of the if branches above was taken */
assert(data != NULL);
gnrc_pktbuf_release(pkt);
return RBUF_ADD_ERROR;
}
gnrc_sixlowpan_frag_rb_gc();
/* only check VRB for subsequent frags, first frags create and not get VRB
@ -301,6 +371,9 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
return RBUF_ADD_ERROR;
}
entry.rbuf = &rbuf[res];
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
offset += entry.rbuf->offset_diff;
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
if ((offset + frag_size) > entry.super->datagram_size) {
DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n");
gnrc_pktbuf_release(entry.rbuf->pkt);
@ -326,11 +399,11 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
DEBUG("6lo rbuf: add fragment data\n");
entry.super->current_size += (uint16_t)frag_size;
if (offset == 0) {
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
if (sixlowpan_iphc_is(data)) {
if (IS_USED(MODULE_GNRC_SIXLOWPAN_IPHC) &&
sixlowpan_iphc_is(data)) {
DEBUG("6lo rbuf: detected IPHC header.\n");
gnrc_pktsnip_t *frag_hdr = gnrc_pktbuf_mark(pkt,
sizeof(sixlowpan_frag_t), GNRC_NETTYPE_SIXLOWPAN);
gnrc_pktsnip_t *frag_hdr = _mark_frag_hdr(pkt);
if (frag_hdr == NULL) {
DEBUG("6lo rbuf: unable to mark fragment header. "
"aborting reassembly.\n");
@ -350,9 +423,7 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
return res;
}
}
else
#endif
if (data[0] == SIXLOWPAN_UNCOMP) {
else if (data[0] == SIXLOWPAN_UNCOMP) {
DEBUG("6lo rbuf: detected uncompressed datagram\n");
data++;
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_MINFWD) &&
@ -376,12 +447,17 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
return _forward_uncomp(pkt, rbuf, vrbe, page);
}
}
else if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
sixlowpan_sfr_rfrag_is(pkt->data)) {
entry.super->datagram_size--;
}
}
}
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_MINFWD)) {
/* all cases to try forwarding with minfwd above failed so just do
* normal reassembly. For the `minfwd` case however, we need to
* resize `entry.rbuf->pkt`, since we kept the packet allocation
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_MINFWD) ||
IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)) {
/* all cases to try forwarding with minfwd or SFR above failed so
* just do normal reassembly. For the `minfwd` case however, we need
* to resize `entry.rbuf->pkt`, since we kept the packet allocation
* with fragment forwarding as minimal as possible in
* `_rbuf_get()` */
res = _rbuf_resize_for_reassembly(entry.rbuf);
@ -423,6 +499,18 @@ static gnrc_sixlowpan_frag_rb_int_t *_rbuf_int_get_free(void)
return NULL;
}
#ifdef TEST_SUITES
bool gnrc_sixlowpan_frag_rb_ints_empty(void)
{
for (unsigned int i = 0; i < RBUF_INT_SIZE; i++) {
if (rbuf_int[i].end > 0) {
return false;
}
}
return true;
}
#endif /* TEST_SUITES */
static bool _rbuf_update_ints(gnrc_sixlowpan_frag_rb_base_t *entry,
uint16_t offset, size_t frag_size)
{
@ -510,8 +598,14 @@ static int _rbuf_get(const void *src, size_t src_len,
for (unsigned int i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
/* check first if entry already available */
if ((rbuf[i].pkt != NULL) && (rbuf[i].super.datagram_size == size) &&
(rbuf[i].super.tag == tag) && (rbuf[i].super.src_len == src_len) &&
if ((rbuf[i].pkt != NULL) && (rbuf[i].super.tag == tag) &&
((IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
/* not all SFR fragments carry the datagram size, so make 0 a
* legal value to not compare datagram size */
((size == 0) || (rbuf[i].super.datagram_size == size))) ||
(!IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) &&
(rbuf[i].super.datagram_size == size))) &&
(rbuf[i].super.src_len == src_len) &&
(rbuf[i].super.dst_len == dst_len) &&
(memcmp(rbuf[i].super.src, src, src_len) == 0) &&
(memcmp(rbuf[i].super.dst, dst, dst_len) == 0)) {
@ -624,6 +718,10 @@ static int _rbuf_get(const void *src, size_t src_len,
res->super.dst_len = dst_len;
res->super.tag = tag;
res->super.current_size = 0;
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
res->offset_diff = 0U;
memset(res->received, 0U, sizeof(res->received));
#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
DEBUG("6lo rfrag: entry %p (%s, ", (void *)res,
gnrc_netif_addr_to_str(res->super.src, res->super.src_len,

View File

@ -0,0 +1,101 @@
# Copyright (c) 2020 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.
#
menuconfig KCONFIG_USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR
bool "Configure GNRC 6LoWPAN Selective Fragment Recovery"
depends on USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR
help
Configure GNRC 6LoWPAN Selective Fragement Recovery using Kconfig.
if KCONFIG_USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR
config GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE
int "Default minimum value for fragment size (MinFragmentSize)"
default 96
config GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE
int "Default maximum value for fragment size (MaxFragmentSize)"
default 112
help
It must be lower than the minimum MTU along the path. A large value
augments the chances of buffer bloat and transmission loss. The value
must be less than 512 if the unit is defined for the PHY layer is the
octet.
config GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE
int "Default value for fragment size that the sender should use to start with (OptFragmentSize)"
default 112
help
Must be inclusively between @ref GNRC_SIXLOWPAN_SFR_MIN_FRAG_SIZE and
@ref GNRC_SIXLOWPAN_SFR_MAX_FRAG_SIZE
config GNRC_SIXLOWPAN_SFR_USE_ECN
bool "Indicates whether the sender should react to ECN (UseECN)"
default false
help
When the sender reacts to Explicit Congestion Notification (ECN) its
window size will vary between @ref
CONFIG_GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE and @ref
CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE.
if GNRC_SIXLOWPAN_SFR_USE_ECN
comment "Warning: Reaction of sender to ECN is not implemented yet"
endif
config GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE
int "Default minimum value of window size that the sender can use (MinWindowSize)"
default 1
range 1 32
config GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE
int "Default maximum value of window size that the sender can use (MaxWindowSize)"
default 16
range 1 32
config GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE
int "Default value of window size that the sender should start with (OptWindowSize)"
default 16
range 1 32
help
Must be inclusively between @ref GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE and
@ref GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE
config GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US
int "Default minimum amount of time between transmissions in microseconds (InterFrameGap)"
default 100
help
All packets to a same destination, and in particular fragments, may be
subject to receive while transmitting and hidden terminal collisions
with the next or the previous transmission as the fragments progress
along a same path. The InterFrameGap protects the propagation of to one
transmission before the next one is triggered and creates a duty cycle
that controls the ratio of air and memory in intermediate nodes that a
particular datagram will use.
config GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS
int "Minimum RFRAG-ACK timeout in msec before a node takes a next action (MinARQTimeOut)"
default 350
config GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS
int "Maximum RFRAG-ACK timeout in msec before a node takes a next action (MaxARQTimeOut)"
default 700
config GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS
int "Default RFRAG-ACK timeout in msec before a node takes a next action (OptARQTimeOut)"
default 700
help
Must be inclusively between @ref GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS
and @ref GNRC_SIXLOWPAN_SFR_MAX_ARQ_TIMEOUT_MS
config GNRC_SIXLOWPAN_SFR_FRAG_RETRIES
int "The maximum number of retries for a particular fragment (MaxFragRetries)"
default 2
config GNRC_SIXLOWPAN_SFR_DG_RETRIES
int "The maximum number of retries from scratch for a particular datagram (MaxDatagramRetries)"
default 0
endif

View File

@ -0,0 +1,3 @@
MODULE := gnrc_sixlowpan_frag_sfr
include $(RIOTBASE)/Makefile.base

File diff suppressed because it is too large Load Diff

View File

@ -184,6 +184,29 @@ gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get(
return NULL;
}
gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_reverse(
const gnrc_netif_t *netif, const uint8_t *src, size_t src_len,
unsigned tag)
{
DEBUG("6lo vrb: trying to get entry for reverse label switching (%s, %u)\n",
gnrc_netif_addr_to_str(src, src_len, addr_str), tag);
for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) {
gnrc_sixlowpan_frag_vrb_t *vrbe = &_vrb[i];
if ((vrbe->out_tag == tag) && (vrbe->out_netif == netif) &&
(memcmp(vrbe->super.dst, src, src_len) == 0)) {
DEBUG("6lo vrb: got VRB entry from (%s, %u)\n",
gnrc_netif_addr_to_str(vrbe->super.src,
vrbe->super.src_len,
addr_str), vrbe->super.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();

View File

@ -23,6 +23,9 @@
#include "net/gnrc/sixlowpan.h"
#include "net/gnrc/sixlowpan/frag.h"
#include "net/gnrc/sixlowpan/frag/rb.h"
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
#include "net/gnrc/sixlowpan/frag/sfr.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
#include "net/gnrc/sixlowpan/iphc.h"
#include "net/gnrc/netif.h"
#include "net/sixlowpan.h"
@ -114,11 +117,16 @@ void gnrc_sixlowpan_multiplex_by_size(gnrc_pktsnip_t *pkt,
DEBUG("6lo: Dispatch for sending\n");
gnrc_sixlowpan_dispatch_send(pkt, NULL, page);
}
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
#if defined(MODULE_GNRC_SIXLOWPAN_FRAG) || defined(MODULE_GNRC_SIXLOWPAN_FRAG_SFR)
else if (orig_datagram_size <= SIXLOWPAN_FRAG_MAX_LEN) {
DEBUG("6lo: Send fragmented (%u > %u)\n",
(unsigned int)datagram_size, netif->sixlo.max_frag_size);
gnrc_sixlowpan_frag_fb_t *fbuf;
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
bool sfr = gnrc_sixlowpan_frag_sfr_netif(netif);
#else /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
bool sfr = false;
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
fbuf = gnrc_sixlowpan_frag_fb_get();
if (fbuf == NULL) {
@ -136,9 +144,20 @@ void gnrc_sixlowpan_multiplex_by_size(gnrc_pktsnip_t *pkt,
fbuf->hint.fragsz = 0;
#endif
gnrc_sixlowpan_frag_send(pkt, fbuf, page);
}
if (!sfr) {
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
gnrc_sixlowpan_frag_send(pkt, fbuf, page);
#endif
}
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
else {
fbuf->sfr.cur_seq = 0U;
fbuf->sfr.frags_sent = 0U;
gnrc_sixlowpan_frag_sfr_send(pkt, fbuf, page);
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
}
#endif /* defined(MODULE_GNRC_SIXLOWPAN_FRAG) || defined(MODULE_GNRC_SIXLOWPAN_FRAG_SFR) */
else {
(void)orig_datagram_size;
DEBUG("6lo: packet too big (%u > %u)\n",
@ -216,6 +235,13 @@ static void _receive(gnrc_pktsnip_t *pkt)
return;
}
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
else if (sixlowpan_sfr_is((sixlowpan_sfr_t *)dispatch)) {
DEBUG("6lo: received 6LoWPAN recoverable fragment\n");
gnrc_sixlowpan_frag_sfr_recv(pkt, NULL, 0);
return;
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
else if (sixlowpan_iphc_is(dispatch)) {
DEBUG("6lo: received 6LoWPAN IPHC compressed datagram\n");
@ -331,6 +357,32 @@ static void _send(gnrc_pktsnip_t *pkt)
gnrc_sixlowpan_multiplex_by_size(pkt, datagram_size, netif, 0);
}
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_FB
static void _continue_fragmenting(gnrc_sixlowpan_frag_fb_t *fbuf)
{
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
if (fbuf->pkt == NULL) {
/* In case the timer fired before the entry was removed */
return;
}
gnrc_netif_t *netif = gnrc_netif_hdr_get_netif(fbuf->pkt->data);
assert(netif != NULL);
if (gnrc_sixlowpan_frag_sfr_netif(netif)) {
gnrc_sixlowpan_frag_sfr_send(NULL, fbuf, 0);
return;
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
gnrc_sixlowpan_frag_send(NULL, fbuf, 0);
#else /* MODULE_GNRC_SIXLOWPAN_FRAG */
(void)fbuf;
DEBUG("6lo: No fragmentation implementation available to sent\n");
assert(false);
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG */
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_FB */
static void *_event_loop(void *args)
{
msg_t msg, reply, msg_q[GNRC_SIXLOWPAN_MSG_QUEUE_SIZE];
@ -346,6 +398,10 @@ static void *_event_loop(void *args)
/* preinitialize ACK */
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
gnrc_sixlowpan_frag_sfr_init();
#endif
/* start event loop */
while (1) {
DEBUG("6lo: waiting for incoming message.\n");
@ -371,20 +427,25 @@ static void *_event_loop(void *args)
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_FB
case GNRC_SIXLOWPAN_FRAG_FB_SND_MSG:
DEBUG("6lo: send fragmented event received\n");
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
gnrc_sixlowpan_frag_send(NULL, msg.content.ptr, 0);
#else /* MODULE_GNRC_SIXLOWPAN_FRAG_FB */
DEBUG("6lo: No fragmentation implementation available to sent\n");
assert(false);
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_FB */
_continue_fragmenting(msg.content.ptr);
break;
#endif
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_FB */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_RB
case GNRC_SIXLOWPAN_FRAG_RB_GC_MSG:
DEBUG("6lo: garbage collect reassembly buffer event received\n");
gnrc_sixlowpan_frag_rb_gc();
break;
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
case GNRC_SIXLOWPAN_FRAG_SFR_ARQ_TIMEOUT_MSG:
DEBUG("6lo sfr: ARQ timeout received\n");
gnrc_sixlowpan_frag_sfr_arq_timeout(msg.content.ptr);
break;
case GNRC_SIXLOWPAN_FRAG_SFR_INTER_FRAG_GAP_MSG:
DEBUG("6lo sfr: sending next scheduled frame\n");
gnrc_sixlowpan_frag_sfr_inter_frame_gap();
break;
#endif
default:
DEBUG("6lo: operation not supported\n");

View File

@ -27,6 +27,9 @@
#include "net/gnrc/sixlowpan/ctx.h"
#include "net/gnrc/sixlowpan/frag/rb.h"
#include "net/gnrc/sixlowpan/frag/minfwd.h"
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
#include "net/gnrc/sixlowpan/frag/sfr.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
#include "net/gnrc/sixlowpan/frag/vrb.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
@ -116,6 +119,18 @@
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
static inline bool _is_rfrag(gnrc_pktsnip_t *sixlo)
{
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
assert((sixlo->next != NULL) &&
(sixlo->next->type == GNRC_NETTYPE_SIXLOWPAN));
return sixlowpan_sfr_rfrag_is(sixlo->next->data);
#else /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
(void)sixlo;
return false;
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
}
static inline bool _context_overlaps_iid(gnrc_sixlowpan_ctx_t *ctx,
ipv6_addr_t *addr,
eui64_t *iid)
@ -562,8 +577,14 @@ static size_t _iphc_nhc_ipv6_decode(gnrc_pktsnip_t *sixlo, size_t offset,
/* might be needed to be overwritten by IPv6 reassembly after the IPv6
* packet was reassembled to get complete length */
if (rbuf != NULL) {
payload_len = rbuf->super.datagram_size - *uncomp_hdr_len-
sizeof(ipv6_hdr_t);
if (_is_rfrag(sixlo)) {
payload_len = (rbuf->super.datagram_size + *uncomp_hdr_len) -
(sizeof(ipv6_hdr_t) - offset);
}
else {
payload_len = rbuf->super.datagram_size - *uncomp_hdr_len -
sizeof(ipv6_hdr_t);
}
}
else {
payload_len = (sixlo->size + *uncomp_hdr_len) -
@ -669,7 +690,13 @@ static size_t _iphc_nhc_udp_decode(gnrc_pktsnip_t *sixlo, size_t offset,
/* might be needed to be overwritten by IPv6 reassembly after the IPv6
* packet was reassembled to get complete length */
if (rbuf != NULL) {
payload_len = rbuf->super.datagram_size - *uncomp_hdr_len;
if (_is_rfrag(sixlo)) {
payload_len = rbuf->super.datagram_size + sizeof(udp_hdr_t) -
offset;
}
else {
payload_len = rbuf->super.datagram_size - *uncomp_hdr_len;
}
}
else {
payload_len = sixlo->size + sizeof(udp_hdr_t) - offset;
@ -781,7 +808,29 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr,
uint16_t payload_len;
if (rbuf != NULL) {
/* for a fragmented datagram we know the overall length already */
payload_len = (uint16_t)(rbuf->super.datagram_size - sizeof(ipv6_hdr_t));
if (_is_rfrag(sixlo)) {
DEBUG("6lo iphc: calculating payload length for SFR\n");
DEBUG(" - rbuf->super.datagram_size: %u\n",
rbuf->super.datagram_size);
DEBUG(" - payload_offset: %u\n", (unsigned)payload_offset);
DEBUG(" - uncomp_hdr_len: %u\n", (unsigned)uncomp_hdr_len);
/* set IPv6 header payload length field to the length of whatever is
* left after removing the 6LoWPAN header and adding uncompressed
* headers */
payload_len = (rbuf->super.datagram_size - payload_offset) +
(uncomp_hdr_len - sizeof(ipv6_hdr_t));
DEBUG(" => %u\n", payload_len);
/* adapt datagram size for uncompressed datagram */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
/* guard required because SFR-specific field of vrbe is accessed */
rbuf->offset_diff += (uncomp_hdr_len - payload_offset);
rbuf->super.datagram_size += rbuf->offset_diff;
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
}
else {
/* for a fragmented datagram we know the overall length already */
payload_len = (uint16_t)(rbuf->super.datagram_size - sizeof(ipv6_hdr_t));
}
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
DEBUG("6lo iphc: VRB present, trying to create entry for dst %s\n",
ipv6_addr_to_str(addr_str, &ipv6_hdr->dst, sizeof(addr_str)));
@ -845,6 +894,16 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr,
ipv6_hdr->hl--;
vrbe->super.current_size = rbuf->super.current_size;
if ((ipv6 = _encode_frag_for_forwarding(ipv6, vrbe))) {
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
/* guard required because SFR-specific field of vrbe is
* accessed */
if (_is_rfrag(sixlo)) {
vrbe->in_netif = iface;
/* calculate offset difference due to compression */
vrbe->offset_diff = ((int)gnrc_pkt_len(ipv6->next)) -
sixlo->size;
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
if ((res = _forward_frag(ipv6, sixlo->next, vrbe, page)) == 0) {
DEBUG("6lo iphc: successfully recompressed and forwarded "
"1st fragment\n");
@ -930,6 +989,11 @@ static int _forward_frag(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *frag_hdr,
}
/* the following is just debug output for testing without any forwarding
* scheme */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR
if (sixlowpan_sfr_rfrag_is(frag_hdr->data)) {
return gnrc_sixlowpan_frag_sfr_forward(pkt, frag_hdr->data, vrbe, page);
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR */
DEBUG("6lo iphc: Do not know how to forward fragment from (%s, %u) ",
gnrc_netif_addr_to_str(vrbe->super.src, vrbe->super.src_len,
addr_str), vrbe->super.tag);

View File

@ -16,6 +16,9 @@
#include <stdio.h>
#include "net/gnrc/sixlowpan/frag/stats.h"
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS
#include "net/gnrc/sixlowpan/frag/sfr.h"
#endif
int _gnrc_6lo_frag_stats(int argc, char **argv)
{
@ -28,6 +31,24 @@ int _gnrc_6lo_frag_stats(int argc, char **argv)
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
printf("VRB full: %u\n", stats->vrb_full);
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS
gnrc_sixlowpan_frag_sfr_stats_t sfr;
gnrc_sixlowpan_frag_sfr_stats_get(&sfr);
printf("DG resends: %lu\n", (long unsigned)sfr.datagram_resends);
printf("frags sent: usual: %lu, aborts: %lu, forwarded: %lu\n",
(long unsigned)sfr.fragments_sent.usual,
(long unsigned)sfr.fragments_sent.aborts,
(long unsigned)sfr.fragments_sent.forwarded);
printf("frag resends: NACK: %lu, timeout: %lu\n",
(long unsigned)sfr.fragment_resends.by_nack,
(long unsigned)sfr.fragment_resends.by_timeout);
printf("ACKs: full: %lu, partly: %lu, aborts: %lu, forwarded: %lu\n",
(long unsigned)sfr.acks.full,
(long unsigned)sfr.acks.partly,
(long unsigned)sfr.acks.aborts,
(long unsigned)sfr.acks.forwarded);
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS */
printf("frags complete: %u\n", stats->fragments);
printf("dgs complete: %u\n", stats->datagrams);
return 0;

View File

@ -536,6 +536,25 @@ static void test_rbuf_add__overlap_rhs(void)
_check_pktbuf(NULL);
}
static void test_rbuf_get_by_dg(void)
{
const gnrc_sixlowpan_frag_rb_t *entry;
TEST_ASSERT_NULL(
gnrc_sixlowpan_frag_rb_get_by_datagram(&_test_netif_hdr.hdr, TEST_TAG)
);
/* add a fragment */
_rbuf_create_first_fragment();
TEST_ASSERT_NOT_NULL(
gnrc_sixlowpan_frag_rb_get_by_datagram(&_test_netif_hdr.hdr, TEST_TAG)
);
/* get entry to release entry->pkt it in `_check_pktbuf()` */
entry = _first_non_empty_rbuf();
/* entry is however not properly removed yet */
TEST_ASSERT_NOT_NULL(entry);
_check_pktbuf(entry);
}
static void test_rbuf_exists(void)
{
const gnrc_sixlowpan_frag_rb_t *entry;
@ -631,6 +650,7 @@ static void run_unittests(void)
new_TestFixture(test_rbuf_add__too_big_fragment),
new_TestFixture(test_rbuf_add__overlap_lhs),
new_TestFixture(test_rbuf_add__overlap_rhs),
new_TestFixture(test_rbuf_get_by_dg),
new_TestFixture(test_rbuf_exists),
new_TestFixture(test_rbuf_rm_by_dg),
new_TestFixture(test_rbuf_rm),

View File

@ -0,0 +1,36 @@
include ../Makefile.tests_common
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_sixlowpan_frag_sfr
USEMODULE += gnrc_sixlowpan_iphc
USEMODULE += gnrc_ipv6_nib
USEMODULE += gnrc_netif
USEMODULE += embunit
USEMODULE += netdev_ieee802154
USEMODULE += netdev_test
CFLAGS += -DTEST_SUITES
include $(RIOTBASE)/Makefile.include
ifndef CONFIG_GNRC_IPV6_NIB_NO_RTR_SOL
# disable router solicitations so they don't interfere with the tests
CFLAGS += -DCONFIG_GNRC_IPV6_NIB_NO_RTR_SOL=1
endif
# SFR parameters
ifndef CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE
# fix window size
CFLAGS += -DCONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE=3U
endif
ifndef CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US
# decrease inter frame gap
CFLAGS += -DCONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US=5U
endif
ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS
# decrease minimal ARQ timeout
CFLAGS += -DCONFIG_GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS=100U
endif
ifndef CONFIG_GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS
# decrease initial ARQ timeout
CFLAGS += -DCONFIG_GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS=100U
endif

View File

@ -0,0 +1,42 @@
BOARD_INSUFFICIENT_MEMORY := \
arduino-duemilanove \
arduino-leonardo \
arduino-mega2560 \
arduino-nano \
arduino-uno \
atmega1284p \
atmega328p \
blackpill \
bluepill \
derfmega128 \
hifive1 \
hifive1b \
i-nucleo-lrwan1 \
im880b \
mega-xplained \
microduino-corerf \
msb-430 \
msb-430h \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f070rb \
nucleo-f072rb \
nucleo-f302r8 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
saml10-xpro \
saml11-xpro \
stk3200 \
stm32f030f4-demo \
stm32f0discovery \
stm32l0538-disco \
stm32mp157c-dk2 \
telosb \
waspmote-pro \
z1 \
#

View File

@ -0,0 +1,10 @@
CONFIG_KCONFIG_USEMODULE_GNRC_IPV6_NIB=y
CONFIG_KCONFIG_USEMODULE_GNRC_SIXLOWPAN=y
CONFIG_KCONFIG_USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR=y
# disable router solicitations so they don't interfere with the tests
CONFIG_GNRC_IPV6_NIB_NO_RTR_SOL=y
# preconfigure SFR for tests
CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE=3
CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US=5
CONFIG_GNRC_SIXLOWPAN_SFR_MIN_ARQ_TIMEOUT_MS=100
CONFIG_GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS=100

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2017 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 tests_gnrc_ipv6_nib Common header for GNRC's NIB tests
* @ingroup tests
* @brief Common definitions for GNRC's NIB tests
* @{
*
* @file
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include "net/gnrc.h"
#include "net/gnrc/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#define _LL0 (0xb8)
#define _LL1 (0x8c)
#define _LL2 (0xcc)
#define _LL3 (0xba)
#define _LL4 (0xef)
#define _LL5 (0x9a)
#define _LL6 (0x67)
#define _LL7 (0x42)
extern gnrc_netif_t *_mock_netif;
void _tests_init(void);
void _common_set_up(void);
#ifdef __cplusplus
}
#endif
#endif /* COMMON_H */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2017 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 <m.lenders@fu-berlin.de>
*/
#include "common.h"
#include "msg.h"
#include "net/gnrc.h"
#include "net/ethernet.h"
#include "net/gnrc/ipv6/nib.h"
#include "net/gnrc/netif/ieee802154.h"
#include "net/gnrc/netif/internal.h"
#include "net/netdev_test.h"
#include "sched.h"
#include "thread.h"
#define _MSG_QUEUE_SIZE (2)
gnrc_netif_t *_mock_netif = NULL;
static netdev_test_t _mock_netdev;
static char _mock_netif_stack[THREAD_STACKSIZE_DEFAULT];
static msg_t _main_msg_queue[_MSG_QUEUE_SIZE];
static gnrc_netif_t _netif;
void _common_set_up(void)
{
assert(_mock_netif != NULL);
gnrc_ipv6_nib_init();
gnrc_netif_acquire(_mock_netif);
gnrc_ipv6_nib_init_iface(_mock_netif);
gnrc_netif_release(_mock_netif);
}
int _get_device_type(netdev_t *dev, void *value, size_t max_len)
{
(void)dev;
assert(max_len == sizeof(uint16_t));
*((uint16_t *)value) = NETDEV_TYPE_IEEE802154;
return sizeof(uint16_t);
}
static int _get_netdev_proto(netdev_t *netdev, void *value, size_t max_len)
{
assert(max_len == sizeof(gnrc_nettype_t));
(void)netdev;
*((gnrc_nettype_t *)value) = GNRC_NETTYPE_SIXLOWPAN;
return sizeof(gnrc_nettype_t);
}
int _get_max_packet_size(netdev_t *dev, void *value, size_t max_len)
{
(void)dev;
assert(max_len == sizeof(uint16_t));
*((uint16_t *)value) = 102U;
return sizeof(uint16_t);
}
int _get_src_len(netdev_t *dev, void *value, size_t max_len)
{
(void)dev;
assert(max_len == sizeof(uint16_t));
*((uint16_t *)value) = IEEE802154_LONG_ADDRESS_LEN;
return sizeof(uint16_t);
}
int _get_address_long(netdev_t *dev, void *value, size_t max_len)
{
static const uint8_t addr[] = { _LL0, _LL1, _LL2, _LL3,
_LL4, _LL5, _LL6, _LL7 };
(void)dev;
assert(max_len >= sizeof(addr));
memcpy(value, addr, sizeof(addr));
return sizeof(addr);
}
int _get_proto(netdev_t *dev, void *value, size_t max_len)
{
(void)dev;
assert(max_len == sizeof(gnrc_nettype_t));
*((gnrc_nettype_t *)value) = GNRC_NETTYPE_SIXLOWPAN;
return sizeof(gnrc_nettype_t);
}
void _tests_init(void)
{
int res;
msg_init_queue(_main_msg_queue, _MSG_QUEUE_SIZE);
netdev_test_setup(&_mock_netdev, 0);
netdev_test_set_get_cb(&_mock_netdev, NETOPT_DEVICE_TYPE,
_get_device_type);
netdev_test_set_get_cb(&_mock_netdev, NETOPT_PROTO,
_get_netdev_proto);
netdev_test_set_get_cb(&_mock_netdev, NETOPT_MAX_PACKET_SIZE,
_get_max_packet_size);
netdev_test_set_get_cb(&_mock_netdev, NETOPT_SRC_LEN,
_get_src_len);
netdev_test_set_get_cb(&_mock_netdev, NETOPT_ADDRESS_LONG,
_get_address_long);
netdev_test_set_get_cb(&_mock_netdev, NETOPT_PROTO,
_get_proto);
res = gnrc_netif_ieee802154_create(
&_netif, _mock_netif_stack, THREAD_STACKSIZE_DEFAULT,
GNRC_NETIF_PRIO, "mockup_wpan", &_mock_netdev.netdev.netdev
);
assert(res == 0);
_mock_netif = &_netif;
}
/** @} */

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
# Copyright (C) 2016 Takuo Yonezawa <Yonezawa-T2@mail.dnp.co.jp>
#
# 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.
import sys
from testrunner import run
def testfunc(child):
child.expect(r"OK \(\d+ tests\)")
if __name__ == "__main__":
sys.exit(run(testfunc))