1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

gnrc_sixlowpan_frag: Initial import of a fragment size hint feature

This allows for sending of fragments smaller than the restrictions set
by the link-layer PDU. E.g. to put some slack for IPHC into the first
fragment (see https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-02#section-4.1).
This commit is contained in:
Martine Lenders 2019-02-25 16:41:27 +01:00 committed by Martine Lenders
parent 8fe12bc82c
commit 2534cfb3fa
5 changed files with 117 additions and 8 deletions

View File

@ -29,6 +29,7 @@ PSEUDOMODULES += gnrc_netif_dedup
PSEUDOMODULES += gnrc_sixloenc
PSEUDOMODULES += gnrc_sixlowpan_border_router_default
PSEUDOMODULES += gnrc_sixlowpan_default
PSEUDOMODULES += gnrc_sixlowpan_frag_hint
PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc
PSEUDOMODULES += gnrc_sixlowpan_nd_border_router
PSEUDOMODULES += gnrc_sixlowpan_router

View File

@ -32,6 +32,9 @@
#include "msg.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/netif/hdr.h"
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
#include "net/gnrc/sixlowpan/frag/hint.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
#include "net/gnrc/sixlowpan/internal.h"
#include "net/ieee802154.h"
#include "net/sixlowpan.h"
@ -94,6 +97,13 @@ typedef struct {
uint16_t tag; /**< Tag used for the fragment */
uint16_t offset; /**< Offset of the Nth fragment from the beginning of the
* payload datagram */
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
/**
* @brief Hint for the size (smaller than link-layer PDU) for the next
* fragment to sent
*/
gnrc_sixlowpan_frag_hint_t hint;
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
} gnrc_sixlowpan_msg_frag_t;
/**

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2019 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_hint Fragment size hint
* @ingroup net_gnrc_sixlowpan_frag
* @brief Provides a hint for smaller fragment sizes than the link-layer
* PDU for the next fragment to sent
* @{
*
* @file
* @brief Definitions to provide a hint on the final fragment size
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NET_GNRC_SIXLOWPAN_FRAG_HINT_H
#define NET_GNRC_SIXLOWPAN_FRAG_HINT_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief A fragment size hint
*/
typedef struct {
/**
* @brief Provides a hint of the size for the next fragment to send
*
* Set to 0 for fitting to the maximum fragment size of the interface the
* datagram is sent over.
*
* @see gnrc_netif_6lo_t::max_frag_size
*/
uint16_t fragsz;
/**
* @brief The size of the data bound by gnrc_sixlowpan_frag_hint_t::fragsz
* uncompressed
*
* This is only evaluated when gnrc_sixlowpan_frag_hint_t::fragsz is greater
* than 0.
* Required to calculate the proper offset for the next fragment.
*/
uint16_t fragsz_uncomp;
} gnrc_sixlowpan_frag_hint_t;
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_SIXLOWPAN_FRAG_HINT_H */
/** @} */

View File

@ -50,6 +50,32 @@ static inline size_t _min(size_t a, size_t b)
return (a < b) ? a : b;
}
static inline uint8_t _max_frag_size(gnrc_netif_t *iface,
gnrc_sixlowpan_msg_frag_t *fragment_msg)
{
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
if (fragment_msg->hint.fragsz > 0) {
/* account for rounding down to 8*/
return (fragment_msg->hint.fragsz & 0x7)
? (fragment_msg->hint.fragsz + 8U)
: fragment_msg->hint.fragsz;
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
(void)fragment_msg;
return iface->sixlo.max_frag_size;
}
static inline int _payload_diff(gnrc_sixlowpan_msg_frag_t *fragment_msg,
size_t payload_len)
{
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
if (fragment_msg->hint.fragsz > 0) {
return fragment_msg->hint.fragsz_uncomp - fragment_msg->hint.fragsz;
}
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
return (fragment_msg->datagram_size - payload_len);
}
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)
@ -57,6 +83,15 @@ static gnrc_pktsnip_t *_build_frag_pkt(gnrc_pktsnip_t *pkt,
sixlowpan_frag_t *frag_hdr;
gnrc_netif_hdr_t *netif_hdr = pkt->data, *new_netif_hdr;
gnrc_pktsnip_t *netif, *frag;
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
size_t fragment_size = ((fragment_msg->hint.fragsz > 0) &&
(fragment_msg->offset == 0))
? size /* we want the calculated fragment size
* to include full IPHC header */
: _min(size, payload_len);
#else /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
size_t fragment_size = _min(size, payload_len);
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
netif = gnrc_netif_hdr_build(gnrc_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len,
@ -74,8 +109,7 @@ static gnrc_pktsnip_t *_build_frag_pkt(gnrc_pktsnip_t *pkt,
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);
frag = gnrc_pktbuf_add(NULL, NULL, fragment_size, GNRC_NETTYPE_SIXLOWPAN);
if (frag == NULL) {
DEBUG("6lo frag: error allocating first fragment\n");
@ -102,12 +136,13 @@ static uint16_t _send_1st_fragment(gnrc_netif_t *iface,
uint8_t *data;
/* payload_len: actual size of the packet vs
* datagram_size: size of the uncompressed IPv6 packet */
int payload_diff = (fragment_msg->datagram_size - payload_len);
int payload_diff = _payload_diff(fragment_msg, 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;
uint16_t max_frag_size = _floor8(_max_frag_size(iface, fragment_msg) +
payload_diff - sizeof(sixlowpan_frag_t)) -
payload_diff;
DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size);
@ -158,7 +193,8 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *iface,
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 max_frag_size = _floor8(iface->sixlo.max_frag_size -
sizeof(sixlowpan_frag_n_t));
DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size);
@ -174,8 +210,8 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *iface,
data = (uint8_t *)(hdr + 1);
hdr->disp_size.u8[0] |= SIXLOWPAN_FRAG_N_DISP;
/* don't mention payload diff in offset */
hdr->offset = (uint8_t)((offset +
(fragment_msg->datagram_size - payload_len)) >> 3);
hdr->offset = (uint8_t)((offset + _payload_diff(fragment_msg,
payload_len)) >> 3);
pkt = pkt->next; /* don't copy netif header */
while ((pkt != NULL) && (offset_count != offset)) { /* go to offset */

View File

@ -134,6 +134,9 @@ void gnrc_sixlowpan_multiplex_by_size(gnrc_pktsnip_t *pkt,
fragment_msg->tag = gnrc_sixlowpan_frag_next_tag();
/* Sending the first fragment has an offset==0 */
fragment_msg->offset = 0;
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_HINT
fragment_msg->hint.fragsz = 0;
#endif
gnrc_sixlowpan_frag_send(pkt, fragment_msg, page);
}