diff --git a/sys/include/net/gnrc/sixlowpan/frag/rb.h b/sys/include/net/gnrc/sixlowpan/frag/rb.h index b66b1d31d1..76091e270e 100644 --- a/sys/include/net/gnrc/sixlowpan/frag/rb.h +++ b/sys/include/net/gnrc/sixlowpan/frag/rb.h @@ -114,6 +114,45 @@ gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_add(gnrc_netif_hdr_t *netif_hdr gnrc_pktsnip_t *frag, size_t offset, unsigned page); +/** + * @brief Checks if a reassembly buffer entry with a given link-layer address + * pair and tag exists + * + * @pre `netif_hdr != NULL` + * + * @param[in] netif_hdr An interface header to provide the (source, destination) + * link-layer address pair. Must not be NULL. + * @param[in] tag Tag to search for. + * + * @note datagram_size is not a search parameter as the primary use case + * for this function is [Selective Fragment Recovery] + * (https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05) + * where this information only exists in the first fragment. + * + * @return true, if an entry with the given tuple exist. + * @return false, if no entry with the given tuple exist. + */ +bool gnrc_sixlowpan_frag_rb_exists(const gnrc_netif_hdr_t *netif_hdr, + uint16_t tag); + +/** + * @brief Removes a reassembly buffer entry with a given link-layer address + * pair and tag + * + * @pre `netif_hdr != NULL` + * + * @param[in] netif_hdr An interface header to provide the (source, destination) + * link-layer address pair. Must not be NULL. + * @param[in] tag Tag to search for. + * + * @note datagram_size is not a search parameter as the primary use case + * for this function is [Selective Fragment Recovery] + * (https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-05) + * where this information only exists in the first fragment. + */ +void gnrc_sixlowpan_frag_rb_rm_by_datagram(const gnrc_netif_hdr_t *netif_hdr, + uint16_t tag); + /** * @brief Checks if a reassembly buffer entry is unset * 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 d0c8856fa4..16913c8fe2 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 @@ -68,11 +68,14 @@ static gnrc_sixlowpan_frag_rb_int_t *_rbuf_int_get_free(void); /* update interval buffer of entry */ static bool _rbuf_update_ints(gnrc_sixlowpan_frag_rb_base_t *entry, uint16_t offset, size_t frag_size); -/* gets an entry identified by its tupel */ +/* gets an entry identified by its tuple */ static int _rbuf_get(const void *src, size_t src_len, const void *dst, size_t dst_len, size_t size, uint16_t tag, unsigned page); +/* gets an entry only by link-layer information and tag */ +static gnrc_sixlowpan_frag_rb_t *_rbuf_get_by_tag(const gnrc_netif_hdr_t *netif_hdr, + uint16_t tag); /* internal add to repeat add when fragments overlapped */ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, size_t offset, unsigned page); @@ -138,6 +141,47 @@ gnrc_sixlowpan_frag_rb_t *gnrc_sixlowpan_frag_rb_add(gnrc_netif_hdr_t *netif_hdr return (res < 0) ? NULL : &rbuf[res]; } + + +bool gnrc_sixlowpan_frag_rb_exists(const gnrc_netif_hdr_t *netif_hdr, + uint16_t tag) +{ + return (_rbuf_get_by_tag(netif_hdr, tag) != NULL); +} + +void gnrc_sixlowpan_frag_rb_rm_by_datagram(const gnrc_netif_hdr_t *netif_hdr, + uint16_t tag) +{ + gnrc_sixlowpan_frag_rb_t *e = _rbuf_get_by_tag(netif_hdr, tag); + + if (e != NULL) { + gnrc_sixlowpan_frag_rb_remove(e); + } +} + +static gnrc_sixlowpan_frag_rb_t *_rbuf_get_by_tag(const gnrc_netif_hdr_t *netif_hdr, + uint16_t tag) +{ + assert(netif_hdr != NULL); + const uint8_t *src = gnrc_netif_hdr_get_src_addr(netif_hdr); + const uint8_t *dst = gnrc_netif_hdr_get_dst_addr(netif_hdr); + const uint8_t src_len = netif_hdr->src_l2addr_len; + const uint8_t dst_len = netif_hdr->dst_l2addr_len; + + for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) { + gnrc_sixlowpan_frag_rb_t *e = &rbuf[i]; + + if ((e->pkt != NULL) && (e->super.tag == tag) && + (e->super.src_len == src_len) && + (e->super.dst_len == dst_len) && + (memcmp(e->super.src, src, src_len) == 0) && + (memcmp(e->super.dst, dst, dst_len) == 0)) { + return e; + } + } + return NULL; +} + #ifndef NDEBUG static bool _valid_offset(gnrc_pktsnip_t *pkt, size_t offset) { diff --git a/tests/gnrc_sixlowpan_frag/main.c b/tests/gnrc_sixlowpan_frag/main.c index 8d0e3e34ca..a54d436dc2 100644 --- a/tests/gnrc_sixlowpan_frag/main.c +++ b/tests/gnrc_sixlowpan_frag/main.c @@ -417,7 +417,7 @@ static void test_rbuf_add__full_rbuf(void) static void test_rbuf_add__too_big_fragment(void) { gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, _fragment1, - /* something definetely bigger than + /* something definitely bigger than * the datagram size noted in * _fragment1, can't just be + 1, * since fragment dispatch and other @@ -527,6 +527,22 @@ static void test_rbuf_add__overlap_rhs(void) _check_pktbuf(NULL); } +static void test_rbuf_exists(void) +{ + TEST_ASSERT(!gnrc_sixlowpan_frag_rb_exists(&_test_netif_hdr.hdr, TEST_TAG)); + /* add a fragment */ + test_rbuf_add__success_first_fragment(); + TEST_ASSERT(gnrc_sixlowpan_frag_rb_exists(&_test_netif_hdr.hdr, TEST_TAG)); +} + +static void test_rbuf_rm_by_dg(void) +{ + /* add a fragment */ + test_rbuf_add__success_first_fragment(); + gnrc_sixlowpan_frag_rb_rm_by_datagram(&_test_netif_hdr.hdr, TEST_TAG); + TEST_ASSERT(!gnrc_sixlowpan_frag_rb_exists(&_test_netif_hdr.hdr, TEST_TAG)); +} + static void test_rbuf_rm(void) { const gnrc_sixlowpan_frag_rb_t *entry; @@ -596,6 +612,8 @@ static void run_unittests(void) new_TestFixture(test_rbuf_add__too_big_fragment), new_TestFixture(test_rbuf_add__overlap_lhs), new_TestFixture(test_rbuf_add__overlap_rhs), + new_TestFixture(test_rbuf_exists), + new_TestFixture(test_rbuf_rm_by_dg), new_TestFixture(test_rbuf_rm), new_TestFixture(test_rbuf_gc__manually), new_TestFixture(test_rbuf_gc__timed),