diff --git a/tests/gnrc_ipv6_ext/Makefile b/tests/gnrc_ipv6_ext/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a4db2d10e3a192fce10988f4de140d35f3f6c8a --- /dev/null +++ b/tests/gnrc_ipv6_ext/Makefile @@ -0,0 +1,43 @@ +# name of your application +APPLICATION = gnrc_ipv6_ext + +# If no BOARD is found in the environment, use this default: +BOARD ?= native + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../.. + +BOARD_INSUFFICIENT_MEMORY := airfy-beacon chronos msb-430 msb-430h nrf51dongle \ + nrf6310 nucleo-f103 nucleo-f334 pca10000 pca10005 spark-core \ + stm32f0discovery telosb weio wsn430-v1_3b wsn430-v1_4 \ + yunjia-nrf51822 z1 + +# Include packages that pull up and auto-init the link layer. +# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present +USEMODULE += gnrc_netif_default +USEMODULE += auto_init_gnrc_netif +# Specify the mandatory networking modules for IPv6 +USEMODULE += gnrc_ipv6_router_default +# IPv6 extension headers +USEMODULE += gnrc_ipv6_ext +USEMODULE += gnrc_rpl_srh +# Add also the shell, some shell commands +USEMODULE += shell +USEMODULE += shell_commands +USEMODULE += ps + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +CFLAGS += -DDEVELHELP + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +include $(RIOTBASE)/Makefile.include + +# This requires ENABLE_DEBUG in gnrc_ipv6.c to be 1 +test: +# `testrunner` calls `make term` recursively, results in duplicated `TERMFLAGS`. +# So clears `TERMFLAGS` before run. + TERMFLAGS= tests/01-run.py diff --git a/tests/gnrc_ipv6_ext/README.md b/tests/gnrc_ipv6_ext/README.md new file mode 100644 index 0000000000000000000000000000000000000000..89650e40fb30bb7d0e133699585441ea4ef393ef --- /dev/null +++ b/tests/gnrc_ipv6_ext/README.md @@ -0,0 +1,43 @@ +# `gnrc_ipv6_ext` test + +This test sends a packet to itself with extension headers. This is based on gnrc_networking example. + +Enable debug output of `gnrc_ipv6.c` before run. When the test is run, it should show the following debug output: + +``` +ipv6: Received (src = fd01::1, dst = fd01::2, next header = 0, length = 40) +ipv6: forward nh = 0 to other threads +ipv6: unable to forward packet as no one is interested in it +ipv6: handle extension header (nh = 0) +ipv6: forward nh = 43 to other threads +ipv6: unable to forward packet as no one is interested in it +ipv6: handle extension header (nh = 43) +ipv6: waiting for incoming message. +ipv6: GNRC_NETAPI_MSG_TYPE_RCV received +ipv6: Received (src = fd01::1, dst = fd01::3, next header = 0, length = 40) +ipv6: forward nh = 0 to other threads +ipv6: unable to forward packet as no one is interested in it +ipv6: handle extension header (nh = 0) +ipv6: forward nh = 43 to other threads +ipv6: unable to forward packet as no one is interested in it +ipv6: handle extension header (nh = 43) +ipv6: waiting for incoming message. +ipv6: GNRC_NETAPI_MSG_TYPE_RCV received +ipv6: Received (src = fd01::1, dst = fd01::2, next header = 0, length = 40) +ipv6: forward nh = 0 to other threads +ipv6: unable to forward packet as no one is interested in it +ipv6: handle extension header (nh = 0) +ipv6: forward nh = 43 to other threads +ipv6: unable to forward packet as no one is interested in it +ipv6: handle extension header (nh = 43) +ipv6: forward nh = 17 to other threads +ipv6: Send receive command for 0x1060b8 to 5 +ipv6: waiting for incoming message. +pkt->users: 0 +``` + +It configures the network interface with addresses fd01::02 and fd01::03. Then it sends a packet to fd01::02 with a routing extension header containing addresses fd01::03 and fd01::02. So the packet should be forwarded from fd01::02 to fd01::03, then to fd01::02 again. + +The packet has a Hop-by-Hop extension header that should be ignored. + +The test also asserts that the packet is released. diff --git a/tests/gnrc_ipv6_ext/main.c b/tests/gnrc_ipv6_ext/main.c new file mode 100644 index 0000000000000000000000000000000000000000..ddf0c939aeba06306806d4a93ae2b822165ae7f4 --- /dev/null +++ b/tests/gnrc_ipv6_ext/main.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 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 extension header handling of gnrc stack. + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + * @author Takuo Yonezawa <Yonezawa-T2@mail.dnp.co.jp> + * + * @} + */ + +#include <stdio.h> + +#include "shell.h" +#include "msg.h" +#include "net/ipv6/addr.h" +#include "net/gnrc/ipv6/netif.h" +#include "net/gnrc/pkt.h" +#include "net/gnrc/pktbuf.h" +#include "net/gnrc/netreg.h" +#include "net/gnrc/netapi.h" +#include "net/gnrc/netif.h" + +#define MAIN_QUEUE_SIZE (8) +static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; + +static void _send_packet(void) { + kernel_pid_t ifs[GNRC_NETIF_NUMOF]; + ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; + + gnrc_netif_get(ifs); + + addr.u8[0] = 0xfd; + addr.u8[1] = 0x01; + addr.u8[15] = 0x02; + /* fd01::02 */ + gnrc_ipv6_netif_add_addr(ifs[0], &addr, 64, GNRC_IPV6_NETIF_ADDR_FLAGS_UNICAST); + + addr.u8[15] = 0x03; + /* fd01::03 */ + gnrc_ipv6_netif_add_addr(ifs[0], &addr, 64, GNRC_IPV6_NETIF_ADDR_FLAGS_UNICAST); + + uint8_t data[] = { + /* IPv6 Header */ + 0x60, 0x00, 0x00, 0x00, /* version, traffic class, flow label */ + 0x00, 0x28, /* payload length: 40 */ + 0x00, /* next header: Hop-by-Hop Option */ + 0x10, /* hop limit: 16 */ + /* source address: fd01::1 */ + 0xfd, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + /* destination address: fd01::2 */ + 0xfd, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, + + /* Hop-by-Hop Options Header */ + /* https://tools.ietf.org/html/rfc6553 */ + 0x2b, /* next header: IPv6-Route */ + 0x00, /* hdr ext len: 0 * 8 + 8 = 8 */ + 0x63, /* option type: RPL Option */ + 0x04, /* opt data len: 4 */ + 0x80, /* flags, Down: 1, Rank-Error: 0, Forwarding-Error: 0 */ + 0x00, /* RPLInstanceID */ + 0x80, 0x00, /* SenderRank */ + + /* RPL Routing Header */ + /* https://tools.ietf.org/html/rfc6554 */ + 0x11, /* next header: UDP */ + 0x02, /* hdr ext len: 2 * 8 + 8 = 24 */ + 0x03, /* routing type: SRH */ + 0x02, /* segments left: 2 */ + 0xef, /* ComprI: 14, ComprE: 15 */ + 0xd0, 0x00, 0x00, /* pad and reserved */ + /* address: fd01::3, fd01::2 */ + 0x00, 0x03, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + /* UDP (ignored) */ + 0x1f, 0x90, /* source port: 8080 */ + 0x1f, 0x90, /* destination port: 8080 */ + 0x00, 0x08, /* length: 8 */ + 0xff, 0xff, /* checksum */ + }; + + gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, data, sizeof(data), GNRC_NETTYPE_UNDEF); + + gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt); + + printf("pkt->users: %d\n", pkt->users); + assert(pkt->users == 0); +} + +int main(void) +{ + /* we need a message queue for the thread running the shell in order to + * receive potentially fast incoming networking packets */ + msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); + puts("RIOT network stack example application"); + + _send_packet(); + + /* start shell */ + puts("All up, running the shell now"); + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE); + + /* should be never reached */ + return 0; +} diff --git a/tests/gnrc_ipv6_ext/tests/01-run.py b/tests/gnrc_ipv6_ext/tests/01-run.py new file mode 100755 index 0000000000000000000000000000000000000000..0e50cb66ddeaf9a6ee85c4578122a968ed4246b6 --- /dev/null +++ b/tests/gnrc_ipv6_ext/tests/01-run.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de> +# Copyright (C) 2016 Takuo Yonezawa <Yonezawa-T2@mail.dnp.co.jp> +# +# 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 os +import sys + +sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner')) +import testrunner + +def testfunc(child): + index = child.expect_exact([ + "ipv6: Received (src = fd01::1, dst = fd01::2, next header = 0, length = 40)", + "pkt->users: 0" + ]) + + if index == 1: + # debug is disabled + return + + child.expect_exact("ipv6: handle extension header (nh = 0)") + child.expect_exact("ipv6: handle extension header (nh = 43)") + child.expect_exact("ipv6: Received (src = fd01::1, dst = fd01::3, next header = 0, length = 40)") + child.expect_exact("ipv6: handle extension header (nh = 0)") + child.expect_exact("ipv6: handle extension header (nh = 43)") + child.expect_exact("ipv6: Received (src = fd01::1, dst = fd01::2, next header = 0, length = 40)") + child.expect_exact("ipv6: handle extension header (nh = 0)") + child.expect_exact("ipv6: handle extension header (nh = 43)") + child.expect_exact("ipv6: forward nh = 17 to other threads") + child.expect_exact("pkt->users: 0") + +if __name__ == "__main__": + sys.exit(testrunner.run(testfunc))