mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16156 from miri64/gnrc_sixlowpan_frag_sfr/feat/congure
gnrc_sixlowpan_frag_sfr: provide CongURE support
This commit is contained in:
commit
9ae66beedf
@ -230,6 +230,12 @@ PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_ecn_if_in
|
||||
PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_ecn_if_out
|
||||
PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_ecn_fqueue
|
||||
PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_stats
|
||||
##
|
||||
## @addtogroup net_gnrc_sixlowpan_frag_sfr_congure
|
||||
## @{
|
||||
##
|
||||
PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_congure
|
||||
## @}
|
||||
PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc
|
||||
PSEUDOMODULES += gnrc_sixlowpan_nd_border_router
|
||||
PSEUDOMODULES += gnrc_sixlowpan_router_default
|
||||
|
@ -209,7 +209,13 @@ extern "C" {
|
||||
* size will vary between @ref CONFIG_GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE and @ref
|
||||
* CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE.
|
||||
*/
|
||||
#ifdef CONFIG_GNRC_SIXLOWPAN_SFR_USE_ECN
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
#define CONFIG_GNRC_SIXLOWPAN_SFR_USE_ECN 1U
|
||||
#else
|
||||
#define CONFIG_GNRC_SIXLOWPAN_SFR_USE_ECN 0U
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default minimum value of window size that the sender can use
|
||||
@ -377,6 +383,17 @@ extern "C" {
|
||||
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_ECN_FQUEUE_DEN
|
||||
#define CONFIG_GNRC_SIXLOWPAN_SFR_ECN_FQUEUE_DEN 2U
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Deactivate automatic handling of ARQ timer
|
||||
*
|
||||
* This requires an external source (e.g. a test application) to call
|
||||
* @ref gnrc_sixlowpan_frag_sfr_arq_timeout() for
|
||||
* @ref net_gnrc_sixlowpan_frag_sfr to still work properly.
|
||||
*/
|
||||
#ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER
|
||||
#define CONFIG_GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER 0U
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -182,8 +182,11 @@ void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf);
|
||||
|
||||
/**
|
||||
* @brief Handles inter frame gap
|
||||
*
|
||||
* @param[in] fbuf The fragmentation buffer representing the datagram for which
|
||||
* the next frame should uphold the inter frame gap
|
||||
*/
|
||||
void gnrc_sixlowpan_frag_sfr_inter_frame_gap(void);
|
||||
void gnrc_sixlowpan_frag_sfr_inter_frame_gap(gnrc_sixlowpan_frag_fb_t *fbuf);
|
||||
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)
|
||||
/**
|
||||
|
428
sys/include/net/gnrc/sixlowpan/frag/sfr/congure.h
Normal file
428
sys/include/net/gnrc/sixlowpan/frag/sfr/congure.h
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_congure Congestion control for 6LoWPAN SFR
|
||||
* @ingroup net_gnrc_sixlowpan_frag_sfr
|
||||
*
|
||||
* @brief Congestion control for 6LoWPAN SFR using the @ref sys_congure
|
||||
*
|
||||
* When included, this module enables congestion control for 6LoWPAN Selective Fragment Recovery
|
||||
* (SFR). The flavor of congestion control can be selected using the following sub-modules:
|
||||
*
|
||||
* - TBD
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Congure definitions for @ref net_gnrc_sixlowpan_frag_sfr
|
||||
*
|
||||
* @author Martine S. Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef NET_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_H
|
||||
#define NET_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "congure.h"
|
||||
#include "kernel_defines.h"
|
||||
#include "net/gnrc/sixlowpan/frag/sfr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The user-defined window unit for congure is one fragment with SFR
|
||||
*/
|
||||
#define GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT (1U)
|
||||
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE) || DOXYGEN
|
||||
/**
|
||||
* @brief Retrieve CongURE state object from a pool of free objects
|
||||
*
|
||||
* Needs to be defined in for a each CongURE implementation `congure_x` e.g. as
|
||||
* a sub-module `gnrc_sixlowpan_frag_sfr_congure_x` and call the respective
|
||||
* `congure_x_snd_setup` function when a free object is available for that
|
||||
* object. As such, congure_snd_t::driver == NULL can be used as an identifier
|
||||
* if a state object is free.
|
||||
*
|
||||
* The pool of objects has to have an initial size of at least
|
||||
* @ref CONFIG_GNRC_SIXLOWPAN_FRAG_FB_SIZE.
|
||||
*
|
||||
* The window unit is @ref GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT.
|
||||
*
|
||||
* @return A CongURE state object on success
|
||||
* @return NULL, if no free CongURE state object is available (including when
|
||||
* when module `gnrc_sixlowpan_frag_sfr_congure` is not included).
|
||||
*/
|
||||
congure_snd_t *gnrc_sixlowpan_frag_sfr_congure_snd_get(void);
|
||||
#else
|
||||
static inline congure_snd_t *gnrc_sixlowpan_frag_sfr_congure_snd_get(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Frees the CongURE state object
|
||||
*
|
||||
* This makes a CongURE state object retrievable with
|
||||
* @ref gnrc_sixlowpan_frag_sfr_congure_snd_get again.
|
||||
*
|
||||
* @pre CongURE object is not NULL when called with module
|
||||
* `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] c A CongURE state object
|
||||
*
|
||||
* @note Does not do anything without the module
|
||||
* `gnrc_sixlowpan_frag_sfr_congure`
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_free(congure_snd_t *c)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
c->driver = NULL;
|
||||
#else
|
||||
(void)c;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Frees the CongURE state object of a fragmentation buffer and set's
|
||||
* it to `NULL`
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer entry
|
||||
*
|
||||
* @note Does not do anything without the module
|
||||
* `gnrc_sixlowpan_frag_sfr_congure`
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_destroy(gnrc_sixlowpan_frag_fb_t *fb)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_free(fb->sfr.congure);
|
||||
fb->sfr.congure = NULL;
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a CongURE state object in a fragmentation buffer entry
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer entry
|
||||
*
|
||||
* @note Does not do anything without the module
|
||||
* `gnrc_sixlowpan_frag_sfr_congure`
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_init(gnrc_sixlowpan_frag_fb_t *fb)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
fb->sfr.congure->driver->init(fb->sfr.congure, fb);
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve CongURE state object when not retrieved and initialize it
|
||||
* for a fragmentation buffer entry
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer entry
|
||||
*
|
||||
* @note Does not do anything without the module
|
||||
* `gnrc_sixlowpan_frag_sfr_congure`
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_setup(gnrc_sixlowpan_frag_fb_t *fb)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
if (fb->sfr.congure == NULL) {
|
||||
fb->sfr.congure = gnrc_sixlowpan_frag_sfr_congure_snd_get();
|
||||
assert(fb->sfr.congure);
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_init(fb);
|
||||
if (fb->sfr.congure->cwnd > CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE) {
|
||||
fb->sfr.congure->cwnd = CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if given fragmentation buffer entry is within congestion
|
||||
* window
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer entry
|
||||
*
|
||||
* @note Without the module `gnrc_sixlowpan_frag_sfr_congure` the
|
||||
* fragmentation buffer entry is checked against
|
||||
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE
|
||||
*
|
||||
* @retval true When @p fb is in congestion window
|
||||
* @retval false When @p fb is not in congestion window
|
||||
*/
|
||||
static inline bool gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(gnrc_sixlowpan_frag_fb_t *fb)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
return fb->sfr.frags_sent < fb->sfr.congure->cwnd;
|
||||
#else
|
||||
return fb->sfr.frags_sent < CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if given fragmentation buffer entry would still be within
|
||||
* congestion window after next send
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @note Without the module `gnrc_sixlowpan_frag_sfr_congure` the
|
||||
* fragmentation buffer entry is checked against
|
||||
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE
|
||||
*
|
||||
* @retval true When @p fb can still send one fragment under the congestion
|
||||
* window constraint.
|
||||
* @retval false When @p fb can not still send one fragment under the
|
||||
* congestion window constraint.
|
||||
*/
|
||||
static inline bool gnrc_sixlowpan_frag_sfr_congure_snd_next_in_cwnd(gnrc_sixlowpan_frag_fb_t *fb)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
return (fb->sfr.frags_sent + GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT)
|
||||
< fb->sfr.congure->cwnd;
|
||||
#else
|
||||
return (fb->sfr.frags_sent + GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT)
|
||||
< CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if inter-frame gap is provided
|
||||
*
|
||||
* Either because @ref CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US is greater
|
||||
* 0 or module `gnrc_sixlowpan_frag_sfr_congure` is provided
|
||||
*
|
||||
* @retval true When an inter-frame gap can be provided
|
||||
* @retval false When the inter-frame gap is supposed to be 0.
|
||||
*/
|
||||
static inline bool gnrc_sixlowpan_frag_sfr_congure_snd_has_inter_frame_gap(void)
|
||||
{
|
||||
return (CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US > 0) ||
|
||||
IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns inter-frame gap if provided by CongURE implementation
|
||||
*
|
||||
* When module `gnrc_sixlowpan_frag_sfr_congure` is provided it will provide
|
||||
* congure_snd_driver_t::inter_message_interval() of the CongURE state object of
|
||||
* the provided fragmentation buffer with @ref
|
||||
* CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US as a lower bound.
|
||||
* If congure_snd_driver_t::inter_message_interval returns -1, @p fb is NULL, or
|
||||
* without the module `gnrc_sixlowpan_frag_sfr_congure` it will return
|
||||
* @ref CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* `fb` is `NULL` and when called with module
|
||||
* `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer. May be NULL.
|
||||
*
|
||||
* @return The inter-frame gap for the given fragmentation buffer, but
|
||||
*/
|
||||
static inline uint32_t gnrc_sixlowpan_frag_sfr_congure_snd_inter_frame_gap(
|
||||
gnrc_sixlowpan_frag_fb_t *fb
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
if (fb != NULL) {
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
int32_t res = c->driver->inter_msg_interval(
|
||||
c, GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT
|
||||
);
|
||||
|
||||
if ((res >= 0) &&
|
||||
((unsigned)res >= CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US)) {
|
||||
return (uint32_t)res;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
return CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report to CongURE that a fragment was sent.
|
||||
*
|
||||
* Calls congure_snd_driver_t::report_msg_sent for the CongURE state object of
|
||||
* @p fb with `msg_size` @ref GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT.
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer.
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_sent(
|
||||
gnrc_sixlowpan_frag_fb_t *fb
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
|
||||
c->driver->report_msg_sent(c, GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT);
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report to CongURE that a fragment as discarded.
|
||||
*
|
||||
* Calls congure_snd_driver_t::report_msg_discarded for the CongURE state object
|
||||
* of @p fb with `msg_size` @ref GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT.
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer.
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_discard(
|
||||
gnrc_sixlowpan_frag_fb_t *fb
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
|
||||
c->driver->report_msg_discarded(c, GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_UNIT);
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report to CongURE that the ACK for a fragment timed out.
|
||||
*
|
||||
* Calls congure_snd_driver_t::report_msgs_timeout for the CongURE state object
|
||||
* of @p fb with gnrc_sixlowpan_frag_sfr_fb_t::window of @p fb as `msgs`.
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer.
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_report_frags_timeout(
|
||||
gnrc_sixlowpan_frag_fb_t *fb
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
|
||||
c->driver->report_msgs_timeout(c, (congure_snd_msg_t *)(&fb->sfr.window));
|
||||
#else
|
||||
(void)fb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report to CongURE that a number of fragments are known to be lost.
|
||||
*
|
||||
* Calls congure_snd_driver_t::report_msgs_lost for the CongURE state object
|
||||
* of @p fb with @p frags.
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer.
|
||||
* @param[in] frags A collection of messages that are known to be lost.
|
||||
* The list may be changed by the function.
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_report_frags_lost(
|
||||
gnrc_sixlowpan_frag_fb_t *fb, congure_snd_msg_t *frags
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
|
||||
c->driver->report_msgs_lost(c, frags);
|
||||
#else
|
||||
(void)fb;
|
||||
(void)frags;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report to CongURE that a number of fragments are known to be lost.
|
||||
*
|
||||
* Calls congure_snd_driver_t::report_msgs_acked for the CongURE state object
|
||||
* of @p fb with @p frag and @p ack.
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer.
|
||||
* @param[in] frag The ACK'd fragment.
|
||||
* @param[in] ack The received ACK.
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_acked(
|
||||
gnrc_sixlowpan_frag_fb_t *fb,
|
||||
congure_snd_msg_t *frag,
|
||||
congure_snd_ack_t *ack
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
|
||||
c->driver->report_msg_acked(c, frag, ack);
|
||||
if (c->cwnd > CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE) {
|
||||
c->cwnd = CONFIG_GNRC_SIXLOWPAN_SFR_MAX_WIN_SIZE;
|
||||
}
|
||||
#else
|
||||
(void)fb;
|
||||
(void)frag;
|
||||
(void)ack;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report to CongURE that ECN bit was set in an ACK.
|
||||
*
|
||||
* Calls congure_snd_driver_t::report_ecn_ce for the CongURE state object
|
||||
* of @p fb with @p time.
|
||||
*
|
||||
* @pre CongURE object of the fragmentation buffer entry is initialized when
|
||||
* called with module `gnrc_sixlowpan_frag_sfr_congure` used.
|
||||
*
|
||||
* @param[in] fb A fragmentation buffer.
|
||||
* @param[in] time Timestamp in milliseconds of the earliest fragment
|
||||
* for which the notified congestion occurred was sent.
|
||||
*/
|
||||
static inline void gnrc_sixlowpan_frag_sfr_congure_snd_report_ecn(
|
||||
gnrc_sixlowpan_frag_fb_t *fb, uint32_t time
|
||||
)
|
||||
{
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
congure_snd_t *c = fb->sfr.congure;
|
||||
|
||||
c->driver->report_ecn_ce(c, (ztimer_now_t)time);
|
||||
#else
|
||||
(void)fb;
|
||||
(void)time;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE_H */
|
||||
/** @} */
|
@ -22,7 +22,9 @@
|
||||
|
||||
#include "bitfield.h"
|
||||
#include "clist.h"
|
||||
#include "congure.h"
|
||||
#include "evtimer_msg.h"
|
||||
#include "kernel_defines.h"
|
||||
#include "msg.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
@ -43,6 +45,9 @@ typedef union {
|
||||
* fragment recovery
|
||||
*/
|
||||
typedef struct gnrc_sixlowpan_frag_sfr_fb {
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE) || DOXYGEN
|
||||
congure_snd_t *congure; /**< state object for [CongURE](@ref sys_congure) */
|
||||
#endif
|
||||
/**
|
||||
* @brief Acknowledgment request timeout event
|
||||
*/
|
||||
@ -51,8 +56,6 @@ typedef struct gnrc_sixlowpan_frag_sfr_fb {
|
||||
* 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;
|
||||
|
@ -240,6 +240,14 @@ ifneq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_sixlowpan_frag_sfr_congure_%,$(USEMODULE)))
|
||||
USEMODULE += gnrc_sixlowpan_frag_sfr_congure
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_sixlowpan_frag_sfr_congure,$(USEMODULE)))
|
||||
USEMODULE += gnrc_sixlowpan_frag_sfr
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_sixlowpan_frag_sfr_ecn_%,$(USEMODULE)))
|
||||
USEMODULE += gnrc_sixlowpan_frag_sfr_ecn
|
||||
endif
|
||||
|
@ -34,6 +34,7 @@ config GNRC_SIXLOWPAN_SFR_OPT_FRAG_SIZE
|
||||
|
||||
config GNRC_SIXLOWPAN_SFR_USE_ECN
|
||||
bool "Indicates whether the sender should react to Explicit Content Notification (UseECN)"
|
||||
default true if KCONFIG_USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE
|
||||
default false
|
||||
help
|
||||
When the sender reacts to Explicit Congestion Notification (ECN) its
|
||||
@ -41,8 +42,8 @@ config GNRC_SIXLOWPAN_SFR_USE_ECN
|
||||
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"
|
||||
if GNRC_SIXLOWPAN_SFR_USE_ECN && !KCONFIG_USEMODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE
|
||||
comment "Warning: Reaction to ECN requires module `gnrc_sixlowpan_frag_sfr_congure`"
|
||||
endif
|
||||
|
||||
config GNRC_SIXLOWPAN_SFR_MIN_WIN_SIZE
|
||||
@ -168,4 +169,12 @@ config GNRC_SIXLOWPAN_SFR_ECN_FQUEUE_DEN
|
||||
@ref CONFIG_GNRC_SIXLOWPAN_SFR_ECN_FQUEUE_NUM / @ref CONFIG_GNRC_SIXLOWPAN_SFR_ECN_FQUEUE_DEN
|
||||
endif
|
||||
|
||||
config GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER
|
||||
bool "Deactivate automatic handling of ARQ timer"
|
||||
default n
|
||||
help
|
||||
This requires an external source (e.g. a test application) to call
|
||||
@ref gnrc_sixlowpan_frag_sfr_arq_timeout() for
|
||||
@ref net_gnrc_sixlowpan_frag_sfr to still work properly.
|
||||
|
||||
endif
|
||||
|
@ -1,3 +1,8 @@
|
||||
MODULE := gnrc_sixlowpan_frag_sfr
|
||||
|
||||
SRC := $(MODULE).c
|
||||
|
||||
# enable submodules
|
||||
SUBMODULES := 1
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "net/gnrc/sixlowpan/frag/sfr.h"
|
||||
#include "net/gnrc/sixlowpan/frag/sfr/congure.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
@ -49,14 +50,12 @@
|
||||
CONFIG_GNRC_SIXLOWPAN_FRAG_VRB_SIZE)
|
||||
|
||||
typedef struct {
|
||||
clist_node_t super; /**< list parent instance */
|
||||
uint32_t last_sent; /**< last time sent in microseconds */
|
||||
congure_snd_msg_t super; /**< CongURE message parent */
|
||||
/**
|
||||
* @brief Acknowledgment request flag, sequence number, and fragment size
|
||||
*/
|
||||
uint16_t ar_seq_fs;
|
||||
uint16_t offset; /**< offset of the fragment */
|
||||
uint8_t retries; /**< how often the fragment was retried */
|
||||
uint16_t offset; /**< offset of the fragment */
|
||||
} _frag_desc_t;
|
||||
|
||||
typedef struct {
|
||||
@ -175,15 +174,25 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *netif,
|
||||
* @brief Send a abort pseudo fragment for datagram identified by @p tag
|
||||
*
|
||||
* @param[in] pkt Datagram that is to be aborted.
|
||||
* @param[in] tag Tag for @p pkt.
|
||||
* @param[in] fbuf Fragmentation buffer for @p pkt.
|
||||
* @param[in] req_ack Request ACK for pseudo fragment from receive
|
||||
* @param[in] page Current 6Lo dispatch parsing page.
|
||||
*
|
||||
* @return true, if abort pseudo fragment was sent.
|
||||
* @return false, if abort pseudo fragment was unable to be sent.
|
||||
*/
|
||||
static bool _send_abort_frag(gnrc_pktsnip_t *pkt, uint8_t tag, bool req_ack,
|
||||
unsigned page);
|
||||
static bool _send_abort_frag(gnrc_pktsnip_t *pkt,
|
||||
gnrc_sixlowpan_frag_fb_t *fbuf,
|
||||
bool req_ack, unsigned page);
|
||||
|
||||
/**
|
||||
* @brief Adapts currently sent number of fragments to current window size
|
||||
*
|
||||
* Balances `fbuf->sfr.window` with `fbuf->sfr.congure->cwnd`
|
||||
*
|
||||
* @param[in] fbuf Fragmentation buffer to adapt window for
|
||||
*/
|
||||
static void _shrink_window(gnrc_sixlowpan_frag_fb_t *fbuf);
|
||||
|
||||
/**
|
||||
* @brief Re-send a fragment
|
||||
@ -235,8 +244,11 @@ static void _send_ack(gnrc_netif_t *netif, const uint8_t *dst, uint8_t dst_len,
|
||||
/**
|
||||
* @brief Schedule next frame (RFRAG or RFRAG-ACK) with
|
||||
* @ref GNRC_SIXLOWPAN_FRAG_SFR_INTER_FRAG_GAP_MSG
|
||||
*
|
||||
* @param[in] fbuf A fragmentation buffer holding the state of the datagram
|
||||
* and recoverable fragments.
|
||||
*/
|
||||
static void _sched_next_frame(void);
|
||||
static void _sched_next_frame(gnrc_sixlowpan_frag_fb_t *fbuf);
|
||||
|
||||
/**
|
||||
* @brief Schedule ARQ timeout
|
||||
@ -297,13 +309,13 @@ static int _forward_rfrag(gnrc_pktsnip_t *pkt, _generic_rb_entry_t *entry,
|
||||
/* ====== PUBLIC FUNCTION DEFINITIONS ====== */
|
||||
void gnrc_sixlowpan_frag_sfr_init(void)
|
||||
{
|
||||
if (CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US > 0) {
|
||||
if (gnrc_sixlowpan_frag_sfr_congure_snd_has_inter_frame_gap()) {
|
||||
for (unsigned i = 0; i < FRAME_QUEUE_POOL_SIZE; i++) {
|
||||
clist_rpush(&_frame_queue_free, &_frame_queue_pool[i].super);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < FRAG_DESCS_POOL_SIZE; i++) {
|
||||
clist_rpush(&_frag_descs_free, &_frag_descs_pool[i].super);
|
||||
clist_rpush(&_frag_descs_free, &_frag_descs_pool[i].super.super);
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,6 +341,7 @@ void gnrc_sixlowpan_frag_sfr_send(gnrc_pktsnip_t *pkt, void *ctx,
|
||||
|
||||
if (fbuf->offset == 0) {
|
||||
DEBUG("6lo sfr: sending first fragment\n");
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_setup(fbuf);
|
||||
res = _send_1st_fragment(netif, fbuf, page, &tx_sync);
|
||||
if (res == 0) {
|
||||
DEBUG("6lo sfr: error sending first fragment\n");
|
||||
@ -337,12 +350,17 @@ void gnrc_sixlowpan_frag_sfr_send(gnrc_pktsnip_t *pkt, void *ctx,
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (fbuf->sfr.frags_sent >= fbuf->sfr.window_size) {
|
||||
DEBUG("6lo sfr: frags_sent >= fbuf->sfr.window_size: don't send more\n");
|
||||
else if (!gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(fbuf)) {
|
||||
DEBUG("6lo sfr: frags_sent not within congestion window: "
|
||||
"don't send more\n");
|
||||
return;
|
||||
}
|
||||
else if (fbuf->offset < fbuf->datagram_size) {
|
||||
DEBUG("6lo sfr: sending subsequent fragment\n");
|
||||
#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)
|
||||
assert(fbuf->sfr.congure);
|
||||
assert(fbuf->sfr.congure->driver);
|
||||
#endif
|
||||
res = _send_nth_fragment(netif, fbuf, page, &tx_sync);
|
||||
if (res == 0) {
|
||||
DEBUG("6lo sfr: error sending subsequent fragment (offset = %u)\n",
|
||||
@ -358,15 +376,17 @@ void gnrc_sixlowpan_frag_sfr_send(gnrc_pktsnip_t *pkt, void *ctx,
|
||||
* the fragmentation buffer now) */
|
||||
goto error;
|
||||
}
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_sent(fbuf);
|
||||
fbuf->offset += res;
|
||||
|
||||
if ((fbuf->sfr.frags_sent < fbuf->sfr.window_size) &&
|
||||
if (gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(fbuf) &&
|
||||
(fbuf->offset < fbuf->datagram_size) &&
|
||||
!gnrc_sixlowpan_frag_fb_send(fbuf)) {
|
||||
/* the queue of the 6LoWPAN thread is full */
|
||||
error_no = ENOMEM;
|
||||
/* go back offset to not send abort on first fragment */
|
||||
fbuf->offset -= res;
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_discard(fbuf);
|
||||
goto error;
|
||||
}
|
||||
/* check if last fragment sent requested an ACK */
|
||||
@ -395,7 +415,7 @@ error:
|
||||
/* don't send abort for first fragment, the network does not know about
|
||||
* the datagram */
|
||||
if ((fbuf->offset > 0) &&
|
||||
_send_abort_frag(fbuf->pkt, (uint8_t)fbuf->tag, true, 0)) {
|
||||
_send_abort_frag(fbuf->pkt, fbuf, true, 0)) {
|
||||
/* wait for ACK before fbuf is deleted */
|
||||
_sched_abort_timeout(fbuf);
|
||||
}
|
||||
@ -468,28 +488,48 @@ int gnrc_sixlowpan_frag_sfr_forward(gnrc_pktsnip_t *pkt,
|
||||
page);
|
||||
}
|
||||
|
||||
static int _report_non_ack_req_window_sent(clist_node_t *node, void *fbuf_ptr)
|
||||
{
|
||||
_frag_desc_t *frag_desc = (_frag_desc_t *)node;
|
||||
if (!_frag_ack_req(frag_desc)) {
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_sent(fbuf_ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
{
|
||||
uint32_t now = xtimer_now_usec();
|
||||
_frag_desc_t * const head = (_frag_desc_t *)fbuf->sfr.window.next;
|
||||
_frag_desc_t *frag_desc = head;
|
||||
uint32_t now = xtimer_now_usec() / US_PER_MS;
|
||||
_frag_desc_t *frag_desc = (_frag_desc_t *)fbuf->sfr.window.next;
|
||||
uint32_t next_arq_offset = fbuf->sfr.arq_timeout;
|
||||
bool reschedule_arq_timeout = false;
|
||||
int error_no = ETIMEDOUT; /* assume time out for fbuf->pkt */
|
||||
|
||||
DEBUG("6lo sfr: ARQ timeout for datagram %u\n", fbuf->tag);
|
||||
fbuf->sfr.arq_timeout_event.msg.content.ptr = NULL;
|
||||
if (IS_ACTIVE(CONFIG_GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER)) {
|
||||
/* mock-up to emulate time having passed beyond (1us) the ARQ timeout */
|
||||
now -= (fbuf->sfr.arq_timeout * US_PER_MS) + 1;
|
||||
}
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE) && frag_desc) {
|
||||
/* report timeout to CongURE state */
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frags_timeout(fbuf);
|
||||
_shrink_window(fbuf); /* potentially shrink window */
|
||||
/* reassign frag_desc, in case window head changed */
|
||||
frag_desc = (_frag_desc_t *)fbuf->sfr.window.next;
|
||||
}
|
||||
/* copying clist_foreach because we can't work just in function context */
|
||||
_frag_desc_t * const head = frag_desc;
|
||||
if (frag_desc) {
|
||||
do {
|
||||
uint32_t diff;
|
||||
|
||||
frag_desc = (_frag_desc_t *)frag_desc->super.next;
|
||||
diff = now - frag_desc->last_sent;
|
||||
if (diff < (fbuf->sfr.arq_timeout * US_PER_MS)) {
|
||||
frag_desc = (_frag_desc_t *)frag_desc->super.super.next;
|
||||
diff = now - frag_desc->super.send_time;
|
||||
if (diff < fbuf->sfr.arq_timeout) {
|
||||
/* this fragment's last was last sent < fbuf->sfr.arq_timeout
|
||||
* ago */
|
||||
uint32_t offset = fbuf->sfr.arq_timeout - (diff / US_PER_MS);
|
||||
uint32_t offset = fbuf->sfr.arq_timeout - diff;
|
||||
|
||||
DEBUG("6lo sfr: wait for fragment %u in next reschedule\n",
|
||||
_frag_seq(frag_desc));
|
||||
@ -507,24 +547,31 @@ void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
else if (_frag_ack_req(frag_desc)) {
|
||||
/* for this fragment we requested an ACK which was not received
|
||||
* yet. Try to resend it */
|
||||
if ((frag_desc->retries++) < CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES) {
|
||||
if ((frag_desc->super.resends++) < CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES) {
|
||||
/* we have retries left for this fragment */
|
||||
DEBUG("6lo sfr: %u retries left for fragment (tag: %u, "
|
||||
"X: %i, seq: %u, frag_size: %u, offset: %u)\n",
|
||||
CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES -
|
||||
(frag_desc->retries - 1), (uint8_t)fbuf->tag,
|
||||
(frag_desc->super.resends - 1), (uint8_t)fbuf->tag,
|
||||
_frag_ack_req(frag_desc), _frag_seq(frag_desc),
|
||||
_frag_size(frag_desc), frag_desc->offset);
|
||||
if (_resend_frag(&frag_desc->super, fbuf) != 0) {
|
||||
if (_resend_frag(&frag_desc->super.super, fbuf) != 0) {
|
||||
/* _resend_frag failed due to a memory resource
|
||||
* problem */
|
||||
error_no = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
else if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
/* fragment was resent successfully, note this done in
|
||||
* the statistics */
|
||||
_stats.fragment_resends.by_timeout++;
|
||||
else {
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)) {
|
||||
/* fragment was resent successfully, report this to CongURE state
|
||||
* object */
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_sent(fbuf);
|
||||
}
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
/* fragment was resent successfully, note this done
|
||||
* in the statistics */
|
||||
_stats.fragment_resends.by_timeout++;
|
||||
}
|
||||
}
|
||||
/* fragment was resent successfully, schedule next ACK
|
||||
* timeout */
|
||||
@ -555,6 +602,10 @@ void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
_frag_seq(frag_desc));
|
||||
}
|
||||
} while (frag_desc != head);
|
||||
/* report all non-ack_req fragments in window also as sent, since even
|
||||
* the lost fragments are still in flight (even though they were
|
||||
* previously marked as timed out) */
|
||||
clist_foreach(&fbuf->sfr.window, _report_non_ack_req_window_sent, fbuf);
|
||||
}
|
||||
else {
|
||||
/* No fragments to resend, we can assume the packet was delivered
|
||||
@ -568,13 +619,13 @@ void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
}
|
||||
error:
|
||||
/* don't check return value, as we don't want to wait for an ACK again ;-) */
|
||||
_send_abort_frag(fbuf->pkt, (uint8_t)fbuf->tag, false, 0);
|
||||
_send_abort_frag(fbuf->pkt, fbuf, false, 0);
|
||||
_clean_up_fbuf(fbuf, error_no);
|
||||
}
|
||||
|
||||
void gnrc_sixlowpan_frag_sfr_inter_frame_gap(void)
|
||||
void gnrc_sixlowpan_frag_sfr_inter_frame_gap(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
{
|
||||
if (CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US > 0) {
|
||||
if (gnrc_sixlowpan_frag_sfr_congure_snd_has_inter_frame_gap()) {
|
||||
_frame_queue_t *node = (_frame_queue_t *)clist_lpop(&_frame_queue);
|
||||
|
||||
if (node != NULL) {
|
||||
@ -585,7 +636,7 @@ void gnrc_sixlowpan_frag_sfr_inter_frame_gap(void)
|
||||
clist_rpush(&_frame_queue_free, &node->super);
|
||||
}
|
||||
if (clist_lpeek(&_frame_queue) != NULL) {
|
||||
_sched_next_frame();
|
||||
_sched_next_frame(fbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -631,7 +682,7 @@ static void _clean_slate_datagram(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
evtimer_del((evtimer_t *)(&_arq_timer),
|
||||
&fbuf->sfr.arq_timeout_event.event);
|
||||
fbuf->sfr.arq_timeout_event.event.next = NULL;
|
||||
if (CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US > 0) {
|
||||
if (gnrc_sixlowpan_frag_sfr_congure_snd_has_inter_frame_gap()) {
|
||||
for (clist_node_t *node = clist_lpop(&_frame_queue);
|
||||
node != NULL; node = clist_lpop(&_frame_queue)) {
|
||||
_frame_queue_t *entry = (_frame_queue_t *)node;
|
||||
@ -652,7 +703,6 @@ static void _clean_slate_datagram(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
fbuf->offset = 0U;
|
||||
fbuf->sfr.cur_seq = 0U;
|
||||
fbuf->sfr.frags_sent = 0U;
|
||||
fbuf->sfr.window_size = CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE;
|
||||
for (clist_node_t *node = clist_lpop(&fbuf->sfr.window);
|
||||
node != NULL; node = clist_lpop(&fbuf->sfr.window)) {
|
||||
clist_rpush(&_frag_descs_free, node);
|
||||
@ -719,7 +769,9 @@ static gnrc_pktsnip_t *_build_frag_from_fbuf(gnrc_pktsnip_t *pkt,
|
||||
{
|
||||
return _build_frag_pkt(pkt->data, (uint8_t)fbuf->tag,
|
||||
((frag_size + fbuf->offset) >= fbuf->datagram_size) ||
|
||||
((fbuf->sfr.frags_sent + 1) >= fbuf->sfr.window_size),
|
||||
/* we only can send the next fragment we build here,
|
||||
* so request ACK for it */
|
||||
!gnrc_sixlowpan_frag_sfr_congure_snd_next_in_cwnd(fbuf),
|
||||
frag_size, fbuf->sfr.cur_seq);
|
||||
}
|
||||
|
||||
@ -807,14 +859,15 @@ static void _check_for_ecn(gnrc_pktsnip_t *frame)
|
||||
}
|
||||
}
|
||||
|
||||
static bool _send_frame(gnrc_pktsnip_t *frame, void *ctx, unsigned page)
|
||||
static bool _send_frame(gnrc_pktsnip_t *frame, gnrc_sixlowpan_frag_fb_t *fbuf,
|
||||
void *ctx, unsigned page)
|
||||
{
|
||||
uint32_t now;
|
||||
uint32_t if_gap = gnrc_sixlowpan_frag_sfr_congure_snd_inter_frame_gap(fbuf);
|
||||
|
||||
_check_for_ecn(frame);
|
||||
now = xtimer_now_usec();
|
||||
if ((CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US == 0) ||
|
||||
((now - _last_frame_sent) > CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US)) {
|
||||
if ((if_gap == 0) || ((now - _last_frame_sent) > if_gap)) {
|
||||
DEBUG("6lo sfr: dispatch frame to network interface\n");
|
||||
_last_frame_sent = now;
|
||||
gnrc_sixlowpan_dispatch_send(frame, ctx, page);
|
||||
@ -831,7 +884,7 @@ static bool _send_frame(gnrc_pktsnip_t *frame, void *ctx, unsigned page)
|
||||
node->datagram_tag = hdr->tag;
|
||||
node->page = page;
|
||||
clist_rpush(&_frame_queue, &node->super);
|
||||
_sched_next_frame();
|
||||
_sched_next_frame(fbuf);
|
||||
}
|
||||
return (node != NULL);
|
||||
}
|
||||
@ -851,13 +904,14 @@ static bool _send_fragment(gnrc_pktsnip_t *frag, gnrc_sixlowpan_frag_fb_t *fbuf,
|
||||
}
|
||||
frag_desc->ar_seq_fs = byteorder_ntohs(hdr->ar_seq_fs);
|
||||
frag_desc->offset = offset;
|
||||
frag_desc->retries = 0;
|
||||
clist_rpush(&fbuf->sfr.window, &frag_desc->super);
|
||||
if ((res = _send_frame(frag, NULL, page))) {
|
||||
frag_desc->super.size = 1;
|
||||
frag_desc->super.resends = 0;
|
||||
clist_rpush(&fbuf->sfr.window, &frag_desc->super.super);
|
||||
if ((res = _send_frame(frag, fbuf, NULL, page))) {
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
_stats.fragments_sent.usual++;
|
||||
}
|
||||
frag_desc->last_sent = _last_frame_sent;
|
||||
frag_desc->super.send_time = _last_frame_sent / US_PER_MS;
|
||||
fbuf->sfr.cur_seq++;
|
||||
fbuf->sfr.frags_sent++;
|
||||
}
|
||||
@ -1188,20 +1242,24 @@ static void _handle_nth_rfrag(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||
|
||||
static int _resend_failed_frag(clist_node_t *node, void *fbuf_ptr)
|
||||
{
|
||||
int res;
|
||||
int res = _resend_frag(node, fbuf_ptr);
|
||||
|
||||
if (((res = _resend_frag(node, fbuf_ptr)) == 0) &&
|
||||
IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
_stats.fragment_resends.by_nack++;
|
||||
if (res == 0) {
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
_stats.fragment_resends.by_nack++;
|
||||
}
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_sent(fbuf_ptr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _check_failed_frags(sixlowpan_sfr_ack_t *ack,
|
||||
gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
gnrc_sixlowpan_frag_fb_t *fbuf,
|
||||
uint32_t ack_recv_time)
|
||||
{
|
||||
_frag_desc_t *frag_desc;
|
||||
clist_node_t not_received = { .next = NULL };
|
||||
ztimer_now_t earliest_send = UINT32_MAX;
|
||||
|
||||
DEBUG("6lo sfr: checking which fragments to resend for datagram %u\n",
|
||||
fbuf->tag);
|
||||
@ -1211,34 +1269,59 @@ static void _check_failed_frags(sixlowpan_sfr_ack_t *ack,
|
||||
uint8_t seq;
|
||||
|
||||
seq = _frag_seq(frag_desc);
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE) &&
|
||||
(earliest_send > frag_desc->super.send_time)) {
|
||||
earliest_send = frag_desc->super.send_time;
|
||||
}
|
||||
if (bf_isset(ack->bitmap, seq)) {
|
||||
DEBUG("6lo sfr: fragment %u (offset: %u, frag_size: %u) "
|
||||
"for datagram %u was received\n", seq,
|
||||
frag_desc->offset, _frag_size(frag_desc), fbuf->tag);
|
||||
fbuf->sfr.frags_sent--;
|
||||
clist_rpush(&_frag_descs_free, &frag_desc->super);
|
||||
clist_rpush(&_frag_descs_free, &frag_desc->super.super);
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)) {
|
||||
congure_snd_ack_t ack = {
|
||||
.recv_time = ack_recv_time,
|
||||
.id = seq,
|
||||
.clean = 1U,
|
||||
};
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frag_acked(
|
||||
fbuf, &frag_desc->super, &ack
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo sfr: fragment %u (offset: %u, frag_size: %u) "
|
||||
"for datagram %u was not received\n", seq,
|
||||
frag_desc->offset, _frag_size(frag_desc), fbuf->tag);
|
||||
if ((frag_desc->retries++) < CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES) {
|
||||
if ((frag_desc->super.resends++) < CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES) {
|
||||
DEBUG("6lo sfr: %u retries left\n",
|
||||
CONFIG_GNRC_SIXLOWPAN_SFR_FRAG_RETRIES -
|
||||
(frag_desc->retries - 1));
|
||||
(frag_desc->super.resends - 1));
|
||||
/* put fragment in "not received" list */
|
||||
clist_rpush(¬_received, &frag_desc->super);
|
||||
clist_rpush(¬_received, &frag_desc->super.super);
|
||||
frag_desc->ar_seq_fs &= ~(SIXLOWPAN_SFR_ACK_REQ << 8U);
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo sfr: no more retries for fragment %u\n", seq);
|
||||
clist_rpush(&_frag_descs_free, &frag_desc->super);
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE) &&
|
||||
IS_ACTIVE(CONFIG_GNRC_SIXLOWPAN_SFR_USE_ECN) &&
|
||||
sixlowpan_sfr_ecn(&ack->base)) {
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_ecn(
|
||||
fbuf, earliest_send
|
||||
);
|
||||
}
|
||||
clist_rpush(&_frag_descs_free, &frag_desc->super.super);
|
||||
/* retry to resend whole datagram */
|
||||
_retry_datagram(fbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE) &&
|
||||
sixlowpan_sfr_ecn(&ack->base)) {
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_ecn(fbuf, earliest_send);
|
||||
}
|
||||
/* all fragments were received of the current window were received and
|
||||
* the datagram was transmitted completely */
|
||||
if ((clist_lpeek(¬_received) == NULL) &&
|
||||
@ -1248,7 +1331,12 @@ static void _check_failed_frags(sixlowpan_sfr_ack_t *ack,
|
||||
}
|
||||
/* at least one fragment was not received */
|
||||
else {
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_report_frags_lost(
|
||||
fbuf,
|
||||
(congure_snd_msg_t *)¬_received
|
||||
);
|
||||
fbuf->sfr.window = not_received;
|
||||
_shrink_window(fbuf);
|
||||
assert(fbuf->sfr.frags_sent == clist_count(&fbuf->sfr.window));
|
||||
/* use _resend_failed_frag here instead of loop above, so
|
||||
* _resend_frag can know if the fragment is the last in the window by
|
||||
@ -1257,7 +1345,7 @@ static void _check_failed_frags(sixlowpan_sfr_ack_t *ack,
|
||||
/* XXX: it is unlikely that allocating an abort RFRAG will be
|
||||
* successful since the resources missing to cause the abort are
|
||||
* still in use, but we should at least try */
|
||||
if (_send_abort_frag(fbuf->pkt, (uint8_t)fbuf->tag, true, 0)) {
|
||||
if (_send_abort_frag(fbuf->pkt, fbuf, true, 0)) {
|
||||
/* wait for ACK before fbuf is deleted */
|
||||
_sched_abort_timeout(fbuf);
|
||||
}
|
||||
@ -1268,7 +1356,7 @@ static void _check_failed_frags(sixlowpan_sfr_ack_t *ack,
|
||||
_clean_up_fbuf(fbuf, ENOMEM);
|
||||
}
|
||||
}
|
||||
if ((fbuf->sfr.frags_sent < fbuf->sfr.window_size) &&
|
||||
if (gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(fbuf) &&
|
||||
(fbuf->offset < fbuf->datagram_size)) {
|
||||
DEBUG("6lo sfr: trigger send of further fragments of datagram %u\n",
|
||||
fbuf->tag);
|
||||
@ -1311,6 +1399,7 @@ static void _clean_up_fbuf(gnrc_sixlowpan_frag_fb_t *fbuf, int error)
|
||||
DEBUG("6lo sfr: removing fragmentation buffer entry for datagram %u\n",
|
||||
fbuf->tag);
|
||||
_clean_slate_datagram(fbuf);
|
||||
gnrc_sixlowpan_frag_sfr_congure_snd_destroy(fbuf);
|
||||
gnrc_pktbuf_release_error(fbuf->pkt, error);
|
||||
fbuf->pkt = NULL;
|
||||
}
|
||||
@ -1347,7 +1436,6 @@ static uint16_t _send_1st_fragment(gnrc_netif_t *netif,
|
||||
fbuf->datagram_size++;
|
||||
}
|
||||
fbuf->sfr.arq_timeout = CONFIG_GNRC_SIXLOWPAN_SFR_OPT_ARQ_TIMEOUT_MS;
|
||||
fbuf->sfr.window_size = CONFIG_GNRC_SIXLOWPAN_SFR_OPT_WIN_SIZE;
|
||||
|
||||
frag = _build_frag_from_fbuf(pkt, fbuf, frag_size);
|
||||
if (frag == NULL) {
|
||||
@ -1425,15 +1513,16 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *netif,
|
||||
return local_offset;
|
||||
}
|
||||
|
||||
static bool _send_abort_frag(gnrc_pktsnip_t *pkt, uint8_t tag, bool req_ack,
|
||||
unsigned page)
|
||||
static bool _send_abort_frag(gnrc_pktsnip_t *pkt,
|
||||
gnrc_sixlowpan_frag_fb_t *fbuf,
|
||||
bool req_ack, unsigned page)
|
||||
{
|
||||
gnrc_pktsnip_t *frag;
|
||||
|
||||
frag = _build_frag_pkt(pkt->data, tag, req_ack, 0, 0);
|
||||
frag = _build_frag_pkt(pkt->data, fbuf->tag, req_ack, 0, 0);
|
||||
if (frag != NULL) {
|
||||
sixlowpan_sfr_rfrag_set_offset(frag->next->data, 0);
|
||||
_send_frame(frag, NULL, page);
|
||||
_send_frame(frag, fbuf, NULL, page);
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
_stats.fragments_sent.aborts++;
|
||||
}
|
||||
@ -1442,6 +1531,37 @@ static bool _send_abort_frag(gnrc_pktsnip_t *pkt, uint8_t tag, bool req_ack,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _shrink_window(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
{
|
||||
if (!IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_CONGURE)) {
|
||||
/* window does not shrink without congure */
|
||||
return;
|
||||
}
|
||||
if (!gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(fbuf)) {
|
||||
/* we are beyond the congestion window, so shrink it to the new size */
|
||||
clist_node_t new_window = { .next = NULL };
|
||||
_frag_desc_t *last;
|
||||
|
||||
fbuf->sfr.frags_sent = 0; /* temporarily reset fragments sent to count them again*/
|
||||
/* move all fragments within congestion window into new, temporary list */
|
||||
while (gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(fbuf)) {
|
||||
clist_rpush(&new_window, clist_lpop(&fbuf->sfr.window));
|
||||
fbuf->sfr.frags_sent++;
|
||||
}
|
||||
/* free all remaining fragments from old congestion window that did not fit into
|
||||
* the shrunk window */
|
||||
for (clist_node_t *node = clist_lpop(&fbuf->sfr.window);
|
||||
node != NULL; node = clist_lpop(&fbuf->sfr.window)) {
|
||||
clist_rpush(&_frag_descs_free, node);
|
||||
}
|
||||
/* the temporary list is now the new, shrunk window */
|
||||
fbuf->sfr.window.next = new_window.next;
|
||||
/* recalculate offset for fragmentation header field */
|
||||
last = (_frag_desc_t *)clist_rpeek(&fbuf->sfr.window);
|
||||
fbuf->offset = last->offset + _frag_size(last);
|
||||
}
|
||||
}
|
||||
|
||||
static int _resend_frag(clist_node_t *node, void *fbuf_ptr)
|
||||
{
|
||||
_frag_desc_t *frag_desc = (_frag_desc_t *)node;
|
||||
@ -1459,7 +1579,7 @@ static int _resend_frag(clist_node_t *node, void *fbuf_ptr)
|
||||
}
|
||||
hdr = frag->next->data;
|
||||
/* is last fragment in window */
|
||||
if (((fbuf->sfr.frags_sent >= fbuf->sfr.window_size) ||
|
||||
if ((!gnrc_sixlowpan_frag_sfr_congure_snd_in_cwnd(fbuf) ||
|
||||
(fbuf->offset >= fbuf->datagram_size)) &&
|
||||
(clist_node_t *)frag_desc == clist_rpeek(&fbuf->sfr.window)) {
|
||||
frag_desc->ar_seq_fs |= (SIXLOWPAN_SFR_ACK_REQ << 8U);
|
||||
@ -1480,14 +1600,14 @@ static int _resend_frag(clist_node_t *node, void *fbuf_ptr)
|
||||
/* copy remaining packet snips */
|
||||
_copy_pkt_to_frag(data, pkt, frag_size, cur_frag_size);
|
||||
DEBUG("6lo sfr: resending fragment (retry: %u, tag: %u, X: %i, seq: %u, "
|
||||
"frag_size: %u, %s: %u)\n", frag_desc->retries,
|
||||
"frag_size: %u, %s: %u)\n", frag_desc->super.resends,
|
||||
hdr->base.tag, sixlowpan_sfr_rfrag_ack_req(hdr),
|
||||
sixlowpan_sfr_rfrag_get_seq(hdr),
|
||||
sixlowpan_sfr_rfrag_get_frag_size(hdr),
|
||||
(sixlowpan_sfr_rfrag_get_seq(hdr)) ? "offset" : "datagram_size",
|
||||
sixlowpan_sfr_rfrag_get_offset(hdr));
|
||||
if (_send_frame(frag, NULL, 0)) {
|
||||
frag_desc->last_sent = _last_frame_sent;
|
||||
if (_send_frame(frag, fbuf, NULL, 0)) {
|
||||
frag_desc->super.send_time = _last_frame_sent / US_PER_MS;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
@ -1547,43 +1667,53 @@ static void _send_ack(gnrc_netif_t *netif, const uint8_t *dst, uint8_t dst_len,
|
||||
gnrc_netif_addr_to_str(dst, dst_len, addr_str),
|
||||
hdr->tag, bitmap[0], bitmap[1], bitmap[2], bitmap[3]);
|
||||
if (ack != NULL) {
|
||||
_send_frame(ack, NULL, 0);
|
||||
_send_frame(ack, NULL, NULL, 0);
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo sfr: unable to build ACK for sending\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _sched_next_frame(void)
|
||||
static void _sched_next_frame(gnrc_sixlowpan_frag_fb_t *fbuf)
|
||||
{
|
||||
if (CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US > 0) {
|
||||
int state = irq_disable(); /* make timer check atomic */
|
||||
bool already_set = xtimer_is_set(&_if_gap_timer);
|
||||
if (!gnrc_sixlowpan_frag_sfr_congure_snd_has_inter_frame_gap()) {
|
||||
return;
|
||||
}
|
||||
int state = irq_disable(); /* make timer check atomic */
|
||||
bool already_set = xtimer_is_set(&_if_gap_timer);
|
||||
|
||||
irq_restore(state);
|
||||
if (!already_set) {
|
||||
uint32_t last_sent_since = (_last_frame_sent - xtimer_now_usec());
|
||||
irq_restore(state);
|
||||
if (already_set) {
|
||||
DEBUG("6lo sfr: inter-frame timer was already set\n");
|
||||
return;
|
||||
}
|
||||
uint32_t last_sent_since = (_last_frame_sent - xtimer_now_usec());
|
||||
uint32_t if_gap = gnrc_sixlowpan_frag_sfr_congure_snd_inter_frame_gap(fbuf);
|
||||
|
||||
if (last_sent_since <= CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US) {
|
||||
uint32_t offset = CONFIG_GNRC_SIXLOWPAN_SFR_INTER_FRAME_GAP_US -
|
||||
last_sent_since;
|
||||
DEBUG("6lo sfr: arming inter-frame timer in %" PRIu32 " us\n",
|
||||
last_sent_since);
|
||||
xtimer_set_msg(&_if_gap_timer, offset, &_if_gap_msg, _getpid());
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo sfr: send frame immediately\n");
|
||||
gnrc_sixlowpan_frag_sfr_inter_frame_gap();
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo sfr: inter-frame timer was already set\n");
|
||||
}
|
||||
if (last_sent_since <= if_gap) {
|
||||
uint32_t offset = if_gap - last_sent_since;
|
||||
DEBUG("6lo sfr: arming inter-frame timer in %" PRIu32 " us\n",
|
||||
last_sent_since);
|
||||
_if_gap_msg.content.ptr = fbuf;
|
||||
xtimer_set_msg(&_if_gap_timer, offset, &_if_gap_msg, _getpid());
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo sfr: send frame immediately\n");
|
||||
/* there is no risk of infinite recursion due to the call of `_sched_next_frame` since
|
||||
* we only get here when (_last_frame_sent - now) > if_gap.
|
||||
* Since gnrc_sixlowpan_frag_sfr_inter_frame_gap updates _last_frame_sent when the list is
|
||||
* empty and only calls _sched_next_frame() when the list is still not empty after that this
|
||||
* can not be the case if we came from there (except for misconfigured if_gap). */
|
||||
gnrc_sixlowpan_frag_sfr_inter_frame_gap(fbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void _sched_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf, uint32_t offset)
|
||||
{
|
||||
if (IS_ACTIVE(CONFIG_GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER)) {
|
||||
/* mock does not need to be scheduled */
|
||||
return;
|
||||
}
|
||||
if (fbuf->sfr.arq_timeout_event.msg.content.ptr != NULL) {
|
||||
DEBUG("6lo sfr: ARQ timeout for datagram %u already scheduled\n",
|
||||
(uint8_t)fbuf->tag);
|
||||
@ -1626,6 +1756,7 @@ static void _handle_ack(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||
{
|
||||
gnrc_sixlowpan_frag_vrb_t *vrbe;
|
||||
sixlowpan_sfr_ack_t *hdr = pkt->data;
|
||||
uint32_t recv_time = xtimer_now_usec();
|
||||
|
||||
(void)page;
|
||||
DEBUG("6lo sfr: received ACK for datagram (%s, %02x): %02X%02X%02X%02X\n",
|
||||
@ -1653,7 +1784,7 @@ static void _handle_ack(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||
if (CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_DEL_TIMER > 0) {
|
||||
/* garbage-collect entry after CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_DEL_TIMER
|
||||
* microseconds */
|
||||
vrbe->super.arrival = xtimer_now_usec() -
|
||||
vrbe->super.arrival = recv_time -
|
||||
(CONFIG_GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US -
|
||||
CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_DEL_TIMER);
|
||||
}
|
||||
@ -1662,7 +1793,7 @@ static void _handle_ack(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||
}
|
||||
}
|
||||
else {
|
||||
vrbe->super.arrival = xtimer_now_usec();
|
||||
vrbe->super.arrival = recv_time;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1685,7 +1816,7 @@ static void _handle_ack(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||
else {
|
||||
/* Check and resent failed fragments within the current window
|
||||
*/
|
||||
_check_failed_frags(hdr, fbuf);
|
||||
_check_failed_frags(hdr, fbuf, recv_time / US_PER_MS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1732,7 +1863,7 @@ static int _forward_rfrag(gnrc_pktsnip_t *pkt, _generic_rb_entry_t *entry,
|
||||
hdr->base.tag = entry->entry.vrb->out_tag;
|
||||
gnrc_netif_hdr_set_netif(new->data, entry->entry.vrb->out_netif);
|
||||
new->next = pkt;
|
||||
_send_frame(new, NULL, page);
|
||||
_send_frame(new, NULL, NULL, page);
|
||||
if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) {
|
||||
_stats.fragments_sent.forwarded++;
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ static void *_event_loop(void *args)
|
||||
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();
|
||||
gnrc_sixlowpan_frag_sfr_inter_frame_gap(msg.content.ptr);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
43
tests/gnrc_sixlowpan_frag_sfr_congure/Makefile
Normal file
43
tests/gnrc_sixlowpan_frag_sfr_congure/Makefile
Normal file
@ -0,0 +1,43 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += congure_mock
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_sixlowpan_frag_sfr
|
||||
USEMODULE += gnrc_sixlowpan_frag_sfr_congure
|
||||
USEMODULE += gnrc_sixlowpan_iphc
|
||||
USEMODULE += gnrc_ipv6_nib
|
||||
USEMODULE += gnrc_netif
|
||||
USEMODULE += embunit
|
||||
USEMODULE += netdev_ieee802154
|
||||
USEMODULE += netdev_test
|
||||
USEMODULE += ztimer_msec ztimer_usec
|
||||
|
||||
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
|
||||
ifndef CONFIG_GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER
|
||||
# mock ARQ timer
|
||||
CFLAGS += -DCONFIG_GNRC_SIXLOWPAN_SFR_MOCK_ARQ_TIMER=1U
|
||||
endif
|
51
tests/gnrc_sixlowpan_frag_sfr_congure/Makefile.ci
Normal file
51
tests/gnrc_sixlowpan_frag_sfr_congure/Makefile.ci
Normal file
@ -0,0 +1,51 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-mega2560 \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega1284p \
|
||||
atmega328p \
|
||||
atmega328p-xplained-mini \
|
||||
atxmega-a1u-xpro \
|
||||
atxmega-a3bu-xplained \
|
||||
blackpill \
|
||||
blackpill-128kib \
|
||||
bluepill \
|
||||
bluepill-128kib \
|
||||
bluepill-stm32f030c8 \
|
||||
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 \
|
||||
slstk3400a \
|
||||
stk3200 \
|
||||
stm32f030f4-demo \
|
||||
stm32f0discovery \
|
||||
stm32g0316-disco \
|
||||
stm32l0538-disco \
|
||||
stm32mp157c-dk2 \
|
||||
telosb \
|
||||
waspmote-pro \
|
||||
z1 \
|
||||
zigduino \
|
||||
#
|
8
tests/gnrc_sixlowpan_frag_sfr_congure/app.config
Normal file
8
tests/gnrc_sixlowpan_frag_sfr_congure/app.config
Normal file
@ -0,0 +1,8 @@
|
||||
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_MOCK_ARQ_TIMER=y
|
50
tests/gnrc_sixlowpan_frag_sfr_congure/common.h
Normal file
50
tests/gnrc_sixlowpan_frag_sfr_congure/common.h
Normal 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 */
|
||||
/** @} */
|
1074
tests/gnrc_sixlowpan_frag_sfr_congure/main.c
Normal file
1074
tests/gnrc_sixlowpan_frag_sfr_congure/main.c
Normal file
File diff suppressed because it is too large
Load Diff
123
tests/gnrc_sixlowpan_frag_sfr_congure/mockup_netif.c
Normal file
123
tests/gnrc_sixlowpan_frag_sfr_congure/mockup_netif.c
Normal 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_PDU_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;
|
||||
}
|
||||
|
||||
/** @} */
|
15
tests/gnrc_sixlowpan_frag_sfr_congure/tests/01-run.py
Executable file
15
tests/gnrc_sixlowpan_frag_sfr_congure/tests/01-run.py
Executable file
@ -0,0 +1,15 @@
|
||||
#!/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_check_unittests
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run_check_unittests())
|
Loading…
Reference in New Issue
Block a user