Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_sixlowpan_frag: allow send of multiple datagrams simultaneously #11021

Merged
merged 4 commits into from
May 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions sys/include/net/gnrc/sixlowpan/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ extern "C" {
#define GNRC_SIXLOWPAN_MSG_QUEUE_SIZE (8U)
#endif

/**
* @brief Number of datagrams that can be fragmented simultaneously
*
* This determines the number of @ref gnrc_sixlowpan_msg_frag_t instances
* available.
*
* @note Only applicable with
* [gnrc_sixlowpan_frag](@ref net_gnrc_sixlowpan_frag) module
*/
#ifndef GNRC_SIXLOWPAN_MSG_FRAG_SIZE
#define GNRC_SIXLOWPAN_MSG_FRAG_SIZE (1U)
#endif

/**
* @brief Size of the reassembly buffer
*
Expand Down
8 changes: 8 additions & 0 deletions sys/include/net/gnrc/sixlowpan/frag.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ typedef struct {
typedef struct {
gnrc_pktsnip_t *pkt; /**< Pointer to the IPv6 packet to be fragmented */
uint16_t datagram_size; /**< Length of just the (uncompressed) IPv6 packet to be fragmented */
uint16_t tag; /**< Tag used for the fragment */
uint16_t offset; /**< Offset of the Nth fragment from the beginning of the
* payload datagram */
} gnrc_sixlowpan_msg_frag_t;
Expand Down Expand Up @@ -129,6 +130,13 @@ void gnrc_sixlowpan_frag_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page);
*/
void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page);

/**
* @brief Generate a new datagram tag for sending
*
* @return A new datagram tag.
*/
uint16_t gnrc_sixlowpan_frag_next_tag(void);

/**
* @brief Garbage collect reassembly buffer.
*/
Expand Down
103 changes: 56 additions & 47 deletions sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@
#define ENABLE_DEBUG (0)
#include "debug.h"

static gnrc_sixlowpan_msg_frag_t _fragment_msg;
static gnrc_sixlowpan_msg_frag_t _fragment_msg[GNRC_SIXLOWPAN_MSG_FRAG_SIZE];

#if ENABLE_DEBUG
/* For PRIu16 etc. */
#include <inttypes.h>
#endif

static uint16_t _tag;
static uint16_t _current_tag;

static inline uint16_t _floor8(uint16_t length)
{
Expand All @@ -50,25 +50,29 @@ static inline size_t _min(size_t a, size_t b)
return (a < b) ? a : b;
}

static gnrc_pktsnip_t *_build_frag_pkt(gnrc_pktsnip_t *pkt, size_t payload_len,
size_t size)
static gnrc_pktsnip_t *_build_frag_pkt(gnrc_pktsnip_t *pkt,
gnrc_sixlowpan_msg_frag_t *fragment_msg,
size_t payload_len, size_t size)
{
gnrc_netif_hdr_t *hdr = pkt->data, *new_hdr;
sixlowpan_frag_t *frag_hdr;
gnrc_netif_hdr_t *netif_hdr = pkt->data, *new_netif_hdr;
gnrc_pktsnip_t *netif, *frag;

netif = gnrc_netif_hdr_build(gnrc_netif_hdr_get_src_addr(hdr), hdr->src_l2addr_len,
gnrc_netif_hdr_get_dst_addr(hdr), hdr->dst_l2addr_len);
netif = gnrc_netif_hdr_build(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);

if (netif == NULL) {
DEBUG("6lo frag: error allocating new link-layer header\n");
return NULL;
}

new_hdr = netif->data;
new_hdr->if_pid = hdr->if_pid;
new_hdr->flags = hdr->flags;
new_hdr->rssi = hdr->rssi;
new_hdr->lqi = hdr->lqi;
new_netif_hdr = netif->data;
new_netif_hdr->if_pid = netif_hdr->if_pid;
new_netif_hdr->flags = netif_hdr->flags;
new_netif_hdr->rssi = netif_hdr->rssi;
new_netif_hdr->lqi = netif_hdr->lqi;

frag = gnrc_pktbuf_add(NULL, NULL, _min(size, payload_len),
GNRC_NETTYPE_SIXLOWPAN);
Expand All @@ -78,30 +82,36 @@ static gnrc_pktsnip_t *_build_frag_pkt(gnrc_pktsnip_t *pkt, size_t payload_len,
gnrc_pktbuf_release(netif);
return NULL;
}
frag_hdr = frag->data;
/* XXX: truncation of datagram_size > 4095 may happen here */
frag_hdr->disp_size = byteorder_htons(fragment_msg->datagram_size);
frag_hdr->tag = byteorder_htons(fragment_msg->tag);


LL_PREPEND(frag, netif);

return frag;
}

static uint16_t _send_1st_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,
size_t payload_len, size_t datagram_size)
static uint16_t _send_1st_fragment(gnrc_netif_t *iface,
gnrc_sixlowpan_msg_frag_t *fragment_msg,
size_t payload_len)
{
gnrc_pktsnip_t *frag;
uint16_t local_offset = 0;
gnrc_pktsnip_t *frag, *pkt = fragment_msg->pkt;
sixlowpan_frag_t *hdr;
uint8_t *data;
/* payload_len: actual size of the packet vs
* datagram_size: size of the uncompressed IPv6 packet */
int payload_diff = (datagram_size - payload_len);
int payload_diff = (fragment_msg->datagram_size - payload_len);
uint16_t local_offset = 0;
/* virtually add payload_diff to flooring to account for offset (must be divisable by 8)
* in uncompressed datagram */
uint16_t max_frag_size = _floor8(iface->sixlo.max_frag_size + payload_diff -
sizeof(sixlowpan_frag_t)) - payload_diff;
sixlowpan_frag_t *hdr;
uint8_t *data;

DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size);

frag = _build_frag_pkt(pkt, payload_len,
frag = _build_frag_pkt(pkt, fragment_msg, payload_len,
max_frag_size + sizeof(sixlowpan_frag_t));

if (frag == NULL) {
Expand All @@ -110,10 +120,7 @@ static uint16_t _send_1st_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,

hdr = frag->next->data;
data = (uint8_t *)(hdr + 1);

hdr->disp_size = byteorder_htons((uint16_t)datagram_size);
hdr->disp_size.u8[0] |= SIXLOWPAN_FRAG_1_DISP;
hdr->tag = byteorder_htons(_tag);

/* Tell the link layer that we will send more fragments */
gnrc_netif_hdr_t *netif_hdr = frag->data;
Expand All @@ -136,26 +143,26 @@ static uint16_t _send_1st_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,

DEBUG("6lo frag: send first fragment (datagram size: %u, "
"datagram tag: %" PRIu16 ", fragment size: %" PRIu16 ")\n",
(unsigned int)datagram_size, _tag, local_offset);
fragment_msg->datagram_size, fragment_msg->tag, local_offset);
gnrc_sixlowpan_dispatch_send(frag, NULL, 0);
return local_offset;
}

static uint16_t _send_nth_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,
size_t payload_len, size_t datagram_size,
uint16_t offset)
static uint16_t _send_nth_fragment(gnrc_netif_t *iface,
gnrc_sixlowpan_msg_frag_t *fragment_msg,
size_t payload_len)
{
gnrc_pktsnip_t *frag;
gnrc_pktsnip_t *frag, *pkt = fragment_msg->pkt;
sixlowpan_frag_n_t *hdr;
uint8_t *data;
uint16_t local_offset = 0, offset_count = 0, offset = fragment_msg->offset;
/* since dispatches aren't supposed to go into subsequent fragments, we need not account
* for payload difference as for the first fragment */
uint16_t max_frag_size = _floor8(iface->sixlo.max_frag_size - sizeof(sixlowpan_frag_n_t));
uint16_t local_offset = 0, offset_count = 0;
sixlowpan_frag_n_t *hdr;
uint8_t *data;

DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size);

frag = _build_frag_pkt(pkt,
frag = _build_frag_pkt(pkt, fragment_msg,
payload_len - offset + sizeof(sixlowpan_frag_n_t),
max_frag_size + sizeof(sixlowpan_frag_n_t));

Expand All @@ -165,13 +172,10 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,

hdr = frag->next->data;
data = (uint8_t *)(hdr + 1);

/* XXX: truncation of datagram_size > 4095 may happen here */
hdr->disp_size = byteorder_htons((uint16_t)datagram_size);
hdr->disp_size.u8[0] |= SIXLOWPAN_FRAG_N_DISP;
hdr->tag = byteorder_htons(_tag);
/* don't mention payload diff in offset */
hdr->offset = (uint8_t)((offset + (datagram_size - payload_len)) >> 3);
hdr->offset = (uint8_t)((offset +
(fragment_msg->datagram_size - payload_len)) >> 3);
pkt = pkt->next; /* don't copy netif header */

while ((pkt != NULL) && (offset_count != offset)) { /* go to offset */
Expand Down Expand Up @@ -221,15 +225,20 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,
DEBUG("6lo frag: send subsequent fragment (datagram size: %u, "
"datagram tag: %" PRIu16 ", offset: %" PRIu8 " (%u bytes), "
"fragment size: %" PRIu16 ")\n",
(unsigned int)datagram_size, _tag, hdr->offset, hdr->offset << 3,
local_offset);
fragment_msg->datagram_size, fragment_msg->tag, hdr->offset,
hdr->offset << 3, local_offset);
gnrc_sixlowpan_dispatch_send(frag, NULL, 0);
return local_offset;
}

gnrc_sixlowpan_msg_frag_t *gnrc_sixlowpan_msg_frag_get(void)
{
return (_fragment_msg.pkt == NULL) ? &_fragment_msg : NULL;
for (unsigned i = 0; i < GNRC_SIXLOWPAN_MSG_FRAG_SIZE; i++) {
if (_fragment_msg[i].pkt == NULL) {
return &_fragment_msg[i];
}
}
return NULL;
}

void gnrc_sixlowpan_frag_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
Expand Down Expand Up @@ -259,20 +268,15 @@ void gnrc_sixlowpan_frag_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)

/* Check whether to send the first or an Nth fragment */
if (fragment_msg->offset == 0) {
/* increment tag for successive, fragmented datagrams */
_tag++;
if ((res = _send_1st_fragment(iface, fragment_msg->pkt, payload_len,
fragment_msg->datagram_size)) == 0) {
if ((res = _send_1st_fragment(iface, fragment_msg, payload_len)) == 0) {
/* error sending first fragment */
DEBUG("6lo frag: error sending 1st fragment\n");
goto error;
}
}
/* (offset + (datagram_size - payload_len) < datagram_size) simplified */
else if (fragment_msg->offset < payload_len) {
if ((res = _send_nth_fragment(iface, fragment_msg->pkt, payload_len,
fragment_msg->datagram_size,
fragment_msg->offset)) == 0) {
if ((res = _send_nth_fragment(iface, fragment_msg, payload_len)) == 0) {
/* error sending subsequent fragment */
DEBUG("6lo frag: error sending subsequent fragment"
"(offset = %u)\n", fragment_msg->offset);
Expand Down Expand Up @@ -320,6 +324,11 @@ void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
rbuf_add(hdr, pkt, offset, page);
}

uint16_t gnrc_sixlowpan_frag_next_tag(void)
{
return (++_current_tag);
}

void gnrc_sixlowpan_frag_rbuf_gc(void)
{
rbuf_gc();
Expand Down
1 change: 1 addition & 0 deletions sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ void gnrc_sixlowpan_multiplex_by_size(gnrc_pktsnip_t *pkt,
}
fragment_msg->pkt = pkt;
fragment_msg->datagram_size = orig_datagram_size;
fragment_msg->tag = gnrc_sixlowpan_frag_next_tag();
/* Sending the first fragment has an offset==0 */
fragment_msg->offset = 0;

Expand Down