mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-24 14:03:55 +01:00
Merge pull request #11021 from miri64/gnrc_sixlowpan_frag/enh/multiple-send
gnrc_sixlowpan_frag: allow send of multiple datagrams simultaneously
This commit is contained in:
commit
8fe12bc82c
@ -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
|
||||
*
|
||||
|
||||
@ -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;
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -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);
|
||||
@ -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) {
|
||||
@ -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;
|
||||
@ -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));
|
||||
|
||||
@ -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 */
|
||||
@ -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)
|
||||
@ -259,10 +268,7 @@ 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;
|
||||
@ -270,9 +276,7 @@ void gnrc_sixlowpan_frag_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
}
|
||||
/* (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);
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user