Skip to content

Commit

Permalink
gnrc_sixlowpan_frag: Initial import of a fragment size hint feature
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
miri64 committed Apr 18, 2019
1 parent af77256 commit 8dd85ce
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 8 deletions.
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,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
Expand Down
10 changes: 10 additions & 0 deletions sys/include/net/gnrc/sixlowpan/frag.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) of the
* *first fragment*
*/
gnrc_sixlowpan_frag_hint_t hint;
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_HINT */
} gnrc_sixlowpan_msg_frag_t;

/**
Expand Down
59 changes: 59 additions & 0 deletions sys/include/net/gnrc/sixlowpan/frag/hint.h
Original file line number Diff line number Diff line change
@@ -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 *first fragment*.
* @{
*
* @file
* @brief Definitions to provide a hint on the final fragment size
*
* @author Martine Lenders <[email protected]>
*/
#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 */
/** @} */
52 changes: 44 additions & 8 deletions sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,48 @@ 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)
{
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,
Expand All @@ -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");
Expand All @@ -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);

Expand Down Expand Up @@ -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);

Expand All @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 8dd85ce

Please sign in to comment.