diff --git a/sys/include/net/gnrc/sixlowpan/frag.h b/sys/include/net/gnrc/sixlowpan/frag.h index 0448ac71b6..1e5a81ab0d 100644 --- a/sys/include/net/gnrc/sixlowpan/frag.h +++ b/sys/include/net/gnrc/sixlowpan/frag.h @@ -31,6 +31,7 @@ #include "byteorder.h" #include "kernel_types.h" #include "net/gnrc/pkt.h" +#include "net/gnrc/netif/hdr.h" #include "net/ieee802154.h" #include "net/sixlowpan.h" @@ -131,7 +132,39 @@ void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page); /** * @brief Garbage collect reassembly buffer. */ -void gnrc_sixlowpan_frag_gc_rbuf(void); +void gnrc_sixlowpan_frag_rbuf_gc(void); + +#if defined(MODULE_GNRC_SIXLOWPAN_FRAG) || defined(DOXYGEN) +/** + * @brief Removes an entry from the reassembly buffer + * + * @pre `rbuf != NULL` + * + * @param[in] rbuf A reassembly buffer entry. Must not be NULL. + */ +void gnrc_sixlowpan_frag_rbuf_remove(gnrc_sixlowpan_rbuf_t *rbuf); + +/** + * @brief Checks if a reassembly buffer entry is complete and dispatches it + * to the next layer if that is the case + * + * @pre `rbuf != NULL` + * @pre `netif != NULL` + * + * @param[in] rbuf A reassembly buffer entry. Must not be NULL. + * @param[in] netif Original @ref gnrc_netif_hdr_t of the last received frame. + * Used to construct the @ref gnrc_netif_hdr_t of the completed + * datagram. Must not be NULL. + */ +void gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(gnrc_sixlowpan_rbuf_t *rbuf, + gnrc_netif_hdr_t *netif); +#else +/* NOPs to be used with gnrc_sixlowpan_iphc if gnrc_sixlowpan_frag is not + * compiled in */ +#define gnrc_sixlowpan_frag_rbuf_remove(rbuf) (void)(rbuf) +#define gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(rbuf, netif) \ + (void)(rbuf); (void)(netif) +#endif #ifdef __cplusplus } 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 03ac3db6f4..b06e465038 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 @@ -320,9 +320,48 @@ void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page) gnrc_pktbuf_release(pkt); } -void gnrc_sixlowpan_frag_gc_rbuf(void) +void gnrc_sixlowpan_frag_rbuf_gc(void) { rbuf_gc(); } +void gnrc_sixlowpan_frag_rbuf_remove(gnrc_sixlowpan_rbuf_t *rbuf) +{ + assert(rbuf != NULL); + rbuf_rm((rbuf_t *)rbuf); +} + +void gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(gnrc_sixlowpan_rbuf_t *rbuf, + gnrc_netif_hdr_t *netif_hdr) +{ + assert(rbuf); + assert(netif_hdr); + if (rbuf->current_size == rbuf->pkt->size) { + gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(rbuf->src, + rbuf->src_len, + rbuf->dst, + rbuf->dst_len); + + if (netif == NULL) { + DEBUG("6lo rbuf: error allocating netif header\n"); + gnrc_pktbuf_release(rbuf->pkt); + gnrc_sixlowpan_frag_rbuf_remove(rbuf); + return; + } + + /* copy the transmit information of the latest fragment into the newly + * created header to have some link_layer information. The link_layer + * info of the previous fragments is discarded. + */ + gnrc_netif_hdr_t *new_netif_hdr = netif->data; + new_netif_hdr->if_pid = netif_hdr->if_pid; + new_netif_hdr->flags = netif_hdr->flags; + new_netif_hdr->lqi = netif_hdr->lqi; + new_netif_hdr->rssi = netif_hdr->rssi; + LL_APPEND(rbuf->pkt, netif); + gnrc_sixlowpan_dispatch_recv(rbuf->pkt, NULL, 0); + gnrc_sixlowpan_frag_rbuf_remove(rbuf); + } +} + /** @} */ diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.c b/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.c index 451edd4be0..115e71d010 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.c @@ -58,8 +58,6 @@ static msg_t _gc_timer_msg = { .type = GNRC_SIXLOWPAN_MSG_FRAG_GC_RBUF }; static inline bool _rbuf_int_overlap_partially(rbuf_int_t *i, uint16_t start, uint16_t end); /* gets a free entry from interval buffer */ static rbuf_int_t *_rbuf_int_get_free(void); -/* remove entry from reassembly buffer */ -static void _rbuf_rem(rbuf_t *entry); /* update interval buffer of entry */ static bool _rbuf_update_ints(rbuf_t *entry, uint16_t offset, size_t frag_size); /* gets an entry identified by its tupel */ @@ -108,7 +106,7 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, if (iphc_len == 0) { DEBUG("6lo rfrag: could not decode IPHC dispatch\n"); gnrc_pktbuf_release(entry->super.pkt); - _rbuf_rem(entry); + rbuf_rm(entry); return; } data += iphc_len; /* take remaining data as data */ @@ -127,7 +125,7 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, if ((offset + frag_size) > entry->super.pkt->size) { DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n"); gnrc_pktbuf_release(entry->super.pkt); - _rbuf_rem(entry); + rbuf_rm(entry); return; } @@ -138,7 +136,7 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) { DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n"); gnrc_pktbuf_release(entry->super.pkt); - _rbuf_rem(entry); + rbuf_rm(entry); /* "A fresh reassembly may be commenced with the most recently * received link fragment" @@ -158,32 +156,7 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, frag_size - data_offset); } - if (entry->super.current_size == entry->super.pkt->size) { - gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(entry->super.src, - entry->super.src_len, - entry->super.dst, - entry->super.dst_len); - - if (netif == NULL) { - DEBUG("6lo rbuf: error allocating netif header\n"); - gnrc_pktbuf_release(entry->super.pkt); - _rbuf_rem(entry); - return; - } - - /* copy the transmit information of the latest fragment into the newly - * created header to have some link_layer information. The link_layer - * info of the previous fragments is discarded. - */ - gnrc_netif_hdr_t *new_netif_hdr = netif->data; - new_netif_hdr->if_pid = netif_hdr->if_pid; - new_netif_hdr->flags = netif_hdr->flags; - new_netif_hdr->lqi = netif_hdr->lqi; - new_netif_hdr->rssi = netif_hdr->rssi; - LL_APPEND(entry->super.pkt, netif); - gnrc_sixlowpan_dispatch_recv(entry->super.pkt, NULL, 0); - _rbuf_rem(entry); - } + gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(&entry->super, netif_hdr); } static inline bool _rbuf_int_overlap_partially(rbuf_int_t *i, uint16_t start, uint16_t end) @@ -204,7 +177,7 @@ static rbuf_int_t *_rbuf_int_get_free(void) return NULL; } -static void _rbuf_rem(rbuf_t *entry) +void rbuf_rm(rbuf_t *entry) { while (entry->ints != NULL) { rbuf_int_t *next = entry->ints->next; @@ -267,7 +240,7 @@ void rbuf_gc(void) (unsigned)rbuf[i].super.pkt->size, rbuf[i].super.tag); gnrc_pktbuf_release(rbuf[i].super.pkt); - _rbuf_rem(&(rbuf[i])); + rbuf_rm(&(rbuf[i])); } } } @@ -324,7 +297,7 @@ static rbuf_t *_rbuf_get(const void *src, size_t src_len, assert(oldest->super.pkt != NULL); DEBUG("6lo rfrag: reassembly buffer full, remove oldest entry\n"); gnrc_pktbuf_release(oldest->super.pkt); - _rbuf_rem(oldest); + rbuf_rm(oldest); res = oldest; } diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.h b/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.h index 810ad2fcdb..d33103a267 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.h +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.h @@ -89,6 +89,8 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *frag, */ void rbuf_gc(void); +void rbuf_rm(rbuf_t *rbuf); + #ifdef __cplusplus } #endif diff --git a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c index 0b947b9f9f..bc1ff176fd 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c +++ b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c @@ -377,7 +377,7 @@ static void *_event_loop(void *args) break; case GNRC_SIXLOWPAN_MSG_FRAG_GC_RBUF: DEBUG("6lo: garbage collect reassembly buffer event received\n"); - gnrc_sixlowpan_frag_gc_rbuf(); + gnrc_sixlowpan_frag_rbuf_gc(); break; #endif