Skip to content
Snippets Groups Projects
Commit 70c97069 authored by Martine Lenders's avatar Martine Lenders
Browse files

tests/gnrc_ipv6_ext: port to scapy

parent d9f26dbb
No related branches found
No related tags found
No related merge requests found
DEVELHELP := 1
# name of your application
include ../Makefile.tests_common
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-mega2560 arduino-uno \
chronos msb-430 msb-430h nucleo-f030r8 \
nucleo-f031k6 nucleo-f042k6 nucleo-f303k8 \
hifive1 mega-xplained msb-430 msb-430h \
nucleo-f030r8 nucleo-f031k6 nucleo-f042k6 \
nucleo-f070rb nucleo-f072rb nucleo-f303k8 \
nucleo-f334r8 nucleo-l031k6 nucleo-l053r8 \
stm32f0discovery waspmote-pro
stm32f0discovery telosb thingy52 waspmote-pro \
wsn430-v1_3b wsn430-v1_4 z1
# chronos, mips-malta, and ruuvitag boards don't support ethos
BOARD_BLACKLIST := chronos mips-malta ruuvitag
export TAP ?= tap0
# use Ethernet as link-layer protocol
USEMODULE += netdev_eth
USEMODULE += netdev_test
ifeq (native,$(BOARD))
USEMODULE += netdev_tap
TERMFLAGS ?= $(TAP)
else
USEMODULE += ethos
ETHOS_BAUDRATE ?= 115200
CFLAGS += -DETHOS_BAUDRATE=$(ETHOS_BAUDRATE) -DUSE_ETHOS_FOR_STDIO
TERMDEPS += ethos
TERMPROG ?= sudo $(RIOTTOOLS)/ethos/ethos
TERMFLAGS ?= $(TAP) $(PORT) $(ETHOS_BAUDRATE)
endif
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules for IPv6
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_icmpv6_error
USEMODULE += gnrc_pktdump
USEMODULE += gnrc_pktbuf_cmd
# IPv6 extension headers
USEMODULE += gnrc_ipv6_ext
USEMODULE += gnrc_rpl_srh
USEMODULE += gnrc_sixlowpan_iphc_nhc
# UDP
USEMODULE += gnrc_udp
USEMODULE += od
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
CFLAGS += -DGNRC_NETIF_IPV6_ADDRS_NUMOF=3
# TEST_ON_CI_WHITELIST += all
TEST_ON_CI_WHITELIST += all
.PHONY: ethos
# Note: The test can check more things with ENABLE_DEBUG set to 1 in gnrc_ipv6.c
ethos:
$(Q)env -u CC -u CFLAGS make -C $(RIOTTOOLS)/ethos
include $(RIOTBASE)/Makefile.include
# `gnrc_ipv6_ext` test
This test sends a packet to itself with extension headers. This is based on gnrc_networking example.
This test utilizes [scapy] to test the IPv6 Extension header parsing.
Enable debug output of `gnrc_ipv6.c` before run. When the test is run, it should show the following debug output:
It is intended to just test the basic parsing functionality. For specific
extension header types please provide a separate test application.
To test, compile and flash the application to any board of your liking (since
`ethos` is used to communicate with non-native boards it really doesn't matter
as long as the application fits).
```
make flash
```
And run the tests using
```
ipv6: Received (src = fd01::1, dst = fd01::2, next header = 0, length = 42)
ipv6: forward nh = 0 to other threads
ipv6: handle extension header (nh = 0)
ipv6: waiting for incoming message.
ipv6: GNRC_NETAPI_MSG_TYPE_RCV received
ipv6: Received (src = fd01::1, dst = fd01::3, next header = 0, length = 42)
ipv6: forward nh = 0 to other threads
ipv6: handle extension header (nh = 0)
ipv6: waiting for incoming message.
ipv6: GNRC_NETAPI_MSG_TYPE_RCV received
ipv6: Received (src = fd01::1, dst = fd01::2, next header = 0, length = 42)
ipv6: forward nh = 0 to other threads
ipv6: handle extension header (nh = 0)
ipv6: forward nh = 17 to other threads
ipv6: waiting for incoming message.
pkt->users: 0
sudo make test
```
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.
Note that root privileges are required since `scapy` needs to construct Ethernet
frames to properly communicate over the TAP interface.
The tests succeeds if you see the string `SUCCESS`.
The packet has a Hop-by-Hop extension header that should be ignored.
If any problems are encountered (i.e. if the test prints the sting `FAILED`),
set the echo parameter in the `run()` function at the bottom of the test script
(tests/01-run.py) to `True`. The test script will then offer a more detailed
output.
The test also asserts that the packet is released.
[scapy]: https://scapy.readthedocs.io/en/latest/
......@@ -22,152 +22,55 @@
#include <stdio.h>
#include "shell.h"
#include "msg.h"
#include "net/ethernet.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/pktdump.h"
#include "net/gnrc/netreg.h"
#include "net/gnrc/netapi.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netif/conf.h"
#include "net/gnrc/netif/ethernet.h"
#include "net/gnrc/netif/hdr.h"
#include "net/netdev_test.h"
static char _netif_stack[THREAD_STACKSIZE_SMALL];
static netdev_test_t _dev;
static char line_buf[SHELL_DEFAULT_BUFSIZE];
static gnrc_netreg_entry_t ip_entry = GNRC_NETREG_ENTRY_INIT_PID(
0, KERNEL_PID_UNDEF
);
static int _get_netdev_device_type(netdev_t *netdev, void *value, size_t max_len)
static inline void _ipreg_usage(char *cmd)
{
assert(max_len == sizeof(uint16_t));
(void)netdev;
*((uint16_t *)value) = NETDEV_TYPE_ETHERNET;
return sizeof(uint16_t);
printf("Usage: %s {reg|unreg} <protnum>", cmd);
}
static int _get_netdev_max_packet_size(netdev_t *netdev, void *value,
size_t max_len)
static int _ipreg(int argc, char **argv)
{
assert(max_len == sizeof(uint16_t));
(void)netdev;
*((uint16_t *)value) = ETHERNET_DATA_LEN;
return sizeof(uint16_t);
}
static void _init_interface(void)
{
gnrc_netif_t *netif;
ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED;
netdev_test_setup(&_dev, NULL);
netdev_test_set_get_cb(&_dev, NETOPT_DEVICE_TYPE,
_get_netdev_device_type);
netdev_test_set_get_cb(&_dev, NETOPT_MAX_PACKET_SIZE,
_get_netdev_max_packet_size);
netif = gnrc_netif_ethernet_create(
_netif_stack, THREAD_STACKSIZE_SMALL, GNRC_NETIF_PRIO,
"dummy_netif", (netdev_t *)&_dev);
addr.u8[0] = 0xfd;
addr.u8[1] = 0x01;
addr.u8[15] = 0x02;
xtimer_usleep(500); /* wait for thread to start */
/* add addresses fd01::02/64 and fd01::3/64 to interface */
for (uint8_t i = 0x2; i <= 0x3; i++) {
addr.u8[15] = i;
if (gnrc_netapi_set(netif->pid, NETOPT_IPV6_ADDR, 64U << 8U, &addr,
sizeof(addr)) < 0) {
printf("error: unable to add IPv6 address fd01::%x/64 to interface %u\n",
addr.u8[15], netif->pid);
if ((argc > 2) && (strcmp("reg", argv[1]) == 0)) {
uint32_t protnum;
if (ip_entry.target.pid != KERNEL_PID_UNDEF) {
printf("Already registered to protnum %" PRIu32 "\n",
ip_entry.demux_ctx);
return 1;
}
protnum = atoi(argv[2]);
gnrc_netreg_entry_init_pid(&ip_entry, protnum, gnrc_pktdump_pid);
gnrc_netreg_register(GNRC_NETTYPE_IPV6, &ip_entry);
printf("Registered to protocol number %" PRIu32 "\n", protnum);
}
else if ((argc > 1) && (strcmp("unreg", argv[1]) == 0)) {
printf("Unregistered from protocol number %" PRIu32 "\n",
ip_entry.demux_ctx);
gnrc_netreg_unregister(GNRC_NETTYPE_IPV6, &ip_entry);
gnrc_netreg_entry_init_pid(&ip_entry, 0, KERNEL_PID_UNDEF);
}
else {
_ipreg_usage(argv[0]);
return 1;
}
}
static void _send_packet_raw(void)
{
gnrc_netif_t *iface = gnrc_netif_iter(NULL);
gnrc_netif_hdr_t netif_hdr;
gnrc_netif_hdr_init(&netif_hdr, 8, 8);
netif_hdr.if_pid = iface->pid;
uint8_t data[] = {
/* IPv6 Header */
0x60, 0x00, 0x00, 0x00, /* version, traffic class, flow label */
0x00, 0x2a, /* payload length: 42 */
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, 0x0a, /* length: 10 */
0xff, 0xff, /* checksum */
0x00, 0x00, /* payload */
};
gnrc_pktsnip_t *netif = gnrc_pktbuf_add(NULL,
&netif_hdr,
sizeof(netif_hdr),
GNRC_NETTYPE_NETIF);
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(netif,
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);
return 0;
}
static const shell_command_t shell_commands[] = {
{ "ip", "Registers pktdump to a protocol number", _ipreg },
{ NULL, NULL, NULL }
};
int main(void)
{
puts("RIOT network stack example application");
_init_interface();
_send_packet_raw();
/* should be never reached */
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment