diff --git a/sys/include/net/gnrc/sixlowpan/frag/rb.h b/sys/include/net/gnrc/sixlowpan/frag/rb.h index 0affb6006d..996cbbc411 100644 --- a/sys/include/net/gnrc/sixlowpan/frag/rb.h +++ b/sys/include/net/gnrc/sixlowpan/frag/rb.h @@ -102,7 +102,8 @@ typedef struct { * @param[in] netif_hdr The interface header of the fragment, with * gnrc_netif_hdr_t::if_pid and its source and * destination address set. - * @param[in] frag The fragment to add. + * @param[in] frag The fragment to add. Will be released by the + * function. * @param[in] offset The fragment's offset. * @param[in] page Current 6Lo dispatch parsing page. * @@ -158,24 +159,6 @@ void gnrc_sixlowpan_frag_rb_base_rm(gnrc_sixlowpan_frag_rb_base_t *entry); */ void gnrc_sixlowpan_frag_rb_gc(void); -#if defined(MODULE_GNRC_SIXLOWPAN_FRAG_RB) || defined(DOXYGEN) -/** - * @brief Unsets a reassembly buffer entry (but does not free - * rbuf_t::super::pkt) - * - * @pre `rbuf != NULL` - * - * This functions sets rbuf_t::super::pkt to NULL and removes all rbuf::ints. - * - * @param[in] rbuf A reassembly buffer entry. Must not be NULL. - */ -static inline void gnrc_sixlowpan_frag_rb_remove(gnrc_sixlowpan_frag_rb_t *rbuf) -{ - assert(rbuf != NULL); - gnrc_sixlowpan_frag_rb_base_rm(&rbuf->super); - rbuf->pkt = NULL; -} - /** * @brief Checks if a reassembly buffer entry is complete and dispatches it * to the next layer if that is the case @@ -195,6 +178,24 @@ static inline void gnrc_sixlowpan_frag_rb_remove(gnrc_sixlowpan_frag_rb_t *rbuf) */ int gnrc_sixlowpan_frag_rb_dispatch_when_complete(gnrc_sixlowpan_frag_rb_t *rbuf, gnrc_netif_hdr_t *netif); + +#if defined(MODULE_GNRC_SIXLOWPAN_FRAG_RB) || defined(DOXYGEN) +/** + * @brief Unsets a reassembly buffer entry (but does not free + * rbuf_t::super::pkt) + * + * @pre `rbuf != NULL` + * + * This functions sets rbuf_t::super::pkt to NULL and removes all rbuf::ints. + * + * @param[in] rbuf A reassembly buffer entry. Must not be NULL. + */ +static inline void gnrc_sixlowpan_frag_rb_remove(gnrc_sixlowpan_frag_rb_t *rbuf) +{ + assert(rbuf != NULL); + gnrc_sixlowpan_frag_rb_base_rm(&rbuf->super); + rbuf->pkt = NULL; +} #else /* NOPs to be used with gnrc_sixlowpan_iphc if gnrc_sixlowpan_frag_rb is not * compiled in */ @@ -203,14 +204,6 @@ static inline void gnrc_sixlowpan_frag_rb_remove(gnrc_sixlowpan_frag_rb_t *rbuf) (void)rbuf; return; } - -static inline int gnrc_sixlowpan_frag_rb_dispatch_when_complete( - gnrc_sixlowpan_frag_rb_t *rbuf, gnrc_netif_hdr_t *netif) -{ - (void)rbuf; - (void)netif; - return -1; -} #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 4c418db811..0ade15e56d 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 @@ -339,8 +339,10 @@ error: void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page) { - gnrc_netif_hdr_t *hdr = pkt->next->data; + gnrc_pktsnip_t *netif_hdr = pkt->next; + gnrc_netif_hdr_t *hdr = netif_hdr->data; sixlowpan_frag_t *frag = pkt->data; + gnrc_sixlowpan_frag_rb_t *rbe; uint16_t offset = 0; (void)ctx; @@ -359,7 +361,14 @@ void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page) return; } - gnrc_sixlowpan_frag_rb_add(hdr, pkt, offset, page); + gnrc_pktbuf_hold(netif_hdr, 1); /* hold netif header to use it with + * dispatch_when_complete() + * (rb_add() releases `pkt`) */ + rbe = gnrc_sixlowpan_frag_rb_add(hdr, pkt, offset, page); + if (rbe != NULL) { + gnrc_sixlowpan_frag_rb_dispatch_when_complete(rbe, hdr); + } + gnrc_pktbuf_release(netif_hdr); } uint16_t gnrc_sixlowpan_frag_next_tag(void) diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c b/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c index a9af53786a..b7dc27dad1 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c @@ -223,27 +223,39 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, if (offset == 0) { #ifdef MODULE_GNRC_SIXLOWPAN_IPHC if (sixlowpan_iphc_is(data)) { + DEBUG("6lo rbuf: detected IPHC header.\n"); gnrc_pktsnip_t *frag_hdr = gnrc_pktbuf_mark(pkt, sizeof(sixlowpan_frag_t), GNRC_NETTYPE_SIXLOWPAN); if (frag_hdr == NULL) { + DEBUG("6lo rbuf: unable to mark fragment header. " + "aborting reassembly.\n"); gnrc_pktbuf_release(entry->pkt); gnrc_pktbuf_release(pkt); gnrc_sixlowpan_frag_rb_remove(entry); return RBUF_ADD_ERROR; } - gnrc_sixlowpan_iphc_recv(pkt, entry, 0); - return res; + else { + DEBUG("6lo rbuf: handing over to IPHC reception.\n"); + /* `pkt` released in IPHC */ + gnrc_sixlowpan_iphc_recv(pkt, entry, 0); + /* check if entry was deleted in IPHC (error case) */ + if (gnrc_sixlowpan_frag_rb_entry_empty(entry)) { + res = RBUF_ADD_ERROR; + } + return res; + } } else #endif if (data[0] == SIXLOWPAN_UNCOMP) { + DEBUG("6lo rbuf: detected uncompressed datagram\n"); data++; } } memcpy(((uint8_t *)entry->pkt->data) + offset, data, frag_size); } - gnrc_sixlowpan_frag_rb_dispatch_when_complete(entry, netif_hdr); + /* no errors and not consumed => release packet */ gnrc_pktbuf_release(pkt); return res; } diff --git a/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c b/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c index 4f007dead6..ce74a4da91 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c +++ b/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c @@ -582,7 +582,6 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, sixlo->size - payload_offset); if (rbuf != NULL) { rbuf->super.current_size += (uncomp_hdr_len - payload_offset); - gnrc_sixlowpan_frag_rb_dispatch_when_complete(rbuf, netif_hdr); } else { LL_DELETE(sixlo, netif); diff --git a/tests/gnrc_sixlowpan_frag/main.c b/tests/gnrc_sixlowpan_frag/main.c index b6efe1ff24..8d0e3e34ca 100644 --- a/tests/gnrc_sixlowpan_frag/main.c +++ b/tests/gnrc_sixlowpan_frag/main.c @@ -317,6 +317,7 @@ static void test_rbuf_add__success_complete(void) gnrc_pktsnip_t *pkt4 = gnrc_pktbuf_add(NULL, _fragment4, sizeof(_fragment4), GNRC_NETTYPE_SIXLOWPAN); gnrc_pktsnip_t *datagram; + gnrc_sixlowpan_frag_rb_t *entry1, *entry2; msg_t msg = { .type = 0U }; gnrc_netreg_entry_t reg = GNRC_NETREG_ENTRY_INIT_PID( GNRC_NETREG_DEMUX_CTX_ALL, @@ -326,20 +327,35 @@ static void test_rbuf_add__success_complete(void) gnrc_netreg_register(TEST_DATAGRAM_NETTYPE, ®); /* Mixing up things. Order decided by fair dice-rolls ;-) */ TEST_ASSERT_NOT_NULL(pkt2); - TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add( + TEST_ASSERT_NOT_NULL((entry1 = gnrc_sixlowpan_frag_rb_add( &_test_netif_hdr.hdr, pkt2, TEST_FRAGMENT2_OFFSET, TEST_PAGE + ))); + TEST_ASSERT_EQUAL_INT(0, gnrc_sixlowpan_frag_rb_dispatch_when_complete( + entry1, &_test_netif_hdr.hdr )); TEST_ASSERT_NOT_NULL(pkt4); - TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add( + TEST_ASSERT_NOT_NULL((entry2 = gnrc_sixlowpan_frag_rb_add( &_test_netif_hdr.hdr, pkt4, TEST_FRAGMENT4_OFFSET, TEST_PAGE + ))); + TEST_ASSERT(entry1 == entry2); + TEST_ASSERT_EQUAL_INT(0, gnrc_sixlowpan_frag_rb_dispatch_when_complete( + entry1, &_test_netif_hdr.hdr )); TEST_ASSERT_NOT_NULL(pkt1); - TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add( + TEST_ASSERT_NOT_NULL((entry2 = gnrc_sixlowpan_frag_rb_add( &_test_netif_hdr.hdr, pkt1, TEST_FRAGMENT1_OFFSET, TEST_PAGE + ))); + TEST_ASSERT(entry1 == entry2); + TEST_ASSERT_EQUAL_INT(0, gnrc_sixlowpan_frag_rb_dispatch_when_complete( + entry1, &_test_netif_hdr.hdr )); TEST_ASSERT_NOT_NULL(pkt3); - TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add( + TEST_ASSERT_NOT_NULL((entry2 = gnrc_sixlowpan_frag_rb_add( &_test_netif_hdr.hdr, pkt3, TEST_FRAGMENT3_OFFSET, TEST_PAGE + ))); + TEST_ASSERT(entry1 == entry2); + TEST_ASSERT(0 < gnrc_sixlowpan_frag_rb_dispatch_when_complete( + entry1, &_test_netif_hdr.hdr )); TEST_ASSERT_MESSAGE( xtimer_msg_receive_timeout(&msg, TEST_RECEIVE_TIMEOUT) >= 0,