From 2534cfb3fa7e71b691dfc5ed4be22e6d17ca39eb Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 25 Feb 2019 16:41:27 +0100 Subject: [PATCH] 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). --- makefiles/pseudomodules.inc.mk | 1 + sys/include/net/gnrc/sixlowpan/frag.h | 10 ++++ sys/include/net/gnrc/sixlowpan/frag/hint.h | 59 +++++++++++++++++++ .../sixlowpan/frag/gnrc_sixlowpan_frag.c | 52 +++++++++++++--- .../network_layer/sixlowpan/gnrc_sixlowpan.c | 3 + 5 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 sys/include/net/gnrc/sixlowpan/frag/hint.h diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 3f0b799ed412..e644489978f4 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -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 diff --git a/sys/include/net/gnrc/sixlowpan/frag.h b/sys/include/net/gnrc/sixlowpan/frag.h index df757c716902..71fb800e3bd7 100644 --- a/sys/include/net/gnrc/sixlowpan/frag.h +++ b/sys/include/net/gnrc/sixlowpan/frag.h @@ -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; /** diff --git a/sys/include/net/gnrc/sixlowpan/frag/hint.h b/sys/include/net/gnrc/sixlowpan/frag/hint.h new file mode 100644 index 000000000000..d5bd46a78690 --- /dev/null +++ b/sys/include/net/gnrc/sixlowpan/frag/hint.h @@ -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 + */ +#ifndef NET_GNRC_SIXLOWPAN_FRAG_HINT_H +#define NET_GNRC_SIXLOWPAN_FRAG_HINT_H + +#include + +#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 */ +/** @} */ diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c b/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c index b475ef03b80c..9953d72f0c04 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c @@ -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 */ diff --git a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c index 8a55b2912554..8741ba881429 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c +++ b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c @@ -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); }