1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

gnrc_sixlowpan_frag: expose (parts of) reassembly buffer

This exposes the parts of the reassembly buffer to be usable as context
as proposed in #8511.

I only exposed *parts of* for two reasons:

1. I don't need to expose further types (like `rbuf_int_t`), that are
   not of interest outside of fragmentation.
2. This allows for an easy future extension for the virtual reassembly
   buffer as proposed in [[1]].

This makes this change a little bit more involved, because instead of
just renaming the type, I also need to add the usage of the `super`
member, but I think in the end this little preparation work will be
beneficial in the future.

[1]: https://tools.ietf.org/html/draft-watteyne-6lo-minimal-fragment-01#section-3
This commit is contained in:
Martine Lenders 2018-06-14 17:13:51 +02:00
parent e91e0a7807
commit 86cbde2db5
3 changed files with 91 additions and 67 deletions

View File

@ -31,6 +31,7 @@
#include "byteorder.h"
#include "kernel_types.h"
#include "net/gnrc/pkt.h"
#include "net/ieee802154.h"
#include "net/sixlowpan.h"
#ifdef __cplusplus
@ -42,6 +43,32 @@ extern "C" {
*/
#define GNRC_SIXLOWPAN_MSG_FRAG_SND (0x0225)
/**
* @brief An entry in the 6LoWPAN reassembly buffer.
*
* A recipient of a fragment SHALL use
*
* 1. the source address,
* 2. the destination address,
* 3. the datagram size (gnrc_pktsnip_t::size of rbuf_t::pkt), and
* 4. the datagram tag
*
* to identify all fragments that belong to the given datagram.
*
* @see [RFC 4944, section 5.3](https://tools.ietf.org/html/rfc4944#section-5.3)
*/
typedef struct {
/**
* @brief The reassembled packet in the packet buffer
*/
gnrc_pktsnip_t *pkt;
uint8_t src[IEEE802154_LONG_ADDRESS_LEN]; /**< source address */
uint8_t dst[IEEE802154_LONG_ADDRESS_LEN]; /**< destination address */
uint8_t src_len; /**< length of gnrc_sixlowpan_rbuf_t::src */
uint8_t dst_len; /**< length of gnrc_sixlowpan_rbuf_t::dst */
uint16_t tag; /**< the datagram's tag */
} gnrc_sixlowpan_rbuf_t;
/**
* @brief Definition of 6LoWPAN fragmentation type.
*/

View File

@ -46,7 +46,7 @@ static rbuf_int_t rbuf_int[RBUF_INT_SIZE];
static rbuf_t rbuf[RBUF_SIZE];
static char l2addr_str[3 * RBUF_L2ADDR_MAX_LEN];
static char l2addr_str[3 * IEEE802154_LONG_ADDRESS_LEN];
/* ------------------------------------
* internal function definitions
@ -100,11 +100,13 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
else if (sixlowpan_iphc_is(data)) {
size_t iphc_len, nh_len = 0;
iphc_len = gnrc_sixlowpan_iphc_decode(&entry->pkt, pkt, entry->pkt->size,
sizeof(sixlowpan_frag_t), &nh_len);
iphc_len = gnrc_sixlowpan_iphc_decode(&entry->super.pkt, pkt,
entry->super.pkt->size,
sizeof(sixlowpan_frag_t),
&nh_len);
if (iphc_len == 0) {
DEBUG("6lo rfrag: could not decode IPHC dispatch\n");
gnrc_pktbuf_release(entry->pkt);
gnrc_pktbuf_release(entry->super.pkt);
_rbuf_rem(entry);
return;
}
@ -121,9 +123,9 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
data++; /* FRAGN header is one byte longer (offset) */
}
if ((offset + frag_size) > entry->pkt->size) {
if ((offset + frag_size) > entry->super.pkt->size) {
DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n");
gnrc_pktbuf_release(entry->pkt);
gnrc_pktbuf_release(entry->super.pkt);
_rbuf_rem(entry);
return;
}
@ -134,7 +136,7 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
while (ptr != NULL) {
if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) {
DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n");
gnrc_pktbuf_release(entry->pkt);
gnrc_pktbuf_release(entry->super.pkt);
_rbuf_rem(entry);
/* "A fresh reassembly may be commenced with the most recently
@ -151,17 +153,19 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
if (_rbuf_update_ints(entry, offset, frag_size)) {
DEBUG("6lo rbuf: add fragment data\n");
entry->cur_size += (uint16_t)frag_size;
memcpy(((uint8_t *)entry->pkt->data) + offset + data_offset, data,
memcpy(((uint8_t *)entry->super.pkt->data) + offset + data_offset, data,
frag_size - data_offset);
}
if (entry->cur_size == entry->pkt->size) {
gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(entry->src, entry->src_len,
entry->dst, entry->dst_len);
if (entry->cur_size == entry->super.pkt->size) {
gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(entry->super.src,
entry->super.src_len,
entry->super.dst,
entry->super.dst_len);
if (netif == NULL) {
DEBUG("6lo rbuf: error allocating netif header\n");
gnrc_pktbuf_release(entry->pkt);
gnrc_pktbuf_release(entry->super.pkt);
_rbuf_rem(entry);
return;
}
@ -175,8 +179,8 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
new_netif_hdr->flags = netif_hdr->flags;
new_netif_hdr->lqi = netif_hdr->lqi;
new_netif_hdr->rssi = netif_hdr->rssi;
LL_APPEND(entry->pkt, netif);
gnrc_sixlowpan_dispatch_recv(entry->pkt, NULL, 0);
LL_APPEND(entry->super.pkt, netif);
gnrc_sixlowpan_dispatch_recv(entry->super.pkt, NULL, 0);
_rbuf_rem(entry);
}
}
@ -210,7 +214,7 @@ static void _rbuf_rem(rbuf_t *entry)
entry->ints = next;
}
entry->pkt = NULL;
entry->super.pkt = NULL;
}
static bool _rbuf_update_ints(rbuf_t *entry, uint16_t offset, size_t frag_size)
@ -229,12 +233,13 @@ static bool _rbuf_update_ints(rbuf_t *entry, uint16_t offset, size_t frag_size)
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,
new->start, new->end, gnrc_netif_addr_to_str(entry->super.src,
entry->super.src_len,
l2addr_str));
DEBUG("%s, %u, %u)\n", gnrc_netif_addr_to_str(entry->dst, entry->dst_len,
DEBUG("%s, %u, %u)\n", gnrc_netif_addr_to_str(entry->super.dst,
entry->super.dst_len,
l2addr_str),
(unsigned)entry->pkt->size, entry->tag);
(unsigned)entry->super.pkt->size, entry->super.tag);
LL_PREPEND(entry->ints, new);
@ -248,17 +253,19 @@ static void _rbuf_gc(void)
for (i = 0; i < RBUF_SIZE; i++) {
/* since pkt occupies pktbuf, aggressivly collect garbage */
if ((rbuf[i].pkt != NULL) &&
if ((rbuf[i].super.pkt != NULL) &&
((now_usec - rbuf[i].arrival) > RBUF_TIMEOUT)) {
DEBUG("6lo rfrag: entry (%s, ",
gnrc_netif_addr_to_str(rbuf[i].src, rbuf[i].src_len,
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].dst, rbuf[i].dst_len,
gnrc_netif_addr_to_str(rbuf[i].super.dst,
rbuf[i].super.dst_len,
l2addr_str),
(unsigned)rbuf[i].pkt->size, rbuf[i].tag);
(unsigned)rbuf[i].super.pkt->size, rbuf[i].super.tag);
gnrc_pktbuf_release(rbuf[i].pkt);
gnrc_pktbuf_release(rbuf[i].super.pkt);
_rbuf_rem(&(rbuf[i]));
}
}
@ -273,24 +280,26 @@ static rbuf_t *_rbuf_get(const void *src, size_t src_len,
for (unsigned int i = 0; i < RBUF_SIZE; i++) {
/* check first if entry already available */
if ((rbuf[i].pkt != NULL) && (rbuf[i].pkt->size == size) &&
(rbuf[i].tag == tag) && (rbuf[i].src_len == src_len) &&
(rbuf[i].dst_len == dst_len) &&
(memcmp(rbuf[i].src, src, src_len) == 0) &&
(memcmp(rbuf[i].dst, dst, dst_len) == 0)) {
if ((rbuf[i].super.pkt != NULL) && (rbuf[i].super.pkt->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].src, rbuf[i].src_len,
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].dst, rbuf[i].dst_len,
gnrc_netif_addr_to_str(rbuf[i].super.dst,
rbuf[i].super.dst_len,
l2addr_str),
(unsigned)rbuf[i].pkt->size, rbuf[i].tag);
(unsigned)rbuf[i].super.pkt->size, rbuf[i].super.tag);
rbuf[i].arrival = now_usec;
return &(rbuf[i]);
}
/* if there is a free spot: remember it */
if ((res == NULL) && (rbuf[i].pkt == NULL)) {
if ((res == NULL) && (rbuf[i].super.pkt == NULL)) {
res = &(rbuf[i]);
}
@ -304,36 +313,39 @@ static rbuf_t *_rbuf_get(const void *src, size_t src_len,
/* entry not in buffer and no empty spot found */
if (res == NULL) {
assert(oldest != NULL);
assert(oldest->pkt != NULL); /* if oldest->pkt == NULL, res must not be NULL */
/* if oldest->pkt == NULL, res must not be NULL */
assert(oldest->super.pkt != NULL);
DEBUG("6lo rfrag: reassembly buffer full, remove oldest entry\n");
gnrc_pktbuf_release(oldest->pkt);
gnrc_pktbuf_release(oldest->super.pkt);
_rbuf_rem(oldest);
res = oldest;
}
/* now we have an empty spot */
res->pkt = gnrc_pktbuf_add(NULL, NULL, size, GNRC_NETTYPE_IPV6);
if (res->pkt == NULL) {
res->super.pkt = gnrc_pktbuf_add(NULL, NULL, size, GNRC_NETTYPE_IPV6);
if (res->super.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 */
*((uint64_t *)res->super.pkt->data) = 0; /* clean first few bytes for later
* look-ups */
res->arrival = now_usec;
memcpy(res->src, src, src_len);
memcpy(res->dst, dst, dst_len);
res->src_len = src_len;
res->dst_len = dst_len;
res->tag = tag;
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->cur_size = 0;
DEBUG("6lo rfrag: entry %p (%s, ", (void *)res,
gnrc_netif_addr_to_str(res->src, res->src_len, l2addr_str));
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->dst, res->dst_len, l2addr_str), (unsigned)res->pkt->size,
res->tag);
gnrc_netif_addr_to_str(res->super.dst, res->super.dst_len,
l2addr_str), (unsigned)res->super.pkt->size,
res->super.tag);
return res;
}

View File

@ -30,7 +30,6 @@
extern "C" {
#endif
#define RBUF_L2ADDR_MAX_LEN (8U) /**< maximum length for link-layer addresses */
#define RBUF_SIZE (4U) /**< size of the reassembly buffer */
#define RBUF_TIMEOUT (3U * US_PER_SEC) /**< timeout for reassembly in microseconds */
@ -53,33 +52,19 @@ typedef struct rbuf_int {
} rbuf_int_t;
/**
* @brief An entry in the 6LoWPAN reassembly buffer.
* @brief Internal representation of the 6LoWPAN reassembly buffer.
*
* @details A receipient of a fragment SHALL use
*
* 1. the source address,
* 2. the destination address,
* 3. the datagram size (gnrc_pktsnip_t::size of rbuf_t::pkt), and
* 4. the datagram tag
*
* to identify all fragments that belong to the given datagram.
*
* @see <a href="https://tools.ietf.org/html/rfc4944#section-5.3">
* RFC 4944, section 5.3
* </a>
* Additional members help with correct reassembly of the buffer.
*
* @internal
*
* @extends gnrc_sixlowpan_rbuf_t
*/
typedef struct {
gnrc_sixlowpan_rbuf_t super; /**< exposed part of the reassembly buffer */
rbuf_int_t *ints; /**< intervals of the fragment */
gnrc_pktsnip_t *pkt; /**< the reassembled packet in packet buffer */
uint32_t arrival; /**< time in microseconds of arrival of
* last received fragment */
uint8_t src[RBUF_L2ADDR_MAX_LEN]; /**< source address */
uint8_t dst[RBUF_L2ADDR_MAX_LEN]; /**< destination address */
uint8_t src_len; /**< length of source address */
uint8_t dst_len; /**< length of destination address */
uint16_t tag; /**< the datagram's tag */
uint16_t cur_size; /**< the datagram's current size */
} rbuf_t;