gnrc_sixlowpan_frag: move private RB functions to RB module
This commit is contained in:
parent
68aae9c848
commit
ec495528fe
@ -213,6 +213,9 @@ endif
|
|||||||
ifneq (,$(filter gnrc_sixlowpan_frag,$(USEMODULE)))
|
ifneq (,$(filter gnrc_sixlowpan_frag,$(USEMODULE)))
|
||||||
USEMODULE += gnrc_sixlowpan
|
USEMODULE += gnrc_sixlowpan
|
||||||
USEMODULE += gnrc_sixlowpan_frag_rb
|
USEMODULE += gnrc_sixlowpan_frag_rb
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter gnrc_sixlowpan_frag_rb,$(USEMODULE)))
|
||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@ -21,11 +21,25 @@
|
|||||||
#define NET_GNRC_SIXLOWPAN_FRAG_RB_H
|
#define NET_GNRC_SIXLOWPAN_FRAG_RB_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "net/gnrc/netif/hdr.h"
|
||||||
|
#include "net/gnrc/pkt.h"
|
||||||
|
|
||||||
|
#include "net/gnrc/sixlowpan/config.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Legacy defines
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define RBUF_SIZE (GNRC_SIXLOWPAN_FRAG_RBUF_SIZE)
|
||||||
|
#define RBUF_TIMEOUT (GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fragment intervals to identify limits of fragments and duplicates.
|
* @brief Fragment intervals to identify limits of fragments and duplicates.
|
||||||
*
|
*
|
||||||
@ -88,6 +102,74 @@ typedef struct {
|
|||||||
gnrc_pktsnip_t *pkt;
|
gnrc_pktsnip_t *pkt;
|
||||||
} gnrc_sixlowpan_rbuf_t;
|
} gnrc_sixlowpan_rbuf_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new fragment to the reassembly buffer. If the packet is
|
||||||
|
* complete, dispatch the packet with the transmit information of
|
||||||
|
* the last fragment.
|
||||||
|
*
|
||||||
|
* @param[in] netif_hdr The interface header of the fragment, with
|
||||||
|
* gnrc_netif_hdr_t::if_pid and its source and
|
||||||
|
* destination address set.
|
||||||
|
* @param[in] frag The fragment to add.
|
||||||
|
* @param[in] offset The fragment's offset.
|
||||||
|
* @param[in] page Current 6Lo dispatch parsing page.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *frag,
|
||||||
|
size_t offset, unsigned page);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks timeouts and removes entries if necessary
|
||||||
|
*/
|
||||||
|
void rbuf_gc(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unsets a reassembly buffer entry (but does not free
|
||||||
|
* rbuf_t::super::pkt)
|
||||||
|
*
|
||||||
|
* This functions sets rbuf_t::super::pkt to NULL and removes all rbuf::ints.
|
||||||
|
*
|
||||||
|
* @param[in] rbuf A reassembly buffer entry
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
void rbuf_rm(gnrc_sixlowpan_rbuf_t *rbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a reassembly buffer entry is unset
|
||||||
|
*
|
||||||
|
* @param[in] rbuf A reassembly buffer entry
|
||||||
|
*
|
||||||
|
* @return true, if @p rbuf is empty (i.e. rbuf->super.pkt is NULL).
|
||||||
|
* @return false, if @p rbuf is in use.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
static inline bool rbuf_entry_empty(const gnrc_sixlowpan_rbuf_t *rbuf) {
|
||||||
|
return (rbuf->pkt == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(TEST_SUITES) || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* @brief Resets the packet buffer to a clean state
|
||||||
|
*
|
||||||
|
* @note Only available when @ref TEST_SUITES is defined
|
||||||
|
*/
|
||||||
|
void rbuf_reset(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a pointer to the array representing the reassembly buffer.
|
||||||
|
*
|
||||||
|
* @note Only available when @ref TEST_SUITES is defined
|
||||||
|
*
|
||||||
|
* @return The first element of the reassembly buffer. `const`, so that write
|
||||||
|
* access is immediately spotted at compile time of tests. The `const`
|
||||||
|
* qualifier may however be discarded if required by the tests.
|
||||||
|
*/
|
||||||
|
const gnrc_sixlowpan_rbuf_t *rbuf_array(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Remove base entry
|
* @brief Remove base entry
|
||||||
*
|
*
|
||||||
|
|||||||
@ -21,13 +21,12 @@
|
|||||||
#include "net/gnrc/netapi.h"
|
#include "net/gnrc/netapi.h"
|
||||||
#include "net/gnrc/netif/hdr.h"
|
#include "net/gnrc/netif/hdr.h"
|
||||||
#include "net/gnrc/sixlowpan/frag.h"
|
#include "net/gnrc/sixlowpan/frag.h"
|
||||||
|
#include "net/gnrc/sixlowpan/frag/rb.h"
|
||||||
#include "net/gnrc/sixlowpan/internal.h"
|
#include "net/gnrc/sixlowpan/internal.h"
|
||||||
#include "net/gnrc/netif.h"
|
#include "net/gnrc/netif.h"
|
||||||
#include "net/sixlowpan.h"
|
#include "net/sixlowpan.h"
|
||||||
#include "utlist.h"
|
#include "utlist.h"
|
||||||
|
|
||||||
#include "rbuf.h"
|
|
||||||
|
|
||||||
#define ENABLE_DEBUG (0)
|
#define ENABLE_DEBUG (0)
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
|||||||
@ -13,18 +13,428 @@
|
|||||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "net/ieee802154.h"
|
#include "net/ieee802154.h"
|
||||||
#include "net/gnrc/netif/hdr.h"
|
#include "net/ipv6.h"
|
||||||
#include "net/gnrc/pkt.h"
|
#include "net/ipv6/hdr.h"
|
||||||
|
#include "net/gnrc.h"
|
||||||
#include "net/gnrc/sixlowpan.h"
|
#include "net/gnrc/sixlowpan.h"
|
||||||
|
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||||
|
#include "net/gnrc/sixlowpan/frag/vrb.h"
|
||||||
|
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||||
|
#include "net/sixlowpan.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
#include "utlist.h"
|
||||||
|
|
||||||
#include "net/gnrc/sixlowpan/frag/rb.h"
|
#include "net/gnrc/sixlowpan/frag/rb.h"
|
||||||
|
|
||||||
#include "rbuf.h"
|
|
||||||
|
|
||||||
#define ENABLE_DEBUG (0)
|
#define ENABLE_DEBUG (0)
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
/* estimated fragment payload size to determinate RBUF_INT_SIZE, default to
|
||||||
|
* MAC payload size - fragment header. */
|
||||||
|
#ifndef GNRC_SIXLOWPAN_FRAG_SIZE
|
||||||
|
/* assuming 64-bit source/destination address, source PAN ID omitted */
|
||||||
|
#define GNRC_SIXLOWPAN_FRAG_SIZE (104 - 5)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RBUF_INT_SIZE
|
||||||
|
/* same as ((int) ceil((double) N / D)) */
|
||||||
|
#define DIV_CEIL(N, D) (((N) + (D) - 1) / (D))
|
||||||
|
#define RBUF_INT_SIZE (DIV_CEIL(IPV6_MIN_MTU, GNRC_SIXLOWPAN_FRAG_SIZE) * RBUF_SIZE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static gnrc_sixlowpan_rbuf_int_t rbuf_int[RBUF_INT_SIZE];
|
||||||
|
|
||||||
|
static gnrc_sixlowpan_rbuf_t rbuf[RBUF_SIZE];
|
||||||
|
|
||||||
|
static char l2addr_str[3 * IEEE802154_LONG_ADDRESS_LEN];
|
||||||
|
|
||||||
|
static xtimer_t _gc_timer;
|
||||||
|
static msg_t _gc_timer_msg = { .type = GNRC_SIXLOWPAN_MSG_FRAG_GC_RBUF };
|
||||||
|
|
||||||
|
/* ------------------------------------
|
||||||
|
* internal function definitions
|
||||||
|
* ------------------------------------*/
|
||||||
|
/* checks whether start and end overlaps, but not identical to, given interval i */
|
||||||
|
static inline bool _rbuf_int_overlap_partially(gnrc_sixlowpan_rbuf_int_t *i,
|
||||||
|
uint16_t start, uint16_t end);
|
||||||
|
/* gets a free entry from interval buffer */
|
||||||
|
static gnrc_sixlowpan_rbuf_int_t *_rbuf_int_get_free(void);
|
||||||
|
/* update interval buffer of entry */
|
||||||
|
static bool _rbuf_update_ints(gnrc_sixlowpan_rbuf_base_t *entry,
|
||||||
|
uint16_t offset, size_t frag_size);
|
||||||
|
/* gets an entry identified by its tupel */
|
||||||
|
static gnrc_sixlowpan_rbuf_t *_rbuf_get(const void *src, size_t src_len,
|
||||||
|
const void *dst, size_t dst_len,
|
||||||
|
size_t size, uint16_t tag,
|
||||||
|
unsigned page);
|
||||||
|
/* internal add to repeat add when fragments overlapped */
|
||||||
|
static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||||
|
size_t offset, unsigned page);
|
||||||
|
|
||||||
|
/* status codes for _rbuf_add() */
|
||||||
|
enum {
|
||||||
|
RBUF_ADD_SUCCESS,
|
||||||
|
RBUF_ADD_ERROR,
|
||||||
|
RBUF_ADD_REPEAT,
|
||||||
|
RBUF_ADD_DUPLICATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_STATS
|
||||||
|
static gnrc_sixlowpan_frag_stats_t _stats;
|
||||||
|
|
||||||
|
gnrc_sixlowpan_frag_stats_t *gnrc_sixlowpan_frag_stats_get(void)
|
||||||
|
{
|
||||||
|
return &_stats;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int _check_fragments(gnrc_sixlowpan_rbuf_base_t *entry,
|
||||||
|
size_t frag_size, size_t offset)
|
||||||
|
{
|
||||||
|
gnrc_sixlowpan_rbuf_int_t *ptr = entry->ints;
|
||||||
|
|
||||||
|
/* If the fragment overlaps another fragment and differs in either the size
|
||||||
|
* or the offset of the overlapped fragment, discards the datagram
|
||||||
|
* https://tools.ietf.org/html/rfc4944#section-5.3 */
|
||||||
|
while (ptr != NULL) {
|
||||||
|
if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) {
|
||||||
|
|
||||||
|
/* "A fresh reassembly may be commenced with the most recently
|
||||||
|
* received link fragment"
|
||||||
|
* https://tools.ietf.org/html/rfc4944#section-5.3 */
|
||||||
|
return RBUF_ADD_REPEAT;
|
||||||
|
}
|
||||||
|
/* End was already checked in overlap check */
|
||||||
|
if (ptr->start == offset) {
|
||||||
|
DEBUG("6lo rbuf: fragment already in reassembly buffer");
|
||||||
|
return RBUF_ADD_DUPLICATE;
|
||||||
|
}
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
return RBUF_ADD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||||
|
size_t offset, unsigned page)
|
||||||
|
{
|
||||||
|
if (_rbuf_add(netif_hdr, pkt, offset, page) == RBUF_ADD_REPEAT) {
|
||||||
|
_rbuf_add(netif_hdr, pkt, offset, page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
||||||
|
size_t offset, unsigned page)
|
||||||
|
{
|
||||||
|
gnrc_sixlowpan_rbuf_t *entry;
|
||||||
|
sixlowpan_frag_n_t *frag = pkt->data;
|
||||||
|
uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t);
|
||||||
|
size_t frag_size;
|
||||||
|
|
||||||
|
/* check if provided offset is the same as in fragment */
|
||||||
|
assert(((((frag->disp_size.u8[0] & SIXLOWPAN_FRAG_DISP_MASK) ==
|
||||||
|
SIXLOWPAN_FRAG_1_DISP)) && (offset == 0)) ||
|
||||||
|
((((frag->disp_size.u8[0] & SIXLOWPAN_FRAG_DISP_MASK) ==
|
||||||
|
SIXLOWPAN_FRAG_N_DISP)) && (offset == (frag->offset * 8U))));
|
||||||
|
rbuf_gc();
|
||||||
|
entry = _rbuf_get(gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len,
|
||||||
|
gnrc_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len,
|
||||||
|
byteorder_ntohs(frag->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK,
|
||||||
|
byteorder_ntohs(frag->tag), page);
|
||||||
|
|
||||||
|
if (entry == NULL) {
|
||||||
|
DEBUG("6lo rbuf: reassembly buffer full.\n");
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
return RBUF_ADD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dispatches in the first fragment are ignored */
|
||||||
|
if (offset == 0) {
|
||||||
|
frag_size = pkt->size - sizeof(sixlowpan_frag_t);
|
||||||
|
if (data[0] == SIXLOWPAN_UNCOMP) {
|
||||||
|
frag_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frag_size = pkt->size - sizeof(sixlowpan_frag_n_t);
|
||||||
|
data++; /* FRAGN header is one byte longer (offset) */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset + frag_size) > entry->super.datagram_size) {
|
||||||
|
DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n");
|
||||||
|
gnrc_pktbuf_release(entry->pkt);
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
rbuf_rm(entry);
|
||||||
|
return RBUF_ADD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_check_fragments(&entry->super, frag_size, offset)) {
|
||||||
|
case RBUF_ADD_REPEAT:
|
||||||
|
DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n");
|
||||||
|
gnrc_pktbuf_release(entry->pkt);
|
||||||
|
rbuf_rm(entry);
|
||||||
|
return RBUF_ADD_REPEAT;
|
||||||
|
case RBUF_ADD_DUPLICATE:
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
return RBUF_ADD_SUCCESS;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rbuf_update_ints(&entry->super, offset, frag_size)) {
|
||||||
|
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)) {
|
||||||
|
gnrc_pktsnip_t *frag_hdr = gnrc_pktbuf_mark(pkt,
|
||||||
|
sizeof(sixlowpan_frag_t), GNRC_NETTYPE_SIXLOWPAN);
|
||||||
|
if (frag_hdr == NULL) {
|
||||||
|
gnrc_pktbuf_release(entry->pkt);
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
rbuf_rm(entry);
|
||||||
|
return RBUF_ADD_ERROR;
|
||||||
|
}
|
||||||
|
gnrc_sixlowpan_iphc_recv(pkt, entry, 0);
|
||||||
|
return RBUF_ADD_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (data[0] == SIXLOWPAN_UNCOMP) {
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(((uint8_t *)entry->pkt->data) + offset, data,
|
||||||
|
frag_size);
|
||||||
|
}
|
||||||
|
gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(entry, netif_hdr);
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
return RBUF_ADD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _rbuf_int_overlap_partially(gnrc_sixlowpan_rbuf_int_t *i,
|
||||||
|
uint16_t start, uint16_t end)
|
||||||
|
{
|
||||||
|
/* start and ends are both inclusive, so using <= for both */
|
||||||
|
return ((i->start <= end) && (start <= i->end)) && /* overlaps */
|
||||||
|
((start != i->start) || (end != i->end)); /* not identical */
|
||||||
|
}
|
||||||
|
|
||||||
|
static gnrc_sixlowpan_rbuf_int_t *_rbuf_int_get_free(void)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < RBUF_INT_SIZE; i++) {
|
||||||
|
if (rbuf_int[i].end == 0) { /* start must be smaller than end anyways*/
|
||||||
|
return rbuf_int + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rbuf_rm(gnrc_sixlowpan_rbuf_t *entry)
|
||||||
|
{
|
||||||
|
gnrc_sixlowpan_frag_rbuf_base_rm(&entry->super);
|
||||||
|
entry->pkt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _rbuf_update_ints(gnrc_sixlowpan_rbuf_base_t *entry,
|
||||||
|
uint16_t offset, size_t frag_size)
|
||||||
|
{
|
||||||
|
gnrc_sixlowpan_rbuf_int_t *new;
|
||||||
|
uint16_t end = (uint16_t)(offset + frag_size - 1);
|
||||||
|
|
||||||
|
new = _rbuf_int_get_free();
|
||||||
|
|
||||||
|
if (new == NULL) {
|
||||||
|
DEBUG("6lo rfrag: no space left in rbuf interval buffer.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->start = offset;
|
||||||
|
new->end = end;
|
||||||
|
|
||||||
|
DEBUG("6lo rfrag: add interval (%" PRIu16 ", %" PRIu16 ") to entry (%s, ",
|
||||||
|
new->start, new->end, gnrc_netif_addr_to_str(entry->src,
|
||||||
|
entry->src_len,
|
||||||
|
l2addr_str));
|
||||||
|
DEBUG("%s, %u, %u)\n", gnrc_netif_addr_to_str(entry->dst,
|
||||||
|
entry->dst_len,
|
||||||
|
l2addr_str),
|
||||||
|
entry->datagram_size, entry->tag);
|
||||||
|
|
||||||
|
LL_PREPEND(entry->ints, new);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rbuf_gc(void)
|
||||||
|
{
|
||||||
|
uint32_t now_usec = xtimer_now_usec();
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < RBUF_SIZE; i++) {
|
||||||
|
/* since pkt occupies pktbuf, aggressivly collect garbage */
|
||||||
|
if (!rbuf_entry_empty(&rbuf[i]) &&
|
||||||
|
((now_usec - rbuf[i].super.arrival) > RBUF_TIMEOUT)) {
|
||||||
|
DEBUG("6lo rfrag: entry (%s, ",
|
||||||
|
gnrc_netif_addr_to_str(rbuf[i].super.src,
|
||||||
|
rbuf[i].super.src_len,
|
||||||
|
l2addr_str));
|
||||||
|
DEBUG("%s, %u, %u) timed out\n",
|
||||||
|
gnrc_netif_addr_to_str(rbuf[i].super.dst,
|
||||||
|
rbuf[i].super.dst_len,
|
||||||
|
l2addr_str),
|
||||||
|
(unsigned)rbuf[i].super.datagram_size, rbuf[i].super.tag);
|
||||||
|
|
||||||
|
gnrc_pktbuf_release(rbuf[i].pkt);
|
||||||
|
rbuf_rm(&(rbuf[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||||
|
gnrc_sixlowpan_frag_vrb_gc();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _set_rbuf_timeout(void)
|
||||||
|
{
|
||||||
|
xtimer_set_msg(&_gc_timer, RBUF_TIMEOUT, &_gc_timer_msg, sched_active_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gnrc_sixlowpan_rbuf_t *_rbuf_get(const void *src, size_t src_len,
|
||||||
|
const void *dst, size_t dst_len,
|
||||||
|
size_t size, uint16_t tag,
|
||||||
|
unsigned page)
|
||||||
|
{
|
||||||
|
gnrc_sixlowpan_rbuf_t *res = NULL, *oldest = NULL;
|
||||||
|
uint32_t now_usec = xtimer_now_usec();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 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) &&
|
||||||
|
(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)) {
|
||||||
|
DEBUG("6lo rfrag: entry %p (%s, ", (void *)(&rbuf[i]),
|
||||||
|
gnrc_netif_addr_to_str(rbuf[i].super.src,
|
||||||
|
rbuf[i].super.src_len,
|
||||||
|
l2addr_str));
|
||||||
|
DEBUG("%s, %u, %u) found\n",
|
||||||
|
gnrc_netif_addr_to_str(rbuf[i].super.dst,
|
||||||
|
rbuf[i].super.dst_len,
|
||||||
|
l2addr_str),
|
||||||
|
(unsigned)rbuf[i].super.datagram_size, rbuf[i].super.tag);
|
||||||
|
rbuf[i].super.arrival = now_usec;
|
||||||
|
_set_rbuf_timeout();
|
||||||
|
return &(rbuf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there is a free spot: remember it */
|
||||||
|
if ((res == NULL) && rbuf_entry_empty(&rbuf[i])) {
|
||||||
|
res = &(rbuf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember oldest slot */
|
||||||
|
/* note that xtimer_now will overflow in ~1.2 hours */
|
||||||
|
if ((oldest == NULL) ||
|
||||||
|
(oldest->super.arrival - rbuf[i].super.arrival < UINT32_MAX / 2)) {
|
||||||
|
oldest = &(rbuf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* entry not in buffer and no empty spot found */
|
||||||
|
if (res == NULL) {
|
||||||
|
assert(oldest != NULL);
|
||||||
|
/* if oldest is not empty, res must not be NULL (because otherwise
|
||||||
|
* oldest could have been picked as res) */
|
||||||
|
assert(!rbuf_entry_empty(oldest));
|
||||||
|
if (GNRC_SIXLOWPAN_FRAG_RBUF_AGGRESSIVE_OVERRIDE ||
|
||||||
|
((now_usec - oldest->super.arrival) >
|
||||||
|
GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US)) {
|
||||||
|
DEBUG("6lo rfrag: reassembly buffer full, remove oldest entry\n");
|
||||||
|
gnrc_pktbuf_release(oldest->pkt);
|
||||||
|
rbuf_rm(oldest);
|
||||||
|
res = oldest;
|
||||||
|
#if GNRC_SIXLOWPAN_FRAG_RBUF_AGGRESSIVE_OVERRIDE && \
|
||||||
|
defined(MODULE_GNRC_SIXLOWPAN_FRAG_STATS)
|
||||||
|
_stats.rbuf_full++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_STATS
|
||||||
|
_stats.rbuf_full++;
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we have an empty spot */
|
||||||
|
|
||||||
|
gnrc_nettype_t reass_type;
|
||||||
|
switch (page) {
|
||||||
|
/* use switch(page) to be extendable */
|
||||||
|
#ifdef MODULE_GNRC_IPV6
|
||||||
|
case 0U:
|
||||||
|
reass_type = GNRC_NETTYPE_IPV6;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
reass_type = GNRC_NETTYPE_UNDEF;
|
||||||
|
}
|
||||||
|
res->pkt = gnrc_pktbuf_add(NULL, NULL, size, reass_type);
|
||||||
|
if (res->pkt == NULL) {
|
||||||
|
DEBUG("6lo rfrag: can not allocate reassembly buffer space.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*((uint64_t *)res->pkt->data) = 0; /* clean first few bytes for later
|
||||||
|
* look-ups */
|
||||||
|
res->super.datagram_size = size;
|
||||||
|
res->super.arrival = now_usec;
|
||||||
|
memcpy(res->super.src, src, src_len);
|
||||||
|
memcpy(res->super.dst, dst, dst_len);
|
||||||
|
res->super.src_len = src_len;
|
||||||
|
res->super.dst_len = dst_len;
|
||||||
|
res->super.tag = tag;
|
||||||
|
res->super.current_size = 0;
|
||||||
|
|
||||||
|
DEBUG("6lo rfrag: entry %p (%s, ", (void *)res,
|
||||||
|
gnrc_netif_addr_to_str(res->super.src, res->super.src_len,
|
||||||
|
l2addr_str));
|
||||||
|
DEBUG("%s, %u, %u) created\n",
|
||||||
|
gnrc_netif_addr_to_str(res->super.dst, res->super.dst_len,
|
||||||
|
l2addr_str), res->super.datagram_size,
|
||||||
|
res->super.tag);
|
||||||
|
|
||||||
|
_set_rbuf_timeout();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TEST_SUITES
|
||||||
|
void rbuf_reset(void)
|
||||||
|
{
|
||||||
|
xtimer_remove(&_gc_timer);
|
||||||
|
memset(rbuf_int, 0, sizeof(rbuf_int));
|
||||||
|
for (unsigned int i = 0; i < RBUF_SIZE; i++) {
|
||||||
|
if ((rbuf[i].pkt != NULL) &&
|
||||||
|
(rbuf[i].pkt->users > 0)) {
|
||||||
|
gnrc_pktbuf_release(rbuf[i].pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(rbuf, 0, sizeof(rbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
const gnrc_sixlowpan_rbuf_t *rbuf_array(void)
|
||||||
|
{
|
||||||
|
return &rbuf[0];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void gnrc_sixlowpan_frag_rbuf_base_rm(gnrc_sixlowpan_rbuf_base_t *entry)
|
void gnrc_sixlowpan_frag_rbuf_base_rm(gnrc_sixlowpan_rbuf_base_t *entry)
|
||||||
{
|
{
|
||||||
while (entry->ints != NULL) {
|
while (entry->ints != NULL) {
|
||||||
|
|||||||
@ -1,436 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
||||||
*
|
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
|
||||||
* General Public License v2.1. See the file LICENSE in the top level
|
|
||||||
* directory for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
* @file
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "rbuf.h"
|
|
||||||
#include "net/ipv6.h"
|
|
||||||
#include "net/ipv6/hdr.h"
|
|
||||||
#include "net/gnrc.h"
|
|
||||||
#include "net/gnrc/sixlowpan.h"
|
|
||||||
#include "net/gnrc/sixlowpan/frag.h"
|
|
||||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
|
||||||
#include "net/gnrc/sixlowpan/frag/vrb.h"
|
|
||||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
|
||||||
#include "net/sixlowpan.h"
|
|
||||||
#include "thread.h"
|
|
||||||
#include "xtimer.h"
|
|
||||||
#include "utlist.h"
|
|
||||||
|
|
||||||
#define ENABLE_DEBUG (0)
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
/* estimated fragment payload size to determinate RBUF_INT_SIZE, default to
|
|
||||||
* MAC payload size - fragment header. */
|
|
||||||
#ifndef GNRC_SIXLOWPAN_FRAG_SIZE
|
|
||||||
/* assuming 64-bit source/destination address, source PAN ID omitted */
|
|
||||||
#define GNRC_SIXLOWPAN_FRAG_SIZE (104 - 5)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RBUF_INT_SIZE
|
|
||||||
/* same as ((int) ceil((double) N / D)) */
|
|
||||||
#define DIV_CEIL(N, D) (((N) + (D) - 1) / (D))
|
|
||||||
#define RBUF_INT_SIZE (DIV_CEIL(IPV6_MIN_MTU, GNRC_SIXLOWPAN_FRAG_SIZE) * RBUF_SIZE)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static gnrc_sixlowpan_rbuf_int_t rbuf_int[RBUF_INT_SIZE];
|
|
||||||
|
|
||||||
static gnrc_sixlowpan_rbuf_t rbuf[RBUF_SIZE];
|
|
||||||
|
|
||||||
static char l2addr_str[3 * IEEE802154_LONG_ADDRESS_LEN];
|
|
||||||
|
|
||||||
static xtimer_t _gc_timer;
|
|
||||||
static msg_t _gc_timer_msg = { .type = GNRC_SIXLOWPAN_MSG_FRAG_GC_RBUF };
|
|
||||||
|
|
||||||
/* ------------------------------------
|
|
||||||
* internal function definitions
|
|
||||||
* ------------------------------------*/
|
|
||||||
/* checks whether start and end overlaps, but not identical to, given interval i */
|
|
||||||
static inline bool _rbuf_int_overlap_partially(gnrc_sixlowpan_rbuf_int_t *i,
|
|
||||||
uint16_t start, uint16_t end);
|
|
||||||
/* gets a free entry from interval buffer */
|
|
||||||
static gnrc_sixlowpan_rbuf_int_t *_rbuf_int_get_free(void);
|
|
||||||
/* update interval buffer of entry */
|
|
||||||
static bool _rbuf_update_ints(gnrc_sixlowpan_rbuf_base_t *entry,
|
|
||||||
uint16_t offset, size_t frag_size);
|
|
||||||
/* gets an entry identified by its tupel */
|
|
||||||
static gnrc_sixlowpan_rbuf_t *_rbuf_get(const void *src, size_t src_len,
|
|
||||||
const void *dst, size_t dst_len,
|
|
||||||
size_t size, uint16_t tag,
|
|
||||||
unsigned page);
|
|
||||||
/* internal add to repeat add when fragments overlapped */
|
|
||||||
static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
|
||||||
size_t offset, unsigned page);
|
|
||||||
|
|
||||||
/* status codes for _rbuf_add() */
|
|
||||||
enum {
|
|
||||||
RBUF_ADD_SUCCESS,
|
|
||||||
RBUF_ADD_ERROR,
|
|
||||||
RBUF_ADD_REPEAT,
|
|
||||||
RBUF_ADD_DUPLICATE,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_STATS
|
|
||||||
static gnrc_sixlowpan_frag_stats_t _stats;
|
|
||||||
|
|
||||||
gnrc_sixlowpan_frag_stats_t *gnrc_sixlowpan_frag_stats_get(void)
|
|
||||||
{
|
|
||||||
return &_stats;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int _check_fragments(gnrc_sixlowpan_rbuf_base_t *entry,
|
|
||||||
size_t frag_size, size_t offset)
|
|
||||||
{
|
|
||||||
gnrc_sixlowpan_rbuf_int_t *ptr = entry->ints;
|
|
||||||
|
|
||||||
/* If the fragment overlaps another fragment and differs in either the size
|
|
||||||
* or the offset of the overlapped fragment, discards the datagram
|
|
||||||
* https://tools.ietf.org/html/rfc4944#section-5.3 */
|
|
||||||
while (ptr != NULL) {
|
|
||||||
if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) {
|
|
||||||
|
|
||||||
/* "A fresh reassembly may be commenced with the most recently
|
|
||||||
* received link fragment"
|
|
||||||
* https://tools.ietf.org/html/rfc4944#section-5.3 */
|
|
||||||
return RBUF_ADD_REPEAT;
|
|
||||||
}
|
|
||||||
/* End was already checked in overlap check */
|
|
||||||
if (ptr->start == offset) {
|
|
||||||
DEBUG("6lo rbuf: fragment already in reassembly buffer");
|
|
||||||
return RBUF_ADD_DUPLICATE;
|
|
||||||
}
|
|
||||||
ptr = ptr->next;
|
|
||||||
}
|
|
||||||
return RBUF_ADD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
|
||||||
size_t offset, unsigned page)
|
|
||||||
{
|
|
||||||
if (_rbuf_add(netif_hdr, pkt, offset, page) == RBUF_ADD_REPEAT) {
|
|
||||||
_rbuf_add(netif_hdr, pkt, offset, page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
|
|
||||||
size_t offset, unsigned page)
|
|
||||||
{
|
|
||||||
gnrc_sixlowpan_rbuf_t *entry;
|
|
||||||
sixlowpan_frag_n_t *frag = pkt->data;
|
|
||||||
uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t);
|
|
||||||
size_t frag_size;
|
|
||||||
|
|
||||||
/* check if provided offset is the same as in fragment */
|
|
||||||
assert(((((frag->disp_size.u8[0] & SIXLOWPAN_FRAG_DISP_MASK) ==
|
|
||||||
SIXLOWPAN_FRAG_1_DISP)) && (offset == 0)) ||
|
|
||||||
((((frag->disp_size.u8[0] & SIXLOWPAN_FRAG_DISP_MASK) ==
|
|
||||||
SIXLOWPAN_FRAG_N_DISP)) && (offset == (frag->offset * 8U))));
|
|
||||||
rbuf_gc();
|
|
||||||
entry = _rbuf_get(gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len,
|
|
||||||
gnrc_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len,
|
|
||||||
byteorder_ntohs(frag->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK,
|
|
||||||
byteorder_ntohs(frag->tag), page);
|
|
||||||
|
|
||||||
if (entry == NULL) {
|
|
||||||
DEBUG("6lo rbuf: reassembly buffer full.\n");
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
return RBUF_ADD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dispatches in the first fragment are ignored */
|
|
||||||
if (offset == 0) {
|
|
||||||
frag_size = pkt->size - sizeof(sixlowpan_frag_t);
|
|
||||||
if (data[0] == SIXLOWPAN_UNCOMP) {
|
|
||||||
frag_size--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
frag_size = pkt->size - sizeof(sixlowpan_frag_n_t);
|
|
||||||
data++; /* FRAGN header is one byte longer (offset) */
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((offset + frag_size) > entry->super.datagram_size) {
|
|
||||||
DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n");
|
|
||||||
gnrc_pktbuf_release(entry->pkt);
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
rbuf_rm(entry);
|
|
||||||
return RBUF_ADD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (_check_fragments(&entry->super, frag_size, offset)) {
|
|
||||||
case RBUF_ADD_REPEAT:
|
|
||||||
DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n");
|
|
||||||
gnrc_pktbuf_release(entry->pkt);
|
|
||||||
rbuf_rm(entry);
|
|
||||||
return RBUF_ADD_REPEAT;
|
|
||||||
case RBUF_ADD_DUPLICATE:
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
return RBUF_ADD_SUCCESS;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rbuf_update_ints(&entry->super, offset, frag_size)) {
|
|
||||||
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)) {
|
|
||||||
gnrc_pktsnip_t *frag_hdr = gnrc_pktbuf_mark(pkt,
|
|
||||||
sizeof(sixlowpan_frag_t), GNRC_NETTYPE_SIXLOWPAN);
|
|
||||||
if (frag_hdr == NULL) {
|
|
||||||
gnrc_pktbuf_release(entry->pkt);
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
rbuf_rm(entry);
|
|
||||||
return RBUF_ADD_ERROR;
|
|
||||||
}
|
|
||||||
gnrc_sixlowpan_iphc_recv(pkt, entry, 0);
|
|
||||||
return RBUF_ADD_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (data[0] == SIXLOWPAN_UNCOMP) {
|
|
||||||
data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(((uint8_t *)entry->pkt->data) + offset, data,
|
|
||||||
frag_size);
|
|
||||||
}
|
|
||||||
gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(entry, netif_hdr);
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
return RBUF_ADD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool _rbuf_int_overlap_partially(gnrc_sixlowpan_rbuf_int_t *i,
|
|
||||||
uint16_t start, uint16_t end)
|
|
||||||
{
|
|
||||||
/* start and ends are both inclusive, so using <= for both */
|
|
||||||
return ((i->start <= end) && (start <= i->end)) && /* overlaps */
|
|
||||||
((start != i->start) || (end != i->end)); /* not identical */
|
|
||||||
}
|
|
||||||
|
|
||||||
static gnrc_sixlowpan_rbuf_int_t *_rbuf_int_get_free(void)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < RBUF_INT_SIZE; i++) {
|
|
||||||
if (rbuf_int[i].end == 0) { /* start must be smaller than end anyways*/
|
|
||||||
return rbuf_int + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rbuf_rm(gnrc_sixlowpan_rbuf_t *entry)
|
|
||||||
{
|
|
||||||
gnrc_sixlowpan_frag_rbuf_base_rm(&entry->super);
|
|
||||||
entry->pkt = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _rbuf_update_ints(gnrc_sixlowpan_rbuf_base_t *entry,
|
|
||||||
uint16_t offset, size_t frag_size)
|
|
||||||
{
|
|
||||||
gnrc_sixlowpan_rbuf_int_t *new;
|
|
||||||
uint16_t end = (uint16_t)(offset + frag_size - 1);
|
|
||||||
|
|
||||||
new = _rbuf_int_get_free();
|
|
||||||
|
|
||||||
if (new == NULL) {
|
|
||||||
DEBUG("6lo rfrag: no space left in rbuf interval buffer.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
new->start = offset;
|
|
||||||
new->end = end;
|
|
||||||
|
|
||||||
DEBUG("6lo rfrag: add interval (%" PRIu16 ", %" PRIu16 ") to entry (%s, ",
|
|
||||||
new->start, new->end, gnrc_netif_addr_to_str(entry->src,
|
|
||||||
entry->src_len,
|
|
||||||
l2addr_str));
|
|
||||||
DEBUG("%s, %u, %u)\n", gnrc_netif_addr_to_str(entry->dst,
|
|
||||||
entry->dst_len,
|
|
||||||
l2addr_str),
|
|
||||||
entry->datagram_size, entry->tag);
|
|
||||||
|
|
||||||
LL_PREPEND(entry->ints, new);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rbuf_gc(void)
|
|
||||||
{
|
|
||||||
uint32_t now_usec = xtimer_now_usec();
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < RBUF_SIZE; i++) {
|
|
||||||
/* since pkt occupies pktbuf, aggressivly collect garbage */
|
|
||||||
if (!rbuf_entry_empty(&rbuf[i]) &&
|
|
||||||
((now_usec - rbuf[i].super.arrival) > RBUF_TIMEOUT)) {
|
|
||||||
DEBUG("6lo rfrag: entry (%s, ",
|
|
||||||
gnrc_netif_addr_to_str(rbuf[i].super.src,
|
|
||||||
rbuf[i].super.src_len,
|
|
||||||
l2addr_str));
|
|
||||||
DEBUG("%s, %u, %u) timed out\n",
|
|
||||||
gnrc_netif_addr_to_str(rbuf[i].super.dst,
|
|
||||||
rbuf[i].super.dst_len,
|
|
||||||
l2addr_str),
|
|
||||||
(unsigned)rbuf[i].super.datagram_size, rbuf[i].super.tag);
|
|
||||||
|
|
||||||
gnrc_pktbuf_release(rbuf[i].pkt);
|
|
||||||
rbuf_rm(&(rbuf[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
|
||||||
gnrc_sixlowpan_frag_vrb_gc();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void _set_rbuf_timeout(void)
|
|
||||||
{
|
|
||||||
xtimer_set_msg(&_gc_timer, RBUF_TIMEOUT, &_gc_timer_msg, sched_active_pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gnrc_sixlowpan_rbuf_t *_rbuf_get(const void *src, size_t src_len,
|
|
||||||
const void *dst, size_t dst_len,
|
|
||||||
size_t size, uint16_t tag,
|
|
||||||
unsigned page)
|
|
||||||
{
|
|
||||||
gnrc_sixlowpan_rbuf_t *res = NULL, *oldest = NULL;
|
|
||||||
uint32_t now_usec = xtimer_now_usec();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 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) &&
|
|
||||||
(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)) {
|
|
||||||
DEBUG("6lo rfrag: entry %p (%s, ", (void *)(&rbuf[i]),
|
|
||||||
gnrc_netif_addr_to_str(rbuf[i].super.src,
|
|
||||||
rbuf[i].super.src_len,
|
|
||||||
l2addr_str));
|
|
||||||
DEBUG("%s, %u, %u) found\n",
|
|
||||||
gnrc_netif_addr_to_str(rbuf[i].super.dst,
|
|
||||||
rbuf[i].super.dst_len,
|
|
||||||
l2addr_str),
|
|
||||||
(unsigned)rbuf[i].super.datagram_size, rbuf[i].super.tag);
|
|
||||||
rbuf[i].super.arrival = now_usec;
|
|
||||||
_set_rbuf_timeout();
|
|
||||||
return &(rbuf[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if there is a free spot: remember it */
|
|
||||||
if ((res == NULL) && rbuf_entry_empty(&rbuf[i])) {
|
|
||||||
res = &(rbuf[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remember oldest slot */
|
|
||||||
/* note that xtimer_now will overflow in ~1.2 hours */
|
|
||||||
if ((oldest == NULL) ||
|
|
||||||
(oldest->super.arrival - rbuf[i].super.arrival < UINT32_MAX / 2)) {
|
|
||||||
oldest = &(rbuf[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* entry not in buffer and no empty spot found */
|
|
||||||
if (res == NULL) {
|
|
||||||
assert(oldest != NULL);
|
|
||||||
/* if oldest is not empty, res must not be NULL (because otherwise
|
|
||||||
* oldest could have been picked as res) */
|
|
||||||
assert(!rbuf_entry_empty(oldest));
|
|
||||||
if (GNRC_SIXLOWPAN_FRAG_RBUF_AGGRESSIVE_OVERRIDE ||
|
|
||||||
((now_usec - oldest->super.arrival) >
|
|
||||||
GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US)) {
|
|
||||||
DEBUG("6lo rfrag: reassembly buffer full, remove oldest entry\n");
|
|
||||||
gnrc_pktbuf_release(oldest->pkt);
|
|
||||||
rbuf_rm(oldest);
|
|
||||||
res = oldest;
|
|
||||||
#if GNRC_SIXLOWPAN_FRAG_RBUF_AGGRESSIVE_OVERRIDE && \
|
|
||||||
defined(MODULE_GNRC_SIXLOWPAN_FRAG_STATS)
|
|
||||||
_stats.rbuf_full++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_STATS
|
|
||||||
_stats.rbuf_full++;
|
|
||||||
#endif
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now we have an empty spot */
|
|
||||||
|
|
||||||
gnrc_nettype_t reass_type;
|
|
||||||
switch (page) {
|
|
||||||
/* use switch(page) to be extendable */
|
|
||||||
#ifdef MODULE_GNRC_IPV6
|
|
||||||
case 0U:
|
|
||||||
reass_type = GNRC_NETTYPE_IPV6;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
reass_type = GNRC_NETTYPE_UNDEF;
|
|
||||||
}
|
|
||||||
res->pkt = gnrc_pktbuf_add(NULL, NULL, size, reass_type);
|
|
||||||
if (res->pkt == NULL) {
|
|
||||||
DEBUG("6lo rfrag: can not allocate reassembly buffer space.\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*((uint64_t *)res->pkt->data) = 0; /* clean first few bytes for later
|
|
||||||
* look-ups */
|
|
||||||
res->super.datagram_size = size;
|
|
||||||
res->super.arrival = now_usec;
|
|
||||||
memcpy(res->super.src, src, src_len);
|
|
||||||
memcpy(res->super.dst, dst, dst_len);
|
|
||||||
res->super.src_len = src_len;
|
|
||||||
res->super.dst_len = dst_len;
|
|
||||||
res->super.tag = tag;
|
|
||||||
res->super.current_size = 0;
|
|
||||||
|
|
||||||
DEBUG("6lo rfrag: entry %p (%s, ", (void *)res,
|
|
||||||
gnrc_netif_addr_to_str(res->super.src, res->super.src_len,
|
|
||||||
l2addr_str));
|
|
||||||
DEBUG("%s, %u, %u) created\n",
|
|
||||||
gnrc_netif_addr_to_str(res->super.dst, res->super.dst_len,
|
|
||||||
l2addr_str), res->super.datagram_size,
|
|
||||||
res->super.tag);
|
|
||||||
|
|
||||||
_set_rbuf_timeout();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TEST_SUITES
|
|
||||||
void rbuf_reset(void)
|
|
||||||
{
|
|
||||||
xtimer_remove(&_gc_timer);
|
|
||||||
memset(rbuf_int, 0, sizeof(rbuf_int));
|
|
||||||
for (unsigned int i = 0; i < RBUF_SIZE; i++) {
|
|
||||||
if ((rbuf[i].pkt != NULL) &&
|
|
||||||
(rbuf[i].pkt->users > 0)) {
|
|
||||||
gnrc_pktbuf_release(rbuf[i].pkt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memset(rbuf, 0, sizeof(rbuf));
|
|
||||||
}
|
|
||||||
|
|
||||||
const gnrc_sixlowpan_rbuf_t *rbuf_array(void)
|
|
||||||
{
|
|
||||||
return &rbuf[0];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
||||||
*
|
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
|
||||||
* General Public License v2.1. See the file LICENSE in the top level
|
|
||||||
* directory for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup net_gnrc_sixlowpan_frag
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
* @file
|
|
||||||
* @internal
|
|
||||||
* @brief 6LoWPAN reassembly buffer
|
|
||||||
*
|
|
||||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
||||||
*/
|
|
||||||
#ifndef RBUF_H
|
|
||||||
#define RBUF_H
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "net/gnrc/netif/hdr.h"
|
|
||||||
#include "net/gnrc/pkt.h"
|
|
||||||
|
|
||||||
#include "net/gnrc/sixlowpan/config.h"
|
|
||||||
#include "net/gnrc/sixlowpan/frag/rb.h"
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name Legacy defines
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
#define RBUF_SIZE (GNRC_SIXLOWPAN_FRAG_RBUF_SIZE)
|
|
||||||
#define RBUF_TIMEOUT (GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US)
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds a new fragment to the reassembly buffer. If the packet is
|
|
||||||
* complete, dispatch the packet with the transmit information of
|
|
||||||
* the last fragment.
|
|
||||||
*
|
|
||||||
* @param[in] netif_hdr The interface header of the fragment, with
|
|
||||||
* gnrc_netif_hdr_t::if_pid and its source and
|
|
||||||
* destination address set.
|
|
||||||
* @param[in] frag The fragment to add.
|
|
||||||
* @param[in] offset The fragment's offset.
|
|
||||||
* @param[in] page Current 6Lo dispatch parsing page.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *frag,
|
|
||||||
size_t offset, unsigned page);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks timeouts and removes entries if necessary
|
|
||||||
*/
|
|
||||||
void rbuf_gc(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unsets a reassembly buffer entry (but does not free
|
|
||||||
* rbuf_t::super::pkt)
|
|
||||||
*
|
|
||||||
* This functions sets rbuf_t::super::pkt to NULL and removes all rbuf::ints.
|
|
||||||
*
|
|
||||||
* @param[in] rbuf A reassembly buffer entry
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
void rbuf_rm(gnrc_sixlowpan_rbuf_t *rbuf);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a reassembly buffer entry is unset
|
|
||||||
*
|
|
||||||
* @param[in] rbuf A reassembly buffer entry
|
|
||||||
*
|
|
||||||
* @return true, if @p rbuf is empty (i.e. rbuf->super.pkt is NULL).
|
|
||||||
* @return false, if @p rbuf is in use.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
static inline bool rbuf_entry_empty(const gnrc_sixlowpan_rbuf_t *rbuf) {
|
|
||||||
return (rbuf->pkt == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(TEST_SUITES) || defined(DOXYGEN)
|
|
||||||
/**
|
|
||||||
* @brief Resets the packet buffer to a clean state
|
|
||||||
*
|
|
||||||
* @note Only available when @ref TEST_SUITES is defined
|
|
||||||
*/
|
|
||||||
void rbuf_reset(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a pointer to the array representing the reassembly buffer.
|
|
||||||
*
|
|
||||||
* @note Only available when @ref TEST_SUITES is defined
|
|
||||||
*
|
|
||||||
* @return The first element of the reassembly buffer. `const`, so that write
|
|
||||||
* access is immediately spotted at compile time of tests. The `const`
|
|
||||||
* qualifier may however be discarded if required by the tests.
|
|
||||||
*/
|
|
||||||
const gnrc_sixlowpan_rbuf_t *rbuf_array(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* RBUF_H */
|
|
||||||
/** @} */
|
|
||||||
@ -12,7 +12,4 @@ DISABLE_MODULE += auto_init
|
|||||||
# we don't need all this packet buffer space so reduce it a little
|
# we don't need all this packet buffer space so reduce it a little
|
||||||
CFLAGS += -DTEST_SUITES -DGNRC_PKTBUF_SIZE=2048
|
CFLAGS += -DTEST_SUITES -DGNRC_PKTBUF_SIZE=2048
|
||||||
|
|
||||||
# to be able to include gnrc_sixlowpan_frag-internal `rbuf.h`
|
|
||||||
INCLUDES += -I$(RIOTBASE)/sys/net/gnrc/network_layer/sixlowpan/frag/
|
|
||||||
|
|
||||||
include $(RIOTBASE)/Makefile.include
|
include $(RIOTBASE)/Makefile.include
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
#include "net/gnrc/pktbuf.h"
|
#include "net/gnrc/pktbuf.h"
|
||||||
#include "net/gnrc/netreg.h"
|
#include "net/gnrc/netreg.h"
|
||||||
#include "net/gnrc/sixlowpan/frag.h"
|
#include "net/gnrc/sixlowpan/frag.h"
|
||||||
#include "rbuf.h"
|
#include "net/gnrc/sixlowpan/frag/rb.h"
|
||||||
#include "xtimer.h"
|
#include "xtimer.h"
|
||||||
|
|
||||||
#define TEST_NETIF_HDR_SRC { 0xb3, 0x47, 0x60, 0x49, \
|
#define TEST_NETIF_HDR_SRC { 0xb3, 0x47, 0x60, 0x49, \
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user