mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
674 lines
28 KiB
C
674 lines
28 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup tests
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Tests 6LoWPAN fragmentation handling of gnrc stack.
|
|
*
|
|
* @author Martine S. Lenders <m.lenders@fu-berlin.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include "embUnit.h"
|
|
#include "net/gnrc/pktbuf.h"
|
|
#include "net/gnrc/netreg.h"
|
|
#include "net/gnrc/sixlowpan/frag.h"
|
|
#include "net/gnrc/sixlowpan/frag/rb.h"
|
|
#include "xtimer.h"
|
|
|
|
#define TEST_NETIF_HDR_SRC { 0xb3, 0x47, 0x60, 0x49, \
|
|
0x78, 0xfe, 0x95, 0x48 }
|
|
#define TEST_NETIF_HDR_DST { 0xa4, 0xf2, 0xd2, 0xc9, \
|
|
0x13, 0xb9, 0xbb, 0x25 }
|
|
#define TEST_NETIF_IFACE (9)
|
|
#define TEST_TAG (0x690e)
|
|
#define TEST_PAGE (0)
|
|
#define TEST_RECEIVE_TIMEOUT (100U)
|
|
#define TEST_GC_TIMEOUT (CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US + TEST_RECEIVE_TIMEOUT)
|
|
|
|
/* test date taken from an experimental run (uncompressed ICMPv6 echo reply with
|
|
* 300 byte payload)*/
|
|
#define TEST_DATAGRAM_SIZE (348U)
|
|
#ifdef MODULE_GNRC_IPV6
|
|
#define TEST_DATAGRAM_NETTYPE (GNRC_NETTYPE_IPV6)
|
|
#else /* MODULE_GNRC_IPV6 */
|
|
#define TEST_DATAGRAM_NETTYPE (GNRC_NETTYPE_UNDEF)
|
|
#endif /* MODULE_GNRC_IPV6 */
|
|
#define TEST_FRAGMENT1_OFFSET (0U)
|
|
#define TEST_FRAGMENT2_OFFSET (96U)
|
|
#define TEST_FRAGMENT3_OFFSET (192U)
|
|
#define TEST_FRAGMENT4_OFFSET (288U)
|
|
#define TEST_FRAGMENT1 { \
|
|
0xc1, 0x5c, 0x00, 0x05, 0x41, 0x60, 0x00, 0x00, \
|
|
0x00, 0x01, 0x34, 0x3a, 0x40, 0xfe, 0x80, 0x00, \
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x65, 0x08, \
|
|
0x22, 0x86, 0x93, 0x9d, 0x5a, 0xfe, 0x80, 0x00, \
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x79, 0x7f, \
|
|
0x7f, 0xa4, 0xb1, 0x55, 0x2e, 0x81, 0x00, 0x7a, \
|
|
0x81, 0x00, 0x54, 0x00, 0x02, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54 \
|
|
}
|
|
#define TEST_FRAGMENT2 { \
|
|
0xe1, 0x5c, 0x00, 0x05, 0x0c, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54 \
|
|
}
|
|
#define TEST_FRAGMENT3 { \
|
|
0xe1, 0x5c, 0x00, 0x05, 0x18, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54 \
|
|
}
|
|
#define TEST_FRAGMENT4 { \
|
|
0xe1, 0x5c, 0x00, 0x05, 0x24, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54 \
|
|
}
|
|
#define TEST_DATAGRAM { \
|
|
0x60, 0x00, 0x00, 0x00, 0x01, 0x34, 0x3a, 0x40, \
|
|
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
0x7b, 0x65, 0x08, 0x22, 0x86, 0x93, 0x9d, 0x5a, \
|
|
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
0x7b, 0x79, 0x7f, 0x7f, 0xa4, 0xb1, 0x55, 0x2e, \
|
|
0x81, 0x00, 0x7a, 0x81, 0x00, 0x54, 0x00, 0x02, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, \
|
|
0x54, 0x54, 0x54, 0x54 \
|
|
}
|
|
|
|
static const uint8_t _test_netif_hdr_src[] = TEST_NETIF_HDR_SRC;
|
|
static const uint8_t _test_netif_hdr_dst[] = TEST_NETIF_HDR_SRC;
|
|
static struct {
|
|
gnrc_netif_hdr_t hdr;
|
|
uint8_t src[GNRC_NETIF_HDR_L2ADDR_MAX_LEN];
|
|
uint8_t dst[GNRC_NETIF_HDR_L2ADDR_MAX_LEN];
|
|
} _test_netif_hdr;
|
|
|
|
static uint8_t _fragment1[] = TEST_FRAGMENT1;
|
|
static uint8_t _fragment2[] = TEST_FRAGMENT2;
|
|
static uint8_t _fragment3[] = TEST_FRAGMENT3;
|
|
static uint8_t _fragment4[] = TEST_FRAGMENT4;
|
|
static const uint8_t _datagram[] = TEST_DATAGRAM;
|
|
static msg_t _msg_queue;
|
|
|
|
static inline void _set_fragment_tag(void *frag, uint16_t tag)
|
|
{
|
|
sixlowpan_frag_t *f = frag;
|
|
|
|
f->tag = byteorder_htons(tag);
|
|
}
|
|
|
|
static inline void _set_fragment_offset(void *frag, uint16_t offset)
|
|
{
|
|
sixlowpan_frag_n_t *f = frag;
|
|
|
|
TEST_ASSERT_EQUAL_INT(SIXLOWPAN_FRAG_N_DISP,
|
|
f->disp_size.u8[0] & SIXLOWPAN_FRAG_DISP_MASK);
|
|
f->offset = offset / 8;
|
|
}
|
|
|
|
static void _set_up(void)
|
|
{
|
|
gnrc_sixlowpan_frag_rb_reset();
|
|
gnrc_pktbuf_init();
|
|
gnrc_netif_hdr_init(&_test_netif_hdr.hdr,
|
|
GNRC_NETIF_HDR_L2ADDR_MAX_LEN,
|
|
GNRC_NETIF_HDR_L2ADDR_MAX_LEN);
|
|
_test_netif_hdr.hdr.if_pid = TEST_NETIF_IFACE;
|
|
gnrc_netif_hdr_set_src_addr(&_test_netif_hdr.hdr,
|
|
(uint8_t *)_test_netif_hdr_src,
|
|
sizeof(_test_netif_hdr_src));
|
|
gnrc_netif_hdr_set_dst_addr(&_test_netif_hdr.hdr,
|
|
(uint8_t *)_test_netif_hdr_dst,
|
|
sizeof(_test_netif_hdr_dst));
|
|
_set_fragment_tag(_fragment1, TEST_TAG);
|
|
_set_fragment_tag(_fragment2, TEST_TAG);
|
|
_set_fragment_tag(_fragment3, TEST_TAG);
|
|
_set_fragment_tag(_fragment4, TEST_TAG);
|
|
_set_fragment_offset(_fragment2, TEST_FRAGMENT2_OFFSET);
|
|
_set_fragment_offset(_fragment3, TEST_FRAGMENT3_OFFSET);
|
|
_set_fragment_offset(_fragment4, TEST_FRAGMENT4_OFFSET);
|
|
}
|
|
|
|
static const gnrc_sixlowpan_frag_rb_t *_first_non_empty_rbuf(void)
|
|
{
|
|
const gnrc_sixlowpan_frag_rb_t *rbuf = gnrc_sixlowpan_frag_rb_array();
|
|
|
|
for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
|
if (!gnrc_sixlowpan_frag_rb_entry_empty(&rbuf[i])) {
|
|
return rbuf;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void _test_entry(const gnrc_sixlowpan_frag_rb_t *entry,
|
|
unsigned exp_current_size,
|
|
unsigned exp_int_start, unsigned exp_int_end)
|
|
{
|
|
TEST_ASSERT_NOT_NULL(entry);
|
|
TEST_ASSERT_NOT_NULL(entry->pkt);
|
|
TEST_ASSERT_EQUAL_INT(TEST_DATAGRAM_SIZE, entry->pkt->size);
|
|
TEST_ASSERT_EQUAL_INT(sizeof(_test_netif_hdr_src),
|
|
entry->super.src_len);
|
|
TEST_ASSERT_MESSAGE(memcmp(entry->super.src, _test_netif_hdr_src,
|
|
entry->super.src_len) == 0,
|
|
"entry->super.src != TEST_NETIF_HDR_SRC");
|
|
TEST_ASSERT_EQUAL_INT(sizeof(_test_netif_hdr_dst),
|
|
entry->super.dst_len);
|
|
TEST_ASSERT_MESSAGE(memcmp(entry->super.dst, _test_netif_hdr_dst,
|
|
entry->super.dst_len) == 0,
|
|
"entry->super.dst != TEST_NETIF_HDR_DST");
|
|
TEST_ASSERT_EQUAL_INT(TEST_TAG, entry->super.tag);
|
|
TEST_ASSERT_EQUAL_INT(exp_current_size, entry->super.current_size);
|
|
TEST_ASSERT_NOT_NULL(entry->super.ints);
|
|
TEST_ASSERT_NULL(entry->super.ints->next);
|
|
TEST_ASSERT_EQUAL_INT(exp_int_start, entry->super.ints->start);
|
|
TEST_ASSERT_EQUAL_INT(exp_int_end, entry->super.ints->end);
|
|
}
|
|
|
|
static void _check_pktbuf(const gnrc_sixlowpan_frag_rb_t *entry)
|
|
{
|
|
if (entry != NULL) {
|
|
gnrc_pktbuf_release(entry->pkt);
|
|
}
|
|
TEST_ASSERT_MESSAGE(gnrc_pktbuf_is_empty(), "Packet buffer is not empty");
|
|
}
|
|
|
|
static void _rbuf_create_first_fragment(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NOT_NULL((entry = gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
)));
|
|
/* current_size must be the offset of fragment 2, not the size of
|
|
* fragment 1 (fragment dispatch was removed, IPHC was applied etc.). */
|
|
_test_entry(entry, TEST_FRAGMENT2_OFFSET,
|
|
TEST_FRAGMENT1_OFFSET, TEST_FRAGMENT2_OFFSET - 1);
|
|
}
|
|
|
|
static void test_rbuf_add__success_first_fragment(void)
|
|
{
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
_rbuf_create_first_fragment();
|
|
/* get entry to release entry->pkt it in `_check_pktbuf()` */
|
|
TEST_ASSERT_NOT_NULL((entry = _first_non_empty_rbuf()));
|
|
_check_pktbuf(entry);
|
|
}
|
|
|
|
static void test_rbuf_add__success_subsequent_fragment(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, _fragment2, sizeof(_fragment2),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NOT_NULL((entry = gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT2_OFFSET, TEST_PAGE
|
|
)));
|
|
/* current_size must be the offset of fragment 3, not the size of
|
|
* fragment 2 (fragment dispatch was removed, IPHC was applied etc.). */
|
|
_test_entry(entry, TEST_FRAGMENT3_OFFSET - TEST_FRAGMENT2_OFFSET,
|
|
TEST_FRAGMENT2_OFFSET, TEST_FRAGMENT3_OFFSET - 1);
|
|
_check_pktbuf(entry);
|
|
}
|
|
|
|
static void test_rbuf_add__success_duplicate_fragments(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt1 = gnrc_pktbuf_add(NULL, _fragment3, sizeof(_fragment3),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_pktsnip_t *pkt2 = gnrc_pktbuf_add(NULL, _fragment3, sizeof(_fragment3),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT_NOT_NULL(pkt1);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt1, TEST_FRAGMENT3_OFFSET, TEST_PAGE
|
|
));
|
|
TEST_ASSERT_NOT_NULL(pkt2);
|
|
TEST_ASSERT_NOT_NULL((entry = gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt2, TEST_FRAGMENT3_OFFSET, TEST_PAGE
|
|
)));
|
|
/* current_size must be the offset of fragment 4, not the size of
|
|
* fragment 3 (fragment dispatch was removed, IPHC was applied etc.). */
|
|
_test_entry(entry, TEST_FRAGMENT4_OFFSET - TEST_FRAGMENT3_OFFSET,
|
|
TEST_FRAGMENT3_OFFSET, TEST_FRAGMENT4_OFFSET - 1);
|
|
_check_pktbuf(entry);
|
|
}
|
|
|
|
static void test_rbuf_add__success_complete(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt1 = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_pktsnip_t *pkt2 = gnrc_pktbuf_add(NULL, _fragment2, sizeof(_fragment2),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_pktsnip_t *pkt3 = gnrc_pktbuf_add(NULL, _fragment3, sizeof(_fragment3),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
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,
|
|
thread_getpid()
|
|
);
|
|
|
|
gnrc_netreg_register(TEST_DATAGRAM_NETTYPE, ®);
|
|
/* Mixing up things. Order decided by fair dice-rolls ;-) */
|
|
TEST_ASSERT_NOT_NULL(pkt2);
|
|
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((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((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((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,
|
|
"Receiving reassembled datagram timed out"
|
|
);
|
|
gnrc_netreg_unregister(TEST_DATAGRAM_NETTYPE, ®);
|
|
TEST_ASSERT_EQUAL_INT(GNRC_NETAPI_MSG_TYPE_RCV, msg.type);
|
|
TEST_ASSERT_NOT_NULL(msg.content.ptr);
|
|
datagram = msg.content.ptr;
|
|
TEST_ASSERT_EQUAL_INT(TEST_DATAGRAM_SIZE, datagram->size);
|
|
TEST_ASSERT_EQUAL_INT(TEST_DATAGRAM_NETTYPE, datagram->type);
|
|
TEST_ASSERT_MESSAGE(memcmp(_datagram, datagram->data,
|
|
TEST_DATAGRAM_SIZE) == 0,
|
|
"Reassembled datagram does not contain expected data");
|
|
gnrc_pktbuf_release(datagram);
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_add__full_rbuf(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt;
|
|
const gnrc_sixlowpan_frag_rb_t *rbuf;
|
|
|
|
for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
|
pkt = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
));
|
|
_set_fragment_tag(_fragment1, TEST_TAG + i + 1);
|
|
/* pkt is released in gnrc_sixlowpan_frag_rb_add() */
|
|
}
|
|
pkt = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
));
|
|
rbuf = gnrc_sixlowpan_frag_rb_array();
|
|
for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
|
const gnrc_sixlowpan_frag_rb_t *entry = &rbuf[i];
|
|
|
|
TEST_ASSERT_MESSAGE(!gnrc_sixlowpan_frag_rb_entry_empty(entry),
|
|
"Reassembly buffer entry unexpectedly empty");
|
|
TEST_ASSERT((sizeof(_fragment1) - sizeof(sixlowpan_frag_t)) <
|
|
entry->pkt->size);
|
|
TEST_ASSERT_MESSAGE(
|
|
memcmp(entry->pkt->data, &_fragment1[sizeof(sixlowpan_frag_t)],
|
|
sizeof(_fragment1) - sizeof(sixlowpan_frag_t)) != 0,
|
|
"Reassembly buffer contains fragment that was not supposed "
|
|
"to fit");
|
|
/* releasing pkt to check if packet buffer is empty in the end */
|
|
gnrc_pktbuf_release(entry->pkt);
|
|
}
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_add__too_big_fragment(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, _fragment1,
|
|
/* something definitely bigger than
|
|
* the datagram size noted in
|
|
* _fragment1, can't just be + 1,
|
|
* since fragment dispatch and other
|
|
* dispatches are supposed to be
|
|
* subtracted */
|
|
2 * TEST_DATAGRAM_SIZE,
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
));
|
|
/* packet buffer is empty*/
|
|
TEST_ASSERT_NULL(_first_non_empty_rbuf());
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_add__overlap_lhs(void)
|
|
{
|
|
static const size_t pkt2_offset = TEST_FRAGMENT2_OFFSET - 8U;
|
|
gnrc_pktsnip_t *pkt1 = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_pktsnip_t *pkt2;
|
|
const gnrc_sixlowpan_frag_rb_t *rbuf;
|
|
unsigned rbuf_entries = 0;
|
|
|
|
_set_fragment_offset(_fragment2, pkt2_offset);
|
|
pkt2 = gnrc_pktbuf_add(NULL, _fragment2, sizeof(_fragment2),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
TEST_ASSERT_NOT_NULL(pkt1);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt1, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
));
|
|
TEST_ASSERT_NOT_NULL(pkt2);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt2, pkt2_offset, TEST_PAGE
|
|
));
|
|
rbuf = gnrc_sixlowpan_frag_rb_array();
|
|
for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
|
const gnrc_sixlowpan_frag_rb_t *entry = &rbuf[i];
|
|
if (!gnrc_sixlowpan_frag_rb_entry_empty(entry)) {
|
|
static const size_t pkt3_offset = TEST_FRAGMENT3_OFFSET - 8U - 1;
|
|
|
|
rbuf_entries++;
|
|
/* only _fragment2 should now in the reassembly buffer according to
|
|
* https://tools.ietf.org/html/rfc4944#section-5.3 */
|
|
_test_entry(entry,
|
|
/* current_size must be the offset of fragment 3, not
|
|
* the size of fragment 2 (fragment dispatch was
|
|
* removed, IPHC was applied etc.). */
|
|
TEST_FRAGMENT3_OFFSET - TEST_FRAGMENT2_OFFSET,
|
|
(unsigned)pkt2_offset, (unsigned)pkt3_offset);
|
|
/* releasing pkt to check if packet buffer is empty in the end */
|
|
gnrc_pktbuf_release(entry->pkt);
|
|
}
|
|
}
|
|
TEST_ASSERT_EQUAL_INT(1U, rbuf_entries);
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_add__overlap_rhs(void)
|
|
{
|
|
static const size_t pkt2_offset = TEST_FRAGMENT2_OFFSET + 8U;
|
|
gnrc_pktsnip_t *pkt1 = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_pktsnip_t *pkt2;
|
|
gnrc_pktsnip_t *pkt3 = gnrc_pktbuf_add(NULL, _fragment3, sizeof(_fragment3),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
const gnrc_sixlowpan_frag_rb_t *rbuf;
|
|
unsigned rbuf_entries = 0;
|
|
|
|
_set_fragment_offset(_fragment2, pkt2_offset);
|
|
pkt2 = gnrc_pktbuf_add(NULL, _fragment2, sizeof(_fragment2),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
TEST_ASSERT_NOT_NULL(pkt1);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt1, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
));
|
|
TEST_ASSERT_NOT_NULL(pkt3);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt3, TEST_FRAGMENT3_OFFSET, TEST_PAGE
|
|
));
|
|
TEST_ASSERT_NOT_NULL(pkt2);
|
|
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt2, pkt2_offset, TEST_PAGE
|
|
));
|
|
rbuf = gnrc_sixlowpan_frag_rb_array();
|
|
for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
|
const gnrc_sixlowpan_frag_rb_t *entry = &rbuf[i];
|
|
if (!gnrc_sixlowpan_frag_rb_entry_empty(entry)) {
|
|
static const size_t pkt3_offset = TEST_FRAGMENT3_OFFSET + 8U - 1U;
|
|
|
|
rbuf_entries++;
|
|
/* only _fragment2 should now in the reassembly buffer according to
|
|
* https://tools.ietf.org/html/rfc4944#section-5.3 */
|
|
_test_entry(entry,
|
|
/* current_size must be the offset of fragment 3, not
|
|
* the size of fragment 2 (fragment dispatch was
|
|
* removed, IPHC was applied etc.). */
|
|
TEST_FRAGMENT3_OFFSET - TEST_FRAGMENT2_OFFSET,
|
|
(unsigned)pkt2_offset, (unsigned)pkt3_offset);
|
|
/* releasing pkt to check if packet buffer is empty in the end */
|
|
gnrc_pktbuf_release(entry->pkt);
|
|
}
|
|
}
|
|
TEST_ASSERT_EQUAL_INT(1U, rbuf_entries);
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_get_by_dg(void)
|
|
{
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT_NULL(
|
|
gnrc_sixlowpan_frag_rb_get_by_datagram(&_test_netif_hdr.hdr, TEST_TAG)
|
|
);
|
|
/* add a fragment */
|
|
_rbuf_create_first_fragment();
|
|
TEST_ASSERT_NOT_NULL(
|
|
gnrc_sixlowpan_frag_rb_get_by_datagram(&_test_netif_hdr.hdr, TEST_TAG)
|
|
);
|
|
/* get entry to release entry->pkt it in `_check_pktbuf()` */
|
|
entry = _first_non_empty_rbuf();
|
|
/* entry is however not properly removed yet */
|
|
TEST_ASSERT_NOT_NULL(entry);
|
|
_check_pktbuf(entry);
|
|
}
|
|
|
|
static void test_rbuf_exists(void)
|
|
{
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT(!gnrc_sixlowpan_frag_rb_exists(&_test_netif_hdr.hdr, TEST_TAG));
|
|
/* add a fragment */
|
|
_rbuf_create_first_fragment();
|
|
TEST_ASSERT(gnrc_sixlowpan_frag_rb_exists(&_test_netif_hdr.hdr, TEST_TAG));
|
|
/* get entry to release entry->pkt it in `_check_pktbuf()` */
|
|
entry = _first_non_empty_rbuf();
|
|
/* entry is however not properly removed yet */
|
|
TEST_ASSERT_NOT_NULL(entry);
|
|
_check_pktbuf(entry);
|
|
}
|
|
|
|
static void test_rbuf_rm_by_dg(void)
|
|
{
|
|
/* add a fragment */
|
|
_rbuf_create_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));
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_rm(void)
|
|
{
|
|
const gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
_rbuf_create_first_fragment();
|
|
entry = _first_non_empty_rbuf();
|
|
/* entry is however not properly removed yet */
|
|
TEST_ASSERT_NOT_NULL(entry);
|
|
/* release packet as `gnrc_sixlowpan_frag_rb_remove()` does not do this */
|
|
gnrc_pktbuf_release(entry->pkt);
|
|
/* intentionally discarding const qualifier since we enter rbuf's internal
|
|
* context again */
|
|
gnrc_sixlowpan_frag_rb_remove((gnrc_sixlowpan_frag_rb_t *)entry);
|
|
/* reassembly buffer is now empty */
|
|
TEST_ASSERT_NULL(_first_non_empty_rbuf());
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_gc__manually(void)
|
|
{
|
|
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NOT_NULL((entry = gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
)));
|
|
TEST_ASSERT_NOT_NULL(entry);
|
|
/* set arrival CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US into the past */
|
|
entry->super.arrival -= CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US;
|
|
gnrc_sixlowpan_frag_rb_gc();
|
|
/* reassembly buffer is now empty */
|
|
TEST_ASSERT_NULL(_first_non_empty_rbuf());
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void test_rbuf_gc__timed(void)
|
|
{
|
|
msg_t msg;
|
|
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, _fragment1, sizeof(_fragment1),
|
|
GNRC_NETTYPE_SIXLOWPAN);
|
|
gnrc_sixlowpan_frag_rb_t *entry;
|
|
|
|
TEST_ASSERT_NOT_NULL(pkt);
|
|
TEST_ASSERT_NOT_NULL((entry = gnrc_sixlowpan_frag_rb_add(
|
|
&_test_netif_hdr.hdr, pkt, TEST_FRAGMENT1_OFFSET, TEST_PAGE
|
|
)));
|
|
TEST_ASSERT_NOT_NULL(entry);
|
|
TEST_ASSERT_MESSAGE(
|
|
xtimer_msg_receive_timeout(&msg, TEST_GC_TIMEOUT) >= 0,
|
|
"Waiting for GC timer timed out"
|
|
);
|
|
TEST_ASSERT_EQUAL_INT(GNRC_SIXLOWPAN_FRAG_RB_GC_MSG, msg.type);
|
|
gnrc_sixlowpan_frag_rb_gc();
|
|
/* reassembly buffer is now empty */
|
|
TEST_ASSERT_NULL(_first_non_empty_rbuf());
|
|
_check_pktbuf(NULL);
|
|
}
|
|
|
|
static void run_unittests(void)
|
|
{
|
|
EMB_UNIT_TESTFIXTURES(fixtures) {
|
|
new_TestFixture(test_rbuf_add__success_first_fragment),
|
|
new_TestFixture(test_rbuf_add__success_subsequent_fragment),
|
|
new_TestFixture(test_rbuf_add__success_duplicate_fragments),
|
|
new_TestFixture(test_rbuf_add__success_complete),
|
|
new_TestFixture(test_rbuf_add__full_rbuf),
|
|
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_get_by_dg),
|
|
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),
|
|
};
|
|
|
|
EMB_UNIT_TESTCALLER(sixlo_frag_tests, _set_up, NULL, fixtures);
|
|
TESTS_START();
|
|
TESTS_RUN((Test *)&sixlo_frag_tests);
|
|
TESTS_END();
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
/* netreg requires queue, but queue size one should be enough for us */
|
|
msg_init_queue(&_msg_queue, 1U);
|
|
run_unittests();
|
|
return 0;
|
|
}
|