mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #12629 from miri64/gnrc_sixlowpan_iphc/enh/vrb-creation
gnrc_sixlowpan_iphc: add fragment forwarding stubs
This commit is contained in:
commit
f38f974d86
@ -25,11 +25,15 @@
|
||||
#include "net/gnrc/sixlowpan.h"
|
||||
#include "net/gnrc/sixlowpan/ctx.h"
|
||||
#include "net/gnrc/sixlowpan/frag/rb.h"
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
#include "net/gnrc/sixlowpan/frag/vrb.h"
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
#include "net/gnrc/sixlowpan/internal.h"
|
||||
#include "net/sixlowpan.h"
|
||||
#include "utlist.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "net/gnrc/udp.h"
|
||||
#include "od.h"
|
||||
|
||||
#include "net/gnrc/sixlowpan/iphc.h"
|
||||
|
||||
@ -92,6 +96,12 @@
|
||||
#define NHC_UDP_8BIT_PORT (0xF000)
|
||||
#define NHC_UDP_8BIT_MASK (0xFF00)
|
||||
|
||||
/* currently only used with forwarding output, remove guard if more debug info
|
||||
* is added */
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
|
||||
static inline bool _context_overlaps_iid(gnrc_sixlowpan_ctx_t *ctx,
|
||||
ipv6_addr_t *addr,
|
||||
eui64_t *iid)
|
||||
@ -113,6 +123,17 @@ static inline bool _context_overlaps_iid(gnrc_sixlowpan_ctx_t *ctx,
|
||||
(iid->uint8[(ctx->prefix_len / 8) - 8] & byte_mask[ctx->prefix_len % 8])));
|
||||
}
|
||||
|
||||
static gnrc_pktsnip_t *_iphc_encode(gnrc_pktsnip_t *pkt,
|
||||
const gnrc_netif_hdr_t *netif_hdr,
|
||||
gnrc_netif_t *netif);
|
||||
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
static gnrc_pktsnip_t *_encode_frag_for_forwarding(gnrc_pktsnip_t *decoded_pkt,
|
||||
gnrc_sixlowpan_frag_vrb_t *vrbe);
|
||||
static int _forward_frag(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *frag_hdr,
|
||||
gnrc_sixlowpan_frag_vrb_t *vrbe, unsigned page);
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC
|
||||
/**
|
||||
* @brief Decodes UDP NHC
|
||||
@ -236,6 +257,9 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr,
|
||||
size_t uncomp_hdr_len = sizeof(ipv6_hdr_t);
|
||||
gnrc_sixlowpan_ctx_t *ctx = NULL;
|
||||
gnrc_sixlowpan_frag_rb_t *rbuf = rbuf_ptr;
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
gnrc_sixlowpan_frag_vrb_t *vrbe = NULL;
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
|
||||
if (rbuf != NULL) {
|
||||
ipv6 = rbuf->pkt;
|
||||
@ -559,6 +583,40 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr,
|
||||
if (rbuf != NULL) {
|
||||
/* for a fragmented datagram we know the overall length already */
|
||||
payload_len = (uint16_t)(rbuf->super.datagram_size - sizeof(ipv6_hdr_t));
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
DEBUG("6lo iphc: VRB present, trying to create entry for dst %s\n",
|
||||
ipv6_addr_to_str(addr_str, &ipv6_hdr->dst, sizeof(addr_str)));
|
||||
/* re-assign IPv6 header in case realloc changed the address */
|
||||
ipv6_hdr = ipv6->data;
|
||||
/* only create virtual reassembly buffer entry from IPv6 destination if
|
||||
* the current first fragment is the only received fragment in the
|
||||
* reassembly buffer so far and the hop-limit is larger than 1
|
||||
*/
|
||||
if ((rbuf->super.current_size <= sixlo->size) && (ipv6_hdr->hl > 1U) &&
|
||||
/* and there is enough slack for changing compression */
|
||||
(rbuf->super.current_size <= iface->sixlo.max_frag_size) &&
|
||||
(vrbe = gnrc_sixlowpan_frag_vrb_from_route(&rbuf->super, iface,
|
||||
ipv6))) {
|
||||
/* add netif header to `ipv6` so its flags can be used when
|
||||
* forwarding the fragment */
|
||||
LL_DELETE(sixlo, netif);
|
||||
LL_APPEND(ipv6, netif);
|
||||
/* provide space to copy remaining payload */
|
||||
if (gnrc_pktbuf_realloc_data(ipv6, uncomp_hdr_len + sixlo->size -
|
||||
payload_offset) != 0) {
|
||||
DEBUG("6lo iphc: no space left to copy payload\n");
|
||||
gnrc_sixlowpan_frag_vrb_rm(vrbe);
|
||||
_recv_error_release(sixlo, ipv6, rbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* reallocate to copy complete payload */
|
||||
else if (gnrc_pktbuf_realloc_data(ipv6, rbuf->super.datagram_size) != 0) {
|
||||
DEBUG("6lo iphc: no space left to reassemble payload\n");
|
||||
_recv_error_release(sixlo, ipv6, rbuf);
|
||||
return;
|
||||
}
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
}
|
||||
else {
|
||||
/* set IPv6 header payload length field to the length of whatever is left
|
||||
@ -580,6 +638,30 @@ 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);
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
if (vrbe != NULL) {
|
||||
int res = -1;
|
||||
DEBUG("6lo iphc: found route, trying to forward\n");
|
||||
ipv6_hdr->hl--;
|
||||
vrbe->super.current_size = rbuf->super.current_size;
|
||||
if ((ipv6 = _encode_frag_for_forwarding(ipv6, vrbe))) {
|
||||
if ((res = _forward_frag(ipv6, sixlo->next, vrbe, page)) == 0) {
|
||||
DEBUG("6lo iphc: successfully recompressed and forwarded "
|
||||
"1st fragment\n");
|
||||
/* empty list, as it should be in VRB now */
|
||||
rbuf->super.ints = NULL;
|
||||
}
|
||||
}
|
||||
if ((ipv6 == NULL) || (res < 0)) {
|
||||
gnrc_sixlowpan_frag_vrb_rm(vrbe);
|
||||
}
|
||||
gnrc_pktbuf_release(sixlo);
|
||||
/* don't remove `rbuf->pkt` (aka ipv6) as it was forwarded */
|
||||
gnrc_sixlowpan_frag_rb_remove(rbuf);
|
||||
return;
|
||||
}
|
||||
DEBUG("6lo iphc: no route found, reassemble datagram normally\n");
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
}
|
||||
else {
|
||||
LL_DELETE(sixlo, netif);
|
||||
@ -590,6 +672,76 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
|
||||
static gnrc_pktsnip_t *_encode_frag_for_forwarding(gnrc_pktsnip_t *decoded_pkt,
|
||||
gnrc_sixlowpan_frag_vrb_t *vrbe)
|
||||
{
|
||||
gnrc_pktsnip_t *res;
|
||||
gnrc_netif_hdr_t *netif_hdr;
|
||||
|
||||
/* mark IPv6 header to allow for next header compression */
|
||||
res = gnrc_pktbuf_mark(decoded_pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6);
|
||||
if (res == NULL) {
|
||||
DEBUG("6lo iphc: unable to mark IPv6 header for forwarding\n");
|
||||
gnrc_pktbuf_release(decoded_pkt);
|
||||
return NULL;
|
||||
}
|
||||
res = gnrc_pktbuf_reverse_snips(decoded_pkt);
|
||||
if (res == NULL) {
|
||||
DEBUG("6lo iphc: unable to reverse packet for forwarding\n");
|
||||
/* decoded_pkt is released in gnrc_pktbuf_reverse_snips() */
|
||||
return NULL;
|
||||
}
|
||||
/* set netif header from VRB for correct encoding */
|
||||
netif_hdr = res->data;
|
||||
/* _iphc_encode only checks the destination address, so leave src
|
||||
* untouched */
|
||||
netif_hdr->dst_l2addr_len = vrbe->super.dst_len;
|
||||
gnrc_netif_hdr_set_dst_addr(netif_hdr, vrbe->super.dst,
|
||||
vrbe->super.dst_len);
|
||||
gnrc_netif_hdr_set_netif(netif_hdr, vrbe->out_netif);
|
||||
decoded_pkt = res;
|
||||
if ((res = _iphc_encode(decoded_pkt, netif_hdr, vrbe->out_netif))) {
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
DEBUG("6lo iphc: unable to compress packet for forwarding\n");
|
||||
gnrc_pktbuf_release(decoded_pkt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int _forward_frag(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *frag_hdr,
|
||||
gnrc_sixlowpan_frag_vrb_t *vrbe, unsigned page)
|
||||
{
|
||||
/* remove rewritten netif header (forwarding implementation must do this
|
||||
* anyway) */
|
||||
pkt = gnrc_pktbuf_remove_snip(pkt, pkt);
|
||||
/* the following is just debug output for testing without any forwarding
|
||||
* scheme */
|
||||
DEBUG("6lo iphc: Do not know how to forward fragment from (%s, %u) ",
|
||||
gnrc_netif_addr_to_str(vrbe->super.src, vrbe->super.src_len,
|
||||
addr_str), vrbe->super.tag);
|
||||
DEBUG("to (%s, %u)\n",
|
||||
gnrc_netif_addr_to_str(vrbe->super.dst, vrbe->super.dst_len,
|
||||
addr_str), vrbe->out_tag);
|
||||
#if ENABLE_DEBUG && defined(MODULE_OD)
|
||||
DEBUG("Original fragmentation header:\n");
|
||||
od_hex_dump(frag_hdr->data, frag_hdr->size, OD_WIDTH_DEFAULT);
|
||||
DEBUG("IPHC headers + payload:\n");
|
||||
frag_hdr = pkt;
|
||||
while (frag_hdr) {
|
||||
od_hex_dump(frag_hdr->data, frag_hdr->size, OD_WIDTH_DEFAULT);
|
||||
frag_hdr = frag_hdr->next;
|
||||
}
|
||||
#endif
|
||||
gnrc_pktbuf_release(pkt);
|
||||
(void)frag_hdr;
|
||||
(void)page;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
|
||||
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC
|
||||
static inline size_t iphc_nhc_udp_encode(uint8_t *nhc_data,
|
||||
const gnrc_pktsnip_t *udp)
|
||||
@ -655,22 +807,19 @@ static inline bool _compressible(gnrc_pktsnip_t *hdr)
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
static gnrc_pktsnip_t *_iphc_encode(gnrc_pktsnip_t *pkt,
|
||||
const gnrc_netif_hdr_t *netif_hdr,
|
||||
gnrc_netif_t *iface)
|
||||
{
|
||||
assert(pkt != NULL);
|
||||
gnrc_netif_hdr_t *netif_hdr = pkt->data;
|
||||
ipv6_hdr_t *ipv6_hdr;
|
||||
gnrc_netif_t *iface = gnrc_netif_hdr_get_netif(netif_hdr);
|
||||
uint8_t *iphc_hdr;
|
||||
gnrc_sixlowpan_ctx_t *src_ctx = NULL, *dst_ctx = NULL;
|
||||
gnrc_pktsnip_t *dispatch, *ptr = pkt->next;
|
||||
bool addr_comp = false;
|
||||
size_t dispatch_size = 0;
|
||||
/* datagram size before compression */
|
||||
size_t orig_datagram_size = gnrc_pkt_len(pkt->next);
|
||||
uint16_t inline_pos = SIXLOWPAN_IPHC_HDR_LEN;
|
||||
|
||||
(void)ctx;
|
||||
assert(iface != NULL);
|
||||
dispatch = NULL; /* use dispatch as temporary pointer for prev */
|
||||
/* determine maximum dispatch size and write protect all headers until
|
||||
@ -680,10 +829,7 @@ void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
|
||||
if (tmp == NULL) {
|
||||
DEBUG("6lo iphc: unable to write protect compressible header\n");
|
||||
if (addr_comp) { /* addr_comp was used as release indicator */
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
ptr = tmp;
|
||||
if (dispatch == NULL) {
|
||||
@ -716,8 +862,7 @@ void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
|
||||
if (dispatch == NULL) {
|
||||
DEBUG("6lo iphc: error allocating dispatch space\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iphc_hdr = dispatch->data;
|
||||
@ -844,8 +989,7 @@ void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
if (gnrc_netif_ipv6_get_iid(iface, &iid) < 0) {
|
||||
DEBUG("6lo iphc: could not get interface's IID\n");
|
||||
gnrc_netif_release(iface);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
gnrc_netif_release(iface);
|
||||
|
||||
@ -963,8 +1107,7 @@ void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
|
||||
if (gnrc_netif_hdr_ipv6_iid_from_dst(iface, netif_hdr, &iid) < 0) {
|
||||
DEBUG("6lo iphc: could not get destination's IID\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ipv6_hdr->dst.u64[1].u64 == iid.uint64.u64) ||
|
||||
@ -1012,7 +1155,7 @@ void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
if (udp == NULL) {
|
||||
DEBUG("gnrc_sixlowpan_iphc_encode: unable to mark UDP header\n");
|
||||
gnrc_pktbuf_release(dispatch);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
gnrc_pktbuf_remove_snip(pkt, udp);
|
||||
@ -1033,8 +1176,24 @@ void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
/* insert dispatch into packet */
|
||||
dispatch->next = pkt->next;
|
||||
pkt->next = dispatch;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
gnrc_sixlowpan_multiplex_by_size(pkt, orig_datagram_size, iface, page);
|
||||
void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
|
||||
{
|
||||
gnrc_netif_hdr_t *netif_hdr = pkt->data;
|
||||
gnrc_netif_t *netif = gnrc_netif_hdr_get_netif(netif_hdr);
|
||||
gnrc_pktsnip_t *tmp;
|
||||
/* datagram size before compression */
|
||||
size_t orig_datagram_size = gnrc_pkt_len(pkt->next);
|
||||
|
||||
(void)ctx;
|
||||
if ((tmp = _iphc_encode(pkt, pkt->data, netif))) {
|
||||
gnrc_sixlowpan_multiplex_by_size(tmp, orig_datagram_size, netif, page);
|
||||
}
|
||||
else {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
15
tests/gnrc_sixlowpan_iphc_w_vrb/Makefile
Normal file
15
tests/gnrc_sixlowpan_iphc_w_vrb/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += embunit
|
||||
USEMODULE += gnrc_ipv6_nib_6ln
|
||||
USEMODULE += gnrc_sixlowpan_iphc
|
||||
USEMODULE += gnrc_sixlowpan_frag
|
||||
USEMODULE += gnrc_sixlowpan_frag_vrb
|
||||
USEMODULE += netdev_ieee802154
|
||||
USEMODULE += netdev_test
|
||||
USEMODULE += od
|
||||
|
||||
# we don't need all this packet buffer space so reduce it a little
|
||||
CFLAGS += -DTEST_SUITES -DGNRC_PKTBUF_SIZE=2048
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
22
tests/gnrc_sixlowpan_iphc_w_vrb/Makefile.ci
Normal file
22
tests/gnrc_sixlowpan_iphc_w_vrb/Makefile.ci
Normal file
@ -0,0 +1,22 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-mega2560 \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
chronos \
|
||||
i-nucleo-lrwan1 \
|
||||
msb-430 \
|
||||
msb-430h \
|
||||
nucleo-f030r8 \
|
||||
nucleo-f031k6 \
|
||||
nucleo-f042k6 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
stm32f030f4-demo \
|
||||
stm32f0discovery \
|
||||
stm32l0538-disco \
|
||||
telosb \
|
||||
waspmote-pro \
|
||||
#
|
321
tests/gnrc_sixlowpan_iphc_w_vrb/main.c
Normal file
321
tests/gnrc_sixlowpan_iphc_w_vrb/main.c
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* 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.h"
|
||||
#include "net/gnrc/netif/ieee802154.h"
|
||||
#include "net/gnrc/sixlowpan.h"
|
||||
#include "net/gnrc/sixlowpan/frag/rb.h"
|
||||
#include "net/gnrc/sixlowpan/frag/vrb.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/netdev_test.h"
|
||||
#include "thread.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#define TEST_DST { 0x5a, 0x9d, 0x93, 0x86, 0x22, 0x08, 0x65, 0x79 }
|
||||
#define TEST_SRC { 0x2a, 0xab, 0xdc, 0x15, 0x54, 0x01, 0x64, 0x79 }
|
||||
#define TEST_6LO_PAYLOAD { \
|
||||
/* 6LoWPAN, Src: 2001:db8::1, Dest: 2001:db8::2
|
||||
* Fragmentation Header
|
||||
* 1100 0... = Pattern: First fragment (0x18)
|
||||
* Datagram size: 188
|
||||
* Datagram tag: 0x000f
|
||||
* IPHC Header
|
||||
* 011. .... = Pattern: IP header compression (0x03)
|
||||
* ...1 1... .... .... = Version, traffic class, and flow label compressed (0x3)
|
||||
* .... .0.. .... .... = Next header: Inline
|
||||
* .... ..10 .... .... = Hop limit: 64 (0x2)
|
||||
* .... .... 0... .... = Context identifier extension: False
|
||||
* .... .... .0.. .... = Source address compression: Stateless
|
||||
* .... .... ..00 .... = Source address mode: Inline (0x0000)
|
||||
* .... .... .... 0... = Multicast address compression: False
|
||||
* .... .... .... .0.. = Destination address compression: Stateless
|
||||
* .... .... .... ..00 = Destination address mode: Inline (0x0000)
|
||||
* Next header: ICMPv6 (0x3a)
|
||||
* Source: 2001:db8::1
|
||||
* Destination: 2001:db8::2 */ \
|
||||
0xc0, 0xbc, 0x00, 0x0f, \
|
||||
/* IPHC Header
|
||||
* 011. .... = Pattern: IP header compression (0x03)
|
||||
* ...1 1... .... .... = Version, traffic class, and flow label compressed (0x3)
|
||||
* .... .0.. .... .... = Next header: Inline
|
||||
* .... ..10 .... .... = Hop limit: 64 (0x2)
|
||||
* .... .... 0... .... = Context identifier extension: False
|
||||
* .... .... .0.. .... = Source address compression: Stateless
|
||||
* .... .... ..00 .... = Source address mode: Inline (0x0000)
|
||||
* .... .... .... 0... = Multicast address compression: False
|
||||
* .... .... .... .0.. = Destination address compression: Stateless
|
||||
* .... .... .... ..00 = Destination address mode: Inline (0x0000)
|
||||
* Next header: ICMPv6 (0x3a) */ \
|
||||
0x7a, 0x00, 0x3a, \
|
||||
/* Source: 2001:db8::1 */ \
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, \
|
||||
/* Destination: 2001:db8::2 */ \
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, \
|
||||
/* Internet Control Message Protocol v6
|
||||
* Type: Echo (ping) request (128)
|
||||
* Code: 0
|
||||
* Checksum: 0x8ea0
|
||||
* Identifier: 0x238f
|
||||
* Sequence: 2
|
||||
* [No response seen]
|
||||
* Data (140 bytes)
|
||||
* Data: 9d4bb21c5353535353535353535353535353535353535353…
|
||||
*/ \
|
||||
0x80, 0x00, 0x8e, 0xa0, 0x23, 0x8f, 0x00, 0x02, \
|
||||
0x9d, 0x4b, 0xb2, 0x1c, 0x53, 0x53, 0x53, 0x53, \
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, \
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, \
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, \
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, \
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, \
|
||||
}
|
||||
#define TEST_TAG (0x000f)
|
||||
#define TEST_TGT_IPV6 { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x48, 0x3d, 0x1d, 0x0c, 0x98, 0x31, 0x58, 0xae }
|
||||
|
||||
const uint8_t _test_src[] = TEST_SRC;
|
||||
const uint8_t _test_dst[] = TEST_DST;
|
||||
const uint8_t _test_6lo_payload[] = TEST_6LO_PAYLOAD;
|
||||
const ipv6_addr_t _test_tgt_ipv6 = { .u8 = TEST_TGT_IPV6 };
|
||||
|
||||
static char _mock_netif_stack[THREAD_STACKSIZE_DEFAULT];
|
||||
static netdev_test_t _mock_dev;
|
||||
static gnrc_netif_t *_mock_netif;
|
||||
|
||||
void _set_up(void)
|
||||
{
|
||||
/* Add default route for the VRB entry created from */
|
||||
gnrc_ipv6_nib_ft_add(NULL, 0, &_test_tgt_ipv6, _mock_netif->pid, 0);
|
||||
}
|
||||
|
||||
void _tear_down(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_del(NULL, 0);
|
||||
gnrc_sixlowpan_frag_rb_reset();
|
||||
gnrc_sixlowpan_frag_vrb_reset();
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *_create_fragment(void)
|
||||
{
|
||||
gnrc_pktsnip_t *res = gnrc_netif_hdr_build(_test_src, sizeof(_test_src),
|
||||
_test_dst, sizeof(_test_dst));
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
gnrc_netif_hdr_set_netif(res->data, _mock_netif);
|
||||
res = gnrc_pktbuf_add(res, _test_6lo_payload, sizeof(_test_6lo_payload),
|
||||
GNRC_NETTYPE_SIXLOWPAN);
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned _dispatch_to_6lowpan(gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
unsigned res = gnrc_netapi_dispatch_receive(GNRC_NETTYPE_SIXLOWPAN,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
pkt);
|
||||
thread_yield_higher();
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool _rb_is_empty(void)
|
||||
{
|
||||
const gnrc_sixlowpan_frag_rb_t *rb = gnrc_sixlowpan_frag_rb_array();
|
||||
unsigned res = 0;
|
||||
|
||||
for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
||||
res += gnrc_sixlowpan_frag_rb_entry_empty(&rb[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _test_no_vrbe_but_rbe_exists(void)
|
||||
{
|
||||
const gnrc_sixlowpan_frag_rb_t *rb = gnrc_sixlowpan_frag_rb_array();
|
||||
unsigned rbs = 0;
|
||||
|
||||
/* VRB entry does not exist */
|
||||
TEST_ASSERT_NULL(gnrc_sixlowpan_frag_vrb_get(_test_src,
|
||||
sizeof(_test_src),
|
||||
TEST_TAG));
|
||||
/* and one reassembly buffer entry exists with the source and tag exists */
|
||||
for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_RBUF_SIZE; i++) {
|
||||
if (!gnrc_sixlowpan_frag_rb_entry_empty(&rb[i])) {
|
||||
rbs++;
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(_test_src), rb[i].super.src_len);
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(rb[i].super.src, _test_src,
|
||||
rb[i].super.src_len));
|
||||
TEST_ASSERT_EQUAL_INT(TEST_TAG, rb[i].super.tag);
|
||||
/* release packet for packet buffer check */
|
||||
gnrc_pktbuf_release(rb[i].pkt);
|
||||
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(1, rbs);
|
||||
}
|
||||
|
||||
static void test_recv__success(void)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _create_fragment();
|
||||
|
||||
TEST_ASSERT_NOT_NULL(pkt);
|
||||
TEST_ASSERT_EQUAL_INT(1, _dispatch_to_6lowpan(pkt));
|
||||
/* A VRB entry exists was created but deleted due to -ENOTSUP being
|
||||
* returned by gnrc_sixlowpan_iphc.c:_forward_frag()
|
||||
* but the reassembly buffer is empty */
|
||||
TEST_ASSERT(_rb_is_empty());
|
||||
TEST_ASSERT(gnrc_pktbuf_is_empty());
|
||||
}
|
||||
|
||||
static void test_recv__no_route(void)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _create_fragment();
|
||||
|
||||
gnrc_ipv6_nib_ft_del(NULL, 0);
|
||||
TEST_ASSERT_NOT_NULL(pkt);
|
||||
TEST_ASSERT_EQUAL_INT(1, _dispatch_to_6lowpan(pkt));
|
||||
_test_no_vrbe_but_rbe_exists();
|
||||
TEST_ASSERT(gnrc_pktbuf_is_empty());
|
||||
}
|
||||
|
||||
static void test_recv__vrb_full(void)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _create_fragment();
|
||||
gnrc_sixlowpan_frag_rb_base_t base = {
|
||||
.src = TEST_SRC,
|
||||
.src_len = sizeof(_test_src),
|
||||
.tag = TEST_TAG,
|
||||
};
|
||||
|
||||
TEST_ASSERT_NOT_NULL(pkt);
|
||||
/* Fill up VRB */
|
||||
for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) {
|
||||
base.tag++;
|
||||
base.arrival = xtimer_now_usec();
|
||||
TEST_ASSERT_NOT_NULL(gnrc_sixlowpan_frag_vrb_add(&base, _mock_netif,
|
||||
_test_dst,
|
||||
sizeof(_test_dst)));
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(1, _dispatch_to_6lowpan(pkt));
|
||||
_test_no_vrbe_but_rbe_exists();
|
||||
TEST_ASSERT(gnrc_pktbuf_is_empty());
|
||||
}
|
||||
|
||||
static void test_recv__pkt_held(void)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _create_fragment();
|
||||
|
||||
TEST_ASSERT_NOT_NULL(pkt);
|
||||
gnrc_pktbuf_hold(pkt, 1);
|
||||
TEST_ASSERT_EQUAL_INT(1, _dispatch_to_6lowpan(pkt));
|
||||
/* A VRB entry exists was created but deleted due to -ENOTSUP being
|
||||
* returned by gnrc_sixlowpan_iphc.c:_forward_frag()
|
||||
* but the reassembly buffer is empty */
|
||||
TEST_ASSERT(_rb_is_empty());
|
||||
gnrc_pktbuf_release(pkt);
|
||||
TEST_ASSERT(gnrc_pktbuf_is_empty());
|
||||
}
|
||||
|
||||
static void run_unittests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_recv__success),
|
||||
new_TestFixture(test_recv__no_route),
|
||||
new_TestFixture(test_recv__vrb_full),
|
||||
new_TestFixture(test_recv__pkt_held),
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(sixlo_iphc_vrb_tests, _set_up, _tear_down, fixtures);
|
||||
TESTS_START();
|
||||
TESTS_RUN((Test *)&sixlo_iphc_vrb_tests);
|
||||
TESTS_END();
|
||||
}
|
||||
|
||||
static int _get_netdev_device_type(netdev_t *netdev, void *value, size_t max_len)
|
||||
{
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
(void)netdev;
|
||||
|
||||
*((uint16_t *)value) = NETDEV_TYPE_IEEE802154;
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
static int _get_netdev_proto(netdev_t *netdev, void *value, size_t max_len)
|
||||
{
|
||||
assert(max_len == sizeof(gnrc_nettype_t));
|
||||
(void)netdev;
|
||||
|
||||
*((gnrc_nettype_t *)value) = GNRC_NETTYPE_SIXLOWPAN;
|
||||
return sizeof(gnrc_nettype_t);
|
||||
}
|
||||
|
||||
static int _get_netdev_max_pdu_size(netdev_t *netdev, void *value,
|
||||
size_t max_len)
|
||||
{
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
(void)netdev;
|
||||
|
||||
*((uint16_t *)value) = sizeof(_test_6lo_payload);
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
static int _get_netdev_src_len(netdev_t *netdev, void *value, size_t max_len)
|
||||
{
|
||||
(void)netdev;
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
*((uint16_t *)value) = sizeof(_test_dst);
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
static int _get_netdev_addr_long(netdev_t *netdev, void *value, size_t max_len)
|
||||
{
|
||||
(void)netdev;
|
||||
assert(max_len >= sizeof(_test_dst));
|
||||
memcpy(value, _test_dst, sizeof(_test_dst));
|
||||
return sizeof(_test_dst);
|
||||
}
|
||||
|
||||
static void _init_mock_netif(void)
|
||||
{
|
||||
netdev_test_setup(&_mock_dev, NULL);
|
||||
netdev_test_set_get_cb(&_mock_dev, NETOPT_DEVICE_TYPE,
|
||||
_get_netdev_device_type);
|
||||
netdev_test_set_get_cb(&_mock_dev, NETOPT_PROTO,
|
||||
_get_netdev_proto);
|
||||
netdev_test_set_get_cb(&_mock_dev, NETOPT_MAX_PDU_SIZE,
|
||||
_get_netdev_max_pdu_size);
|
||||
netdev_test_set_get_cb(&_mock_dev, NETOPT_SRC_LEN,
|
||||
_get_netdev_src_len);
|
||||
netdev_test_set_get_cb(&_mock_dev, NETOPT_ADDRESS_LONG,
|
||||
_get_netdev_addr_long);
|
||||
_mock_netif = gnrc_netif_ieee802154_create(
|
||||
_mock_netif_stack, THREAD_STACKSIZE_DEFAULT, GNRC_NETIF_PRIO,
|
||||
"mock_netif", (netdev_t *)&_mock_dev);
|
||||
thread_yield_higher();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
_init_mock_netif();
|
||||
run_unittests();
|
||||
return 0;
|
||||
}
|
96
tests/gnrc_sixlowpan_iphc_w_vrb/tests/01-run.py
Executable file
96
tests/gnrc_sixlowpan_iphc_w_vrb/tests/01-run.py
Executable file
@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
debug_enabled = child.expect([
|
||||
r"OK \(\d+ tests\)",
|
||||
r"6lo iphc: VRB present, trying to create entry for dst 2001:db8::2",
|
||||
])
|
||||
if debug_enabled:
|
||||
# only import scapy dependency if DEBUG_ENABLE=1
|
||||
from scapy.all import SixLoWPAN, LoWPANFragmentationFirst, \
|
||||
LoWPAN_IPHC, IPv6, ICMPv6EchoRequest
|
||||
|
||||
# test_recv__success
|
||||
child.expect_exact("6lo iphc: found route, trying to forward")
|
||||
child.expect(
|
||||
r"6lo iphc: Do not know how to forward fragment from "
|
||||
r"\((?P<vrb_src>[a-fA-F0-9:]+), (?P<vrb_src_tag>\d+)\) to "
|
||||
r"\((?P<vrb_dst>[a-fA-F0-9:]+), (?P<vrb_dst_tag>\d+)\)"
|
||||
)
|
||||
vrb_src_tag = int(child.match.group("vrb_src_tag"))
|
||||
child.expect_exact("Original fragmentation header:")
|
||||
child.expect("(?P<hex>( [A-Fa-f0-9]{2})+)")
|
||||
frag = SixLoWPAN(bytes.fromhex(child.match.group("hex")))
|
||||
assert LoWPANFragmentationFirst in frag
|
||||
assert frag[LoWPANFragmentationFirst].datagramTag == vrb_src_tag
|
||||
stream = ""
|
||||
child.expect_exact("IPHC headers + payload:")
|
||||
for _ in range(7):
|
||||
child.expect("(?P<hex>( [A-Fa-f0-9]{2})+)")
|
||||
stream += child.match.group("hex")
|
||||
iphc = SixLoWPAN(bytes.fromhex(stream))
|
||||
assert LoWPAN_IPHC in iphc
|
||||
assert IPv6 in iphc # The IPHC header after compression
|
||||
assert ICMPv6EchoRequest in iphc
|
||||
# check against fields of original fragment specified in main.c
|
||||
assert iphc[LoWPAN_IPHC].tf == 0x3
|
||||
assert iphc[LoWPAN_IPHC].nh == 0b0 # Inline (ICMPv6)
|
||||
assert iphc[LoWPAN_IPHC].hlim == 0b00 # Inline as it was decremented
|
||||
assert not iphc[LoWPAN_IPHC].cid
|
||||
assert iphc[LoWPAN_IPHC].sac == 0b0 # Stateless
|
||||
assert iphc[LoWPAN_IPHC].sam == 0b00 # Inline
|
||||
assert not iphc[LoWPAN_IPHC].m # not multicast
|
||||
assert iphc[LoWPAN_IPHC].dac == 0b0 # Stateless
|
||||
assert iphc[LoWPAN_IPHC].dam == 0b00 # Inline
|
||||
assert iphc[IPv6].src == "2001:db8::1"
|
||||
assert iphc[IPv6].dst == "2001:db8::2"
|
||||
assert iphc[IPv6].hlim == (64 - 1) # hop limit was decremented
|
||||
assert iphc[ICMPv6EchoRequest].code == 0
|
||||
assert iphc[ICMPv6EchoRequest].cksum == 0x8ea0
|
||||
assert iphc[ICMPv6EchoRequest].id == 0x238f
|
||||
assert iphc[ICMPv6EchoRequest].seq == 2
|
||||
assert iphc[ICMPv6EchoRequest].data.startswith(
|
||||
bytes.fromhex("9d4bb21c5353535353535353535353535353535353535353")
|
||||
)
|
||||
|
||||
# test_recv__no_route
|
||||
child.expect_exact(
|
||||
"6lo iphc: VRB present, trying to create entry for dst 2001:db8::2"
|
||||
)
|
||||
child.expect_exact(
|
||||
"6lo iphc: no route found, reassemble datagram normally"
|
||||
)
|
||||
|
||||
# test_recv__vrb_full
|
||||
child.expect_exact(
|
||||
"6lo iphc: VRB present, trying to create entry for dst 2001:db8::2"
|
||||
)
|
||||
child.expect_exact(
|
||||
"6lo iphc: no route found, reassemble datagram normally"
|
||||
)
|
||||
|
||||
# test_recv__pkt_held
|
||||
child.expect_exact("6lo iphc: found route, trying to forward")
|
||||
child.expect(
|
||||
r"6lo iphc: Do not know how to forward fragment from "
|
||||
r"\((?P<vrb_src>[a-fA-F0-9:]+), (?P<vrb_src_tag>\d+)\) to "
|
||||
r"\((?P<vrb_dst>[a-fA-F0-9:]+), (?P<vrb_dst_tag>\d+)\)"
|
||||
)
|
||||
child.expect_exact("Original fragmentation header:")
|
||||
child.expect_exact("IPHC headers + payload:")
|
||||
child.expect(r"OK \((\d+) tests\)")
|
||||
assert int(child.match.group(1)) >= 4
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
Loading…
Reference in New Issue
Block a user