diff --git a/Makefile.dep b/Makefile.dep index dd4dbcdfe4..1d5508bdf2 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -264,6 +264,11 @@ ifneq (,$(filter gnrc_rpl_srh,$(USEMODULE))) USEMODULE += gnrc_ipv6_ext_rh endif +ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE))) + USEMODULE += gnrc_ipv6_ext + USEMODULE += xtimer +endif + ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE))) USEMODULE += gnrc_ipv6_ext endif diff --git a/sys/include/net/gnrc/ipv6/ext.h b/sys/include/net/gnrc/ipv6/ext.h index 6524896d19..ee66c48dfb 100644 --- a/sys/include/net/gnrc/ipv6/ext.h +++ b/sys/include/net/gnrc/ipv6/ext.h @@ -29,6 +29,7 @@ #include "net/gnrc/pkt.h" #include "net/ipv6/ext.h" +#include "timex.h" #ifdef MODULE_GNRC_IPV6_EXT_RH #include "net/gnrc/ipv6/ext/rh.h" @@ -38,6 +39,45 @@ extern "C" { #endif +/** + * @defgroup net_gnrc_ipv6_ext_conf IPv6 extension header compile configurations + * @ingroup net_gnrc_ipv6_ext + * @ingroup config + * @{ + */ +/** + * @brief IPv6 fragmentation reassembly buffer size + * + * This limits the total amount of datagrams that can be reassembled at the same time. + * + * @note Only applicable with [gnrc_ipv6_ext_frag](@ref net_gnrc_ipv6_ext_frag) module + */ +#ifndef GNRC_IPV6_EXT_FRAG_RBUF_SIZE +#define GNRC_IPV6_EXT_FRAG_RBUF_SIZE (1U) +#endif + +/** + * @brief The number of total allocatable @ref gnrc_ipv6_ext_frag_limits_t objects + * + * This is the maximum number of receivable fragments, shared between all + * fragmented datagrams + * + * @note Only applicable with [gnrc_ipv6_ext_frag](@ref net_gnrc_ipv6_ext_frag) module + */ +#ifndef GNRC_IPV6_EXT_FRAG_LIMITS_POOL_SIZE +#define GNRC_IPV6_EXT_FRAG_LIMITS_POOL_SIZE (GNRC_IPV6_EXT_FRAG_RBUF_SIZE * 2U) +#endif + +/** + * @brief Timeout for IPv6 fragmentation reassembly buffer entries in microseconds + * + * @note Only applicable with [gnrc_ipv6_ext_frag](@ref net_gnrc_ipv6_ext_frag) module + */ +#ifndef GNRC_IPV6_EXT_FRAG_RBUF_TIMEOUT_US +#define GNRC_IPV6_EXT_FRAG_RBUF_TIMEOUT_US (10U * US_PER_SEC) +#endif +/** @} **/ + /** * @brief Builds an extension header for sending. * diff --git a/sys/include/net/gnrc/ipv6/ext/frag.h b/sys/include/net/gnrc/ipv6/ext/frag.h new file mode 100644 index 0000000000..397e617c48 --- /dev/null +++ b/sys/include/net/gnrc/ipv6/ext/frag.h @@ -0,0 +1,147 @@ +/* + * 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_ipv6_ext_frag Support for IPv6 fragmentation extension + * @ingroup net_gnrc_ipv6_ext + * @brief GNRC implementation of IPv6 fragmentation extension + * @{ + * + * @file + * @brief GNRC fragmentation extension definitions + * + * @author Martine Lenders + */ +#ifndef NET_GNRC_IPV6_EXT_FRAG_H +#define NET_GNRC_IPV6_EXT_FRAG_H + +#include + +#include "clist.h" +#include "net/gnrc/pkt.h" +#include "net/gnrc/pktbuf.h" +#include "net/ipv6/hdr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Message type to time reassembly buffer garbage collection + */ +#define GNRC_IPV6_EXT_FRAG_RBUF_GC (0xfe00U) + +/** + * @brief Data type to describe limits of a single fragment in the reassembly + * buffer + */ +typedef struct gnrc_ipv6_ext_frag_limits { + struct gnrc_ipv6_ext_frag_limits *next; /**< limits of next fragment */ + uint16_t start; /**< the start (= offset) of the fragment */ + uint16_t end; /**< the exclusive end (= offset + length) of the + * fragment */ +} gnrc_ipv6_ext_frag_limits_t; + +/** + * @brief A reassembly buffer entry + */ +typedef struct { + gnrc_pktsnip_t *pkt; /**< the (partly) reassembled packet */ + ipv6_hdr_t *ipv6; /**< the IPv6 header of gnrc_ipv6_ext_frag_rbuf_t::pkt */ + /** + * @brief The limits of the fragments in the reassembled packet + * + * @note Members of this list can be cast to gnrc_ipv6_ext_frag_limits_t. + */ + clist_node_t limits; + uint32_t id; /**< the identification from the fragment headers */ + uint32_t arrival; /**< arrival time of last received fragment */ + uint16_t pkt_len; /**< length of gnrc_ipv6_ext_frag_rbuf_t::pkt */ + uint8_t last; /**< received last fragment */ +} gnrc_ipv6_ext_frag_rbuf_t; + +/** + * @brief Initializes IPv6 fragmentation and reassembly + * @internal + */ +void gnrc_ipv6_ext_frag_init(void); + +/** + * @brief Reassemble fragmented IPv6 packet + * + * @param[in] pkt A fragment of the IPv6 packet to be reassembled containing + * the fragment header in the first snip. + * + * @return The reassembled packet when @p pkt completed the reassembly + * @return NULL, when there are still fragments missing or an error occured + * during reassembly + */ +gnrc_pktsnip_t *gnrc_ipv6_ext_frag_reass(gnrc_pktsnip_t *pkt); + +/** + * @name Reassembly buffer operations + * @{ + */ +/** + * @brief Get a reassembly buffer by the identifying parameters + * + * @internal + * @see [RFC 8200, section 4.5](https://tools.ietf.org/html/rfc8200#section-4.5) + * + * @param[in] hdr IPv6 header to get source and destination address from. + * @param[in] id The identification from the fragment header. + * + * @return A reassembly buffer matching @p id ipv6_hdr_t::src and ipv6_hdr::dst + * of @p hdr or first free reassembly buffer. Will never be NULL, as + * in the case of the reassembly buffer being full, the entry with the + * lowest gnrc_ipv6_ext_frag_rbuf_t::arrival (serial-number-like) is + * removed. + */ +gnrc_ipv6_ext_frag_rbuf_t *gnrc_ipv6_ext_frag_rbuf_get(ipv6_hdr_t *ipv6, + uint32_t id); + +/** + * @brief Frees a reassembly buffer entry (but does not release its + * gnrc_ipv6_ext_frag_rbuf_t::pkt) + * + * @param[in] rbuf A reassembly buffer entry. + */ +void gnrc_ipv6_ext_frag_rbuf_free(gnrc_ipv6_ext_frag_rbuf_t *rbuf); + +/** + * @brief Delete a reassembly buffer entry (and release its + * gnrc_ipv6_ext_frag_rbuf_t::pkt) + * + * @note May be used by the IPv6 thread to remove a timed out reassembly + * buffer entry. + * + * @param[in] rbuf A reassembly buffer entry. + */ +static inline void gnrc_ipv6_ext_frag_rbuf_del(gnrc_ipv6_ext_frag_rbuf_t *rbuf) +{ + gnrc_pktbuf_release(rbuf->pkt); + rbuf->pkt = NULL; + gnrc_ipv6_ext_frag_rbuf_free(rbuf); +} + +/** + * @brief Garbage-collect reassembly buffer + * + * This calls @ref gnrc_ipv6_ext_frag_rbuf_del() for all reassembly buffer + * entries for which * gnrc_ipv6_ext_frag_rbuf_t::arrival is + * @ref GNRC_IPV6_EXT_FRAG_RBUF_TIMEOUT_US in the past. + */ +void gnrc_ipv6_ext_frag_rbuf_gc(void); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NET_GNRC_IPV6_EXT_FRAG_H */ +/** @} */ diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index 434f234ee3..d26036d5af 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -13,6 +13,9 @@ endif ifneq (,$(filter gnrc_ipv6_ext,$(USEMODULE))) DIRS += network_layer/ipv6/ext endif +ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE))) + DIRS += network_layer/ipv6/ext/frag +endif ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE))) DIRS += network_layer/ipv6/ext/rh endif diff --git a/sys/net/gnrc/network_layer/ipv6/ext/frag/Makefile b/sys/net/gnrc/network_layer/ipv6/ext/frag/Makefile new file mode 100644 index 0000000000..51f1ac0b6f --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/ext/frag/Makefile @@ -0,0 +1,3 @@ +MODULE := gnrc_ipv6_ext_frag + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c b/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c new file mode 100644 index 0000000000..ef1b7ea0da --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c @@ -0,0 +1,401 @@ +/* + * 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. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders + */ + +#include + +#include "byteorder.h" +#include "net/ipv6/ext/frag.h" +#include "net/ipv6/addr.h" +#include "net/gnrc/ipv6/ext.h" +#include "net/gnrc/pktbuf.h" +#include "sched.h" +#include "xtimer.h" + +#include "net/gnrc/ipv6/ext/frag.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static gnrc_ipv6_ext_frag_rbuf_t _rbuf[GNRC_IPV6_EXT_FRAG_RBUF_SIZE]; +static gnrc_ipv6_ext_frag_limits_t _limits_pool[GNRC_IPV6_EXT_FRAG_LIMITS_POOL_SIZE]; +static clist_node_t _free_limits; +static xtimer_t _gc_xtimer; +static msg_t _gc_msg = { .type = GNRC_IPV6_EXT_FRAG_RBUF_GC }; + +typedef enum { + FRAG_LIMITS_NEW = 0, /**< limits are not present and do not overlap */ + FRAG_LIMITS_DUPLICATE, /**< fragment limits are already present */ + FRAG_LIMITS_OVERLAP, /**< limits overlap */ + FRAG_LIMITS_FULL, /**< no free gnrc_ipv6_ext_frag_limits_t object */ +} _limits_res_t; + +void gnrc_ipv6_ext_frag_init(void) +{ +#ifdef TEST_SUITES + memset(_rbuf, 0, sizeof(_rbuf)); +#endif + for (unsigned i = 0; i < GNRC_IPV6_EXT_FRAG_LIMITS_POOL_SIZE; i++) { + clist_rpush(&_free_limits, (clist_node_t *)&_limits_pool[i]); + } +} + +/* + * =============== + * IPv6 reassembly + * =============== + */ + +/** + * @brief Initializes a reassembly buffer entry + * + * @param[in] rbuf A reassembly buffer entry. + * @param[in] ipv6 The IPv6 header for the reassembly buffer entry. + * @param[in] id The identification from the fragment header. + */ +static inline void _init_rbuf(gnrc_ipv6_ext_frag_rbuf_t *rbuf, ipv6_hdr_t *ipv6, + uint32_t id); + +/** + * @brief Checks if given fragment limits overlap with fragment limits already + * in a given reassembly buffer entry + * + * If no overlap exists the new limits are added to @p rbuf. + * + * @param[in, out] rbuf A reassembly buffer entry. + * @param[in] offset A fragment offset. + * @param[in] pkt_len The length of the packet. + * + * @return see _limits_res_t. + */ +static _limits_res_t _overlaps(gnrc_ipv6_ext_frag_rbuf_t *rbuf, + unsigned offset, unsigned pkt_len); + +/** + * @brief Sets the next header field of a header. + * + * @pre `hdr_snip->type` $\in$ {GNRC_NETTYPE_IPV6, GNRC_NETTYPE_IPV6_EXT} + * + * @param[in] hdr_snip A header + * @param[in] nh A protocol number + */ +static inline void _set_nh(gnrc_pktsnip_t *hdr_snip, uint8_t nh); + +/** + * @brief Checks if a fragmented packet is completely reassembled. + * + * @param[in] rbuf A reassembly buffer entry. + * + * @return The reassembled packet on if it is completed. + * @return NULL, if the packet is not completely reassembled yet + */ +static gnrc_pktsnip_t *_completed(gnrc_ipv6_ext_frag_rbuf_t *rbuf); + +gnrc_pktsnip_t *gnrc_ipv6_ext_frag_reass(gnrc_pktsnip_t *pkt) +{ + gnrc_ipv6_ext_frag_rbuf_t *rbuf; + gnrc_pktsnip_t *fh_snip, *ipv6_snip; + ipv6_hdr_t *ipv6; + ipv6_ext_frag_t *fh; + unsigned offset; + uint8_t nh; + + fh_snip = gnrc_pktbuf_mark(pkt, sizeof(ipv6_ext_frag_t), + GNRC_NETTYPE_IPV6_EXT); + if (fh_snip == NULL) { + DEBUG("ipv6_ext_frag: unable to mark fragmentation header\n"); + goto error_release; + } + fh = fh_snip->data; + /* search IPv6 header */ + ipv6_snip = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); + assert(ipv6_snip != NULL); + ipv6 = ipv6_snip->data; + rbuf = gnrc_ipv6_ext_frag_rbuf_get(ipv6, byteorder_ntohl(fh->id)); + if (rbuf == NULL) { + DEBUG("ipv6_ext_frag: reassembly buffer full\n"); + goto error_release; + } + rbuf->arrival = xtimer_now_usec(); + xtimer_set_msg(&_gc_xtimer, GNRC_IPV6_EXT_FRAG_RBUF_TIMEOUT_US, &_gc_msg, + sched_active_pid); + nh = fh->nh; + offset = ipv6_ext_frag_get_offset(fh); + switch (_overlaps(rbuf, offset, pkt->size)) { + case FRAG_LIMITS_NEW: + break; + case FRAG_LIMITS_DUPLICATE: + gnrc_pktbuf_release(pkt); + return NULL; + case FRAG_LIMITS_OVERLAP: + DEBUG("ipv6_ext_frag: fragment overlaps with existing fragments\n"); + /* intentionally falls through */ + case FRAG_LIMITS_FULL: + default: + DEBUG("ipv6_ext_frag: can't store fragment limits\n"); + goto error_exit; + } + if (offset > 0) { + size_t size_until = offset + pkt->size; + + /* use IPv6 header in reassembly buffer from here on */ + ipv6 = rbuf->ipv6; + /* subsequent fragment */ + if (!ipv6_ext_frag_more(fh)) { + /* last fragment; add to rbuf->pkt_len */ + rbuf->last++; + rbuf->pkt_len += size_until; + } + /* not divisible by 8 */ + else if ((pkt->size & 0x7)) { + DEBUG("ipv6_ext_frag: fragment length not divisible by 8"); + goto error_exit; + } + if (rbuf->pkt == NULL) { + rbuf->pkt = gnrc_pktbuf_add(fh_snip->next, NULL, size_until, + GNRC_NETTYPE_UNDEF); + if (rbuf->pkt == NULL) { + DEBUG("ipv6_ext_frag: unable to create space for reassembled " + "packet\n"); + goto error_exit; + } + } + else if (rbuf->pkt->size < size_until) { + if (gnrc_pktbuf_realloc_data(rbuf->pkt, size_until) != 0) { + DEBUG("ipv6_ext_frag: unable to allocate space for reassembled " + "packet\n"); + goto error_exit; + } + } + memcpy(((uint8_t *)rbuf->pkt->data) + offset, pkt->data, pkt->size); + /* we don't need the rest anymore */ + gnrc_pktbuf_release(pkt); + return _completed(rbuf); + } + else if (!ipv6_ext_frag_more(fh)) { + /* first fragment but actually not fragmented */ + _set_nh(fh_snip->next, nh); + gnrc_pktbuf_remove_snip(pkt, fh_snip); + gnrc_ipv6_ext_frag_rbuf_del(rbuf); + ipv6->len = byteorder_htons(byteorder_ntohs(ipv6->len) - + sizeof(ipv6_ext_frag_t)); + return pkt; + } + else { + /* first fragment */ + uint16_t ipv6_len = byteorder_ntohs(ipv6->len); + + /* not divisible by 8*/ + if ((pkt->size & 0x7)) { + DEBUG("ipv6_ext_frag: fragment length not divisible by 8"); + goto error_exit; + } + _set_nh(fh_snip->next, nh); + gnrc_pktbuf_remove_snip(pkt, fh_snip); + /* TODO: RFC 8200 says "- 8"; determine if `sizeof(ipv6_ext_frag_t)` is + * really needed*/ + rbuf->pkt_len += ipv6_len - pkt->size - sizeof(ipv6_ext_frag_t); + if (rbuf->pkt != NULL) { + /* first fragment but not first arriving */ + memcpy(rbuf->pkt->data, pkt->data, pkt->size); + rbuf->pkt->next = pkt->next; + rbuf->pkt->type = pkt->type; + /* payload was copied to reassembly buffer so remove it */ + gnrc_pktbuf_remove_snip(pkt, pkt); + rbuf->ipv6 = ipv6; + return _completed(rbuf); + } + else { + /* first fragment but first arriving */ + rbuf->pkt = pkt; + } + } + return NULL; +error_exit: + gnrc_ipv6_ext_frag_rbuf_del(rbuf); +error_release: + gnrc_pktbuf_release(pkt); + return NULL; +} + +gnrc_ipv6_ext_frag_rbuf_t *gnrc_ipv6_ext_frag_rbuf_get(ipv6_hdr_t *ipv6, + uint32_t id) +{ + gnrc_ipv6_ext_frag_rbuf_t *res = NULL, *oldest = NULL; + for (unsigned i = 0; i < GNRC_IPV6_EXT_FRAG_RBUF_SIZE; i++) { + gnrc_ipv6_ext_frag_rbuf_t *tmp = &_rbuf[i]; + if (tmp->ipv6 != NULL) { + if ((tmp->id == id) && + ipv6_addr_equal(&tmp->ipv6->src, &ipv6->src) && + ipv6_addr_equal(&tmp->ipv6->dst, &ipv6->dst)) { + return tmp; + } + } + else if (res == NULL) { + res = tmp; + _init_rbuf(res, ipv6, id); + } + if ((oldest == NULL) || + /* xtimer_now_usec() overflows every ~1.2 hours */ + ((tmp->arrival - oldest->arrival) < (UINT32_MAX / 2))) { + oldest = tmp; + } + } + if (res == NULL) { + assert(oldest != NULL); /* reassembly buffer is full, so there needs + * to be an oldest entry */ + DEBUG("ipv6_ext_frag: dropping oldest entry\n"); + gnrc_ipv6_ext_frag_rbuf_del(oldest); + res = oldest; + _init_rbuf(res, ipv6, id); + } + return res; +} + +void gnrc_ipv6_ext_frag_rbuf_free(gnrc_ipv6_ext_frag_rbuf_t *rbuf) +{ + rbuf->ipv6 = NULL; + while (rbuf->limits.next != NULL) { + clist_node_t *tmp = clist_lpop(&rbuf->limits); + clist_rpush(&_free_limits, tmp); + } +} + +void gnrc_ipv6_ext_frag_rbuf_gc(void) +{ + uint32_t now = xtimer_now_usec(); + for (unsigned i = 0; i < GNRC_IPV6_EXT_FRAG_RBUF_SIZE; i++) { + gnrc_ipv6_ext_frag_rbuf_t *rbuf = &_rbuf[i]; + if ((now - rbuf->arrival) > GNRC_IPV6_EXT_FRAG_RBUF_TIMEOUT_US) { + gnrc_ipv6_ext_frag_rbuf_del(rbuf); + } + } +} + +typedef struct { + uint16_t start; + uint16_t end; +} _check_limits_t; + +static inline void _init_rbuf(gnrc_ipv6_ext_frag_rbuf_t *rbuf, ipv6_hdr_t *ipv6, + uint32_t id) +{ + rbuf->ipv6 = ipv6; + rbuf->id = id; + rbuf->pkt_len = 0; + rbuf->last = 0; +} + +static int _check_overlap(clist_node_t *node, void *arg) +{ + _check_limits_t *limits = arg; + gnrc_ipv6_ext_frag_limits_t *cur = (gnrc_ipv6_ext_frag_limits_t *)node; + + return ((cur->start < limits->end) && (limits->start < cur->end)); +} + +static int _limits_cmp(clist_node_t *a, clist_node_t *b) +{ + gnrc_ipv6_ext_frag_limits_t *al = (gnrc_ipv6_ext_frag_limits_t *)a; + gnrc_ipv6_ext_frag_limits_t *bl = (gnrc_ipv6_ext_frag_limits_t *)b; + + return (int)al->start - (int)bl->start; +} + +static _limits_res_t _overlaps(gnrc_ipv6_ext_frag_rbuf_t *rbuf, + unsigned offset, unsigned pkt_len) +{ + _check_limits_t limits = { .start = offset >> 3U, + .end = (offset + pkt_len) >> 3U }; + gnrc_ipv6_ext_frag_limits_t *res; + + if (limits.start == limits.end) { + /* might happen with last fragment */ + limits.end++; + } + res = (gnrc_ipv6_ext_frag_limits_t *)clist_foreach(&rbuf->limits, + _check_overlap, + &limits); + if (res == NULL) { + res = (gnrc_ipv6_ext_frag_limits_t *)clist_lpop(&_free_limits); + if (res != NULL) { + res->start = limits.start; + res->end = limits.end; + clist_rpush(&rbuf->limits, (clist_node_t *)res); + clist_sort(&rbuf->limits, _limits_cmp); + return FRAG_LIMITS_NEW; + } + else { + return FRAG_LIMITS_FULL; + } + } + else if ((res->start == limits.start) && (res->end == limits.end)) { + return FRAG_LIMITS_DUPLICATE; + } + else { + return FRAG_LIMITS_NEW; + } +} + +static inline void _set_nh(gnrc_pktsnip_t *hdr_snip, uint8_t nh) +{ + switch (hdr_snip->type) { + case GNRC_NETTYPE_IPV6: { + ipv6_hdr_t *hdr = hdr_snip->data; + hdr->nh = nh; + break; + } + case GNRC_NETTYPE_IPV6_EXT: { + ipv6_ext_t *hdr = hdr_snip->data; + hdr->nh = nh; + break; + } + default: + /* should not happen */ + assert(false); + break; + } +} + +static gnrc_pktsnip_t *_completed(gnrc_ipv6_ext_frag_rbuf_t *rbuf) +{ + assert(rbuf->limits.next != NULL); /* this function is only called when + * at least one fragment was already + * added */ + /* clist: first element is second element ;-) (from next of head) */ + gnrc_ipv6_ext_frag_limits_t *ptr = + (gnrc_ipv6_ext_frag_limits_t *)rbuf->limits.next->next; + if (rbuf->last && (ptr->start == 0)) { + gnrc_pktsnip_t *res = NULL; + + /* last and first fragment were received, so check if everything + * in-between is there */ + do { + gnrc_ipv6_ext_frag_limits_t *next = ptr->next; + if (ptr->end < next->start) { + return NULL; + } + ptr = next; + } while (((clist_node_t *)ptr) != rbuf->limits.next); + res = rbuf->pkt; + /* rewrite length */ + rbuf->ipv6->len = byteorder_htons(rbuf->pkt_len); + rbuf->pkt = NULL; + gnrc_ipv6_ext_frag_rbuf_free(rbuf); + return res; + } + return NULL; +} + +/** @} */ diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index 06cc0fbbb9..886088b597 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -32,6 +32,10 @@ #include "net/gnrc/ipv6/whitelist.h" #include "net/gnrc/ipv6/blacklist.h" +#ifdef MODULE_GNRC_IPV6_EXT_FRAG +#include "net/gnrc/ipv6/ext/frag.h" +#endif + #include "net/gnrc/ipv6.h" #define ENABLE_DEBUG (0) @@ -171,6 +175,10 @@ static void *_event_loop(void *args) (void)args; msg_init_queue(msg_q, GNRC_IPV6_MSG_QUEUE_SIZE); + /* initialize fragmentation data-structures */ +#ifdef MODULE_GNRC_IPV6_EXT_FRAG + gnrc_ipv6_ext_frag_init(); +#endif /* MODULE_GNRC_IPV6_EXT_FRAG */ /* register interest in all IPv6 packets */ gnrc_netreg_register(GNRC_NETTYPE_IPV6, &me_reg); @@ -200,6 +208,11 @@ static void *_event_loop(void *args) msg_reply(&msg, &reply); break; +#ifdef MODULE_GNRC_IPV6_EXT_FRAG + case GNRC_IPV6_EXT_FRAG_RBUF_GC: + gnrc_ipv6_ext_frag_rbuf_gc(); + break; +#endif /* MODULE_GNRC_IPV6_EXT_FRAG */ case GNRC_IPV6_NIB_SND_UC_NS: case GNRC_IPV6_NIB_SND_MC_NS: case GNRC_IPV6_NIB_SND_NA: