

12 changed files with 2313 additions and 0 deletions
@ -0,0 +1,3 @@
|
||||
MODULE := lwip_sock_udp
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @{ |
||||
* |
||||
* @file |
||||
* @author Martine Lenders <m.lenders@fu-berlin.de> |
||||
*/ |
||||
|
||||
#include <errno.h> |
||||
|
||||
#include "net/ipv4/addr.h" |
||||
#include "net/ipv6/addr.h" |
||||
#include "net/sock/udp.h" |
||||
#include "timex.h" |
||||
|
||||
#include "lwip/api.h" |
||||
#include "lwip/opt.h" |
||||
#include "lwip/sys.h" |
||||
#include "lwip/sock_internal.h" |
||||
|
||||
int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, |
||||
const sock_udp_ep_t *remote, uint16_t flags) |
||||
{ |
||||
assert(sock != NULL); |
||||
assert(local == NULL || local->port != 0); |
||||
assert(remote == NULL || remote->port != 0); |
||||
|
||||
int res; |
||||
struct netconn *tmp = NULL; |
||||
|
||||
if ((res = lwip_sock_create(&tmp, (struct _sock_tl_ep *)local, |
||||
(struct _sock_tl_ep *)remote, 0, flags, |
||||
NETCONN_UDP)) == 0) { |
||||
sock->conn = tmp; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
void sock_udp_close(sock_udp_t *sock) |
||||
{ |
||||
assert(sock != NULL); |
||||
if (sock->conn != NULL) { |
||||
netconn_delete(sock->conn); |
||||
sock->conn = NULL; |
||||
} |
||||
} |
||||
|
||||
int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *ep) |
||||
{ |
||||
assert(sock != NULL); |
||||
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep, |
||||
1)) ? -EADDRNOTAVAIL : 0; |
||||
} |
||||
|
||||
int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *ep) |
||||
{ |
||||
assert(sock != NULL); |
||||
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep, |
||||
0)) ? -ENOTCONN : 0; |
||||
} |
||||
|
||||
ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len, |
||||
uint32_t timeout, sock_udp_ep_t *remote) |
||||
{ |
||||
uint8_t *data_ptr = data; |
||||
struct netbuf *buf; |
||||
int res; |
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0)); |
||||
if ((res = lwip_sock_recv(sock->conn, timeout, &buf)) < 0) { |
||||
return res; |
||||
} |
||||
res = buf->p->tot_len; |
||||
if ((unsigned)res > max_len) { |
||||
netbuf_delete(buf); |
||||
return -ENOBUFS; |
||||
} |
||||
if (remote != NULL) { |
||||
/* convert remote */ |
||||
size_t addr_len; |
||||
#if LWIP_IPV6 |
||||
if (sock->conn->type & NETCONN_TYPE_IPV6) { |
||||
addr_len = sizeof(ipv6_addr_t); |
||||
remote->family = AF_INET6; |
||||
} |
||||
else { |
||||
#endif |
||||
#if LWIP_IPV4 |
||||
addr_len = sizeof(ipv4_addr_t); |
||||
remote->family = AF_INET; |
||||
#else |
||||
netbuf_delete(buf); |
||||
return -EPROTO; |
||||
#endif |
||||
#if LWIP_IPV6 |
||||
} |
||||
#endif |
||||
#if LWIP_NETBUF_RECVINFO |
||||
remote->netif = lwip_sock_bind_addr_to_netif(&buf->toaddr); |
||||
#else |
||||
remote->netif = SOCK_ADDR_ANY_NETIF; |
||||
#endif |
||||
/* copy address */ |
||||
memcpy(&remote->addr, &buf->addr, addr_len); |
||||
remote->port = buf->port; |
||||
} |
||||
/* copy data */ |
||||
for (struct pbuf *q = buf->p; q != NULL; q = q->next) { |
||||
memcpy(data_ptr, q->payload, q->len); |
||||
data_ptr += q->len; |
||||
} |
||||
netbuf_delete(buf); |
||||
return (ssize_t)res; |
||||
} |
||||
|
||||
ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len, |
||||
const sock_udp_ep_t *remote) |
||||
{ |
||||
assert((sock != NULL) || (remote != NULL)); |
||||
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */ |
||||
|
||||
if ((remote != NULL) && (remote->port == 0)) { |
||||
return -EINVAL; |
||||
} |
||||
return lwip_sock_send(&sock->conn, data, len, 0, (struct _sock_tl_ep *)remote, |
||||
NETCONN_UDP); |
||||
} |
||||
|
||||
/** @} */ |
@ -0,0 +1,46 @@
|
||||
APPLICATION = lwip_sock_udp
|
||||
|
||||
include ../Makefile.tests_common |
||||
|
||||
# lwIP's memory management doesn't seem to work on non 32-bit platforms at the
|
||||
# moment.
|
||||
BOARD_BLACKLIST := arduino-uno arduino-duemilanove arduino-mega2560 chronos \
|
||||
msb-430 msb-430h telosb waspmote-pro wsn430-v1_3b \
|
||||
wsn430-v1_4 z1
|
||||
BOARD_INSUFFICIENT_MEMORY = nucleo32-f042 nucleo-f030 nucleo-f042 nucleo-f334 \
|
||||
stm32f0discovery weio
|
||||
|
||||
LWIP_IPV4 ?= 0
|
||||
|
||||
ifneq (0, $(LWIP_IPV4)) |
||||
USEMODULE += ipv4_addr
|
||||
USEMODULE += lwip_arp
|
||||
USEMODULE += lwip_ipv4
|
||||
CFLAGS += -DETHARP_SUPPORT_STATIC_ENTRIES=1
|
||||
LWIP_IPV6 ?= 0
|
||||
else |
||||
LWIP_IPV6 ?= 1
|
||||
endif |
||||
|
||||
ifneq (0, $(LWIP_IPV6)) |
||||
USEMODULE += ipv6_addr
|
||||
USEMODULE += lwip_ipv6_autoconfig
|
||||
endif |
||||
|
||||
USEMODULE += inet_csum
|
||||
USEMODULE += lwip_ethernet lwip_netdev2
|
||||
USEMODULE += lwip_sock_udp
|
||||
USEMODULE += netdev2_eth
|
||||
USEMODULE += netdev2_test
|
||||
USEMODULE += ps
|
||||
|
||||
DISABLE_MODULE += auto_init
|
||||
|
||||
CFLAGS += -DDEVELHELP
|
||||
CFLAGS += -DSO_REUSE
|
||||
CFLAGS += -DLWIP_SO_RCVTIMEO
|
||||
|
||||
include $(RIOTBASE)/Makefile.include |
||||
|
||||
test: |
||||
./tests/01-run.py
|
@ -0,0 +1,33 @@
|
||||
Tests for lwIP's sock_udp port |
||||
============================== |
||||
|
||||
This tests the `sock_udp` port of lwIP. There is no network device needed since |
||||
a [virtual device](http://doc.riot-os.org/group__sys__netdev2__test.html) is |
||||
provided at the backend. |
||||
|
||||
These tests test both IPv4 and IPv6 capabilities. They can be activated by |
||||
the `LWIP_IPV4` and `LWIP_IPV6` environment variables to a non-zero value. |
||||
IPv6 is activated by default: |
||||
|
||||
```sh |
||||
make all test |
||||
# or |
||||
LWIP_IPV6=1 make all test |
||||
``` |
||||
|
||||
To just test IPv4 set the `LWIP_IPV4` to a non-zero value (IPv6 will be |
||||
deactivated automatically): |
||||
|
||||
```sh |
||||
LWIP_IPV4=1 make all test |
||||
``` |
||||
|
||||
To test both set the `LWIP_IPV4` and `LWIP_IPV6` to a non-zero value: |
||||
|
||||
```sh |
||||
LWIP_IPV4=1 LWIP_IPV6=1 make all test |
||||
``` |
||||
|
||||
Since lwIP uses a lot of macro magic to activate/deactivate these capabilities |
||||
it is advisable to **test all three configurations individually** (just IPv4, |
||||
just IPv6, IPv4/IPv6 dual stack mode). |
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup |
||||
* @ingroup |
||||
* @brief |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief |
||||
* |
||||
* @author Martine Lenders <m.lenders@fu-berlin.de> |
||||
*/ |
||||
#ifndef CONSTANTS_H_ |
||||
#define CONSTANTS_H_ |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#define _TEST_PORT_LOCAL (0x2c94) |
||||
#define _TEST_PORT_REMOTE (0xa615) |
||||
#define _TEST_NETIF (1) |
||||
#define _TEST_TIMEOUT (1000000U) |
||||
#define _TEST_ADDR4_LOCAL (0xc0a84f96U) /* 192.168.79.150 */ |
||||
#define _TEST_ADDR4_REMOTE (0xc0a84f6bU) /* 192.168.79.107 */ |
||||
#define _TEST_ADDR4_WRONG (0x254c6b4cU) |
||||
#define _TEST_ADDR4_MASK (0xffffff00U) /* 255.255.255.0 */ |
||||
#define _TEST_ADDR4_GW (0UL) /* so we can test unreachability */ |
||||
#define _TEST_ADDR6_LOCAL { 0x2f, 0xc4, 0x11, 0x5a, 0xe6, 0x91, 0x8d, 0x5d, \ |
||||
0x8c, 0xd1, 0x47, 0x07, 0xb7, 0x6f, 0x9b, 0x48 } |
||||
#define _TEST_ADDR6_REMOTE { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ |
||||
0x93, 0xcf, 0x11, 0xe1, 0x72, 0x44, 0xc5, 0x9d } |
||||
#define _TEST_ADDR6_WRONG { 0x2a, 0xce, 0x5d, 0x4e, 0xc8, 0xbf, 0x86, 0xf7, \ |
||||
0x85, 0x49, 0xb4, 0x19, 0xf2, 0x28, 0xde, 0x9b } |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* CONSTANTS_H_ */ |
||||
/** @} */ |
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @{ |
||||
* |
||||
* @file |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
|
||||
#include "msg.h" |
||||
#include "net/ethernet.h" |
||||
#include "net/ipv6.h" |
||||
#include "net/netdev2/eth.h" |
||||
#include "net/netdev2_test.h" |
||||
#include "net/sock.h" |
||||
#include "net/udp.h" |
||||
#include "sched.h" |
||||
#include "xtimer.h" |
||||
|
||||
#include "lwip.h" |
||||
#include "lwip/ip4.h" |
||||
#include "lwip/inet_chksum.h" |
||||
#include "lwip/nd6.h" |
||||
#include "lwip/netif.h" |
||||
#include "lwip/netif/netdev2.h" |
||||
#include "lwip/opt.h" |
||||
#include "lwip/tcpip.h" |
||||
#include "netif/etharp.h" |
||||
|
||||
#include "constants.h" |
||||
#include "stack.h" |
||||
|
||||
#define _MSG_QUEUE_SIZE (1) |
||||
#define _SEND_DONE (0x92d7) |
||||
#define _NETDEV_BUFFER_SIZE (128) |
||||
|
||||
static msg_t _msg_queue[_MSG_QUEUE_SIZE]; |
||||
static uint8_t _netdev_buffer[_NETDEV_BUFFER_SIZE]; |
||||
netdev2_test_t netdev; |
||||
static struct netif netif; |
||||
static kernel_pid_t _check_pid = KERNEL_PID_UNDEF; |
||||
static mutex_t _netdev_buffer_mutex = MUTEX_INIT; |
||||
static uint8_t _netdev_buffer_size; |
||||
|
||||
static inline void _get_iid(uint8_t *iid) |
||||
{ |
||||
static const uint8_t _local_ip[] = _TEST_ADDR6_LOCAL; |
||||
|
||||
memcpy(iid, &_local_ip[8], sizeof(uint64_t)); |
||||
iid[0] ^= 0x2; |
||||
} |
||||
|
||||
static int _get_max_pkt_size(netdev2_t *dev, void *value, size_t max_len) |
||||
{ |
||||
return netdev2_eth_get(dev, NETOPT_MAX_PACKET_SIZE, value, max_len); |
||||
} |
||||
|
||||
static int _get_src_len(netdev2_t *dev, void *value, size_t max_len) |
||||
{ |
||||
uint16_t *v = value; |
||||
|
||||
(void)dev; |
||||
if (max_len != sizeof(uint16_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
*v = sizeof(uint64_t); |
||||
|
||||
return sizeof(uint16_t); |
||||
} |
||||
|
||||
static int _get_addr(netdev2_t *dev, void *value, size_t max_len) |
||||
{ |
||||
uint8_t iid[ETHERNET_ADDR_LEN + 2]; |
||||
uint8_t *addr = value; |
||||
|
||||
(void)dev; |
||||
if (max_len < ETHERNET_ADDR_LEN) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
_get_iid(iid); |
||||
|
||||
addr[0] = iid[0]; |
||||
addr[1] = iid[1]; |
||||
addr[2] = iid[2]; |
||||
addr[3] = iid[5]; |
||||
addr[4] = iid[6]; |
||||
addr[5] = iid[7]; |
||||
|
||||
return ETHERNET_ADDR_LEN; |
||||
} |
||||
|
||||
static int _get_addr_len(netdev2_t *dev, void *value, size_t max_len) |
||||
{ |
||||
return netdev2_eth_get(dev, NETOPT_ADDR_LEN, value, max_len); |
||||
} |
||||
|
||||
static int _get_device_type(netdev2_t *dev, void *value, size_t max_len) |
||||
{ |
||||
return netdev2_eth_get(dev, NETOPT_DEVICE_TYPE, value, max_len); |
||||
} |
||||
|
||||
static int _get_ipv6_iid(netdev2_t *dev, void *value, size_t max_len) |
||||
{ |
||||
(void)dev; |
||||
if (max_len != sizeof(uint64_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
_get_iid(value); |
||||
return sizeof(uint64_t); |
||||
} |
||||
|
||||
static void _netdev_isr(netdev2_t *dev) |
||||
{ |
||||
dev->event_callback(dev, NETDEV2_EVENT_RX_COMPLETE); |
||||
} |
||||
|
||||
static int _netdev_recv(netdev2_t *dev, char *buf, int len, void *info) |
||||
{ |
||||
int res; |
||||
|
||||
(void)dev; |
||||
(void)info; |
||||
mutex_lock(&_netdev_buffer_mutex); |
||||
if (buf != NULL) { |
||||
if ((unsigned)len < _netdev_buffer_size) { |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
return -ENOBUFS; |
||||
} |
||||
memcpy(buf, _netdev_buffer, _netdev_buffer_size); |
||||
} |
||||
res = _netdev_buffer_size; |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
return res; |
||||
} |
||||
|
||||
static int _netdev_send(netdev2_t *dev, const struct iovec *vector, int count) |
||||
{ |
||||
msg_t done = { .type = _SEND_DONE }; |
||||
unsigned offset = 0; |
||||
|
||||
(void)dev; |
||||
mutex_lock(&_netdev_buffer_mutex); |
||||
for (int i = 0; i < count; i++) { |
||||
memcpy(&_netdev_buffer[offset], vector[i].iov_base, vector[i].iov_len); |
||||
offset += vector[i].iov_len; |
||||
if (offset > sizeof(_netdev_buffer)) { |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
return -ENOBUFS; |
||||
} |
||||
} |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
done.content.value = (uint32_t)offset - sizeof(ethernet_hdr_t) - |
||||
sizeof(udp_hdr_t); |
||||
msg_send(&done, _check_pid); |
||||
return offset; |
||||
} |
||||
|
||||
void _net_init(void) |
||||
{ |
||||
xtimer_init(); |
||||
msg_init_queue(_msg_queue, _MSG_QUEUE_SIZE); |
||||
_check_pid = sched_active_pid; |
||||
|
||||
netdev2_test_setup(&netdev, NULL); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_SRC_LEN, _get_src_len); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_MAX_PACKET_SIZE, |
||||
_get_max_pkt_size); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_ADDRESS, _get_addr); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_ADDR_LEN, |
||||
_get_addr_len); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_SRC_LEN, |
||||
_get_addr_len); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_DEVICE_TYPE, |
||||
_get_device_type); |
||||
netdev2_test_set_get_cb(&netdev, NETOPT_IPV6_IID, |
||||
_get_ipv6_iid); |
||||
netdev2_test_set_recv_cb(&netdev, _netdev_recv); |
||||
netdev2_test_set_isr_cb(&netdev, _netdev_isr); |
||||
/* netdev needs to be set-up */ |
||||
assert(netdev.netdev.driver); |
||||
#if LWIP_IPV4 |
||||
ip4_addr_t local4, mask4, gw4; |
||||
local4.addr = HTONL(_TEST_ADDR4_LOCAL); |
||||
mask4.addr = HTONL(_TEST_ADDR4_MASK); |
||||
gw4.addr = HTONL(_TEST_ADDR4_GW); |
||||
netif_add(&netif, &local4, &mask4, &gw4, &netdev, lwip_netdev2_init, tcpip_input); |
||||
#else |
||||
netif_add(&netif, &netdev, lwip_netdev2_init, tcpip_input); |
||||
#endif |
||||
#if LWIP_IPV6 |
||||
static const uint8_t local6[] = _TEST_ADDR6_LOCAL; |
||||
s8_t idx; |
||||
netif_add_ip6_address(&netif, (ip6_addr_t *)&local6, &idx); |
||||
netif_ip6_addr_set_state(&netif, idx, IP6_ADDR_VALID); |
||||
#endif |
||||
netif_set_default(&netif); |
||||
lwip_bootstrap(); |
||||
xtimer_sleep(3); /* Let the auto-configuration run warm */ |
||||
} |
||||
|
||||
void _prepare_send_checks(void) |
||||
{ |
||||
uint8_t remote6[] = _TEST_ADDR6_REMOTE; |
||||
uint8_t mac[sizeof(uint64_t)]; |
||||
|
||||
memcpy(mac, &remote6[8], sizeof(uint64_t)); |
||||
mac[0] ^= 0x2; |
||||
mac[3] = mac[5]; |
||||
mac[4] = mac[6]; |
||||
mac[5] = mac[7]; |
||||
|
||||
netdev2_test_set_send_cb(&netdev, _netdev_send); |
||||
#if LWIP_ARP |
||||
const ip4_addr_t remote4 = { .addr = HTONL(_TEST_ADDR4_REMOTE) }; |
||||
assert(ERR_OK == etharp_add_static_entry(&remote4, (struct eth_addr *)mac)); |
||||
#endif |
||||
#if LWIP_IPV6 |
||||
memset(destination_cache, 0, |
||||
LWIP_ND6_NUM_DESTINATIONS * sizeof(struct nd6_destination_cache_entry)); |
||||
memset(neighbor_cache, 0, |
||||
LWIP_ND6_NUM_NEIGHBORS * sizeof(struct nd6_neighbor_cache_entry)); |
||||
for (int i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { |
||||
struct nd6_neighbor_cache_entry *nc = &neighbor_cache[i]; |
||||
if (nc->state == ND6_NO_ENTRY) { |
||||
nc->state = ND6_REACHABLE; |
||||
memcpy(&nc->next_hop_address, remote6, sizeof(ip6_addr_t)); |
||||
memcpy(&nc->lladdr, mac, 6); |
||||
nc->netif = &netif; |
||||
nc->counter.reachable_time = UINT32_MAX; |
||||
break; |
||||
} |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
bool _inject_4packet(uint32_t src, uint32_t dst, uint16_t src_port, |
||||
uint16_t dst_port, void *data, size_t data_len, |
||||
uint16_t netif) |
||||
{ |
||||
#if LWIP_IPV4 |
||||
mutex_lock(&_netdev_buffer_mutex); |
||||
ethernet_hdr_t *eth_hdr = (ethernet_hdr_t *)_netdev_buffer; |
||||
struct ip_hdr *ip_hdr = (struct ip_hdr *)(eth_hdr + 1); |
||||
udp_hdr_t *udp_hdr = (udp_hdr_t *)(ip_hdr + 1); |
||||
uint8_t *payload = (uint8_t *)(udp_hdr + 1); |
||||
const uint16_t udp_len = (uint16_t)(sizeof(udp_hdr_t) + data_len); |
||||
(void)netif; |
||||
|
||||
_get_addr((netdev2_t *)&netdev, ð_hdr->dst, sizeof(eth_hdr->dst)); |
||||
eth_hdr->type = byteorder_htons(ETHERTYPE_IPV4); |
||||
IPH_VHL_SET(ip_hdr, 4, 5); |
||||
IPH_TOS_SET(ip_hdr, 0); |
||||
IPH_LEN_SET(ip_hdr, HTONS(sizeof(struct ip_hdr) + udp_len)); |
||||
IPH_TTL_SET(ip_hdr, 64); |
||||
IPH_PROTO_SET(ip_hdr, PROTNUM_UDP); |
||||
ip_hdr->src.addr = HTONL(src); |
||||
ip_hdr->dest.addr = HTONL(dst); |
||||
IPH_CHKSUM_SET(ip_hdr, 0); |
||||
IPH_CHKSUM_SET(ip_hdr, inet_chksum(ip_hdr, sizeof(struct ip_hdr))); |
||||
|
||||
udp_hdr->src_port = byteorder_htons(src_port); |
||||
udp_hdr->dst_port = byteorder_htons(dst_port); |
||||
udp_hdr->length.u16 = IPH_LEN(ip_hdr); |
||||
udp_hdr->checksum.u16 = 0; |
||||
|
||||
memcpy(payload, data, data_len); |
||||
|
||||
_netdev_buffer_size = sizeof(ethernet_hdr_t) + sizeof(struct ip_hdr) + |
||||
sizeof(udp_hdr_t) + data_len; |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
((netdev2_t *)&netdev)->event_callback((netdev2_t *)&netdev, NETDEV2_EVENT_ISR); |
||||
|
||||
return true; |
||||
#else |
||||
(void)src; (void)dst; (void)src_port; (void)dst_port; (void)netif; |
||||
(void)data; (void)data_len; |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
bool _inject_6packet(const ipv6_addr_t *src, const ipv6_addr_t *dst, |
||||
uint16_t src_port, uint16_t dst_port, |
||||
void *data, size_t data_len, uint16_t netif) |
||||
{ |
||||
#if LWIP_IPV6 |
||||
mutex_lock(&_netdev_buffer_mutex); |
||||
ethernet_hdr_t *eth_hdr = (ethernet_hdr_t *)_netdev_buffer; |
||||
ipv6_hdr_t *ipv6_hdr = (ipv6_hdr_t *)(eth_hdr + 1); |
||||
udp_hdr_t *udp_hdr = (udp_hdr_t *)(ipv6_hdr + 1); |
||||
uint8_t *payload = (uint8_t *)(udp_hdr + 1); |
||||
const uint16_t udp_len = (uint16_t)(sizeof(udp_hdr_t) + data_len); |
||||
uint16_t csum = 0; |
||||
(void)netif; |
||||
|
||||
_get_addr((netdev2_t *)&netdev, ð_hdr->dst, sizeof(eth_hdr->dst)); |
||||
eth_hdr->type = byteorder_htons(ETHERTYPE_IPV6); |
||||
ipv6_hdr_set_version(ipv6_hdr); |
||||
ipv6_hdr->len = byteorder_htons(udp_len); |
||||
ipv6_hdr->nh = PROTNUM_UDP; |
||||
ipv6_hdr->hl = 64; |
||||
memcpy(&ipv6_hdr->src, src, sizeof(ipv6_hdr->src)); |
||||
memcpy(&ipv6_hdr->dst, dst, sizeof(ipv6_hdr->dst)); |
||||
csum = ipv6_hdr_inet_csum(csum, ipv6_hdr, ipv6_hdr->nh, udp_len); |
||||
|
||||
udp_hdr->src_port = byteorder_htons(src_port); |
||||
udp_hdr->dst_port = byteorder_htons(dst_port); |
||||
udp_hdr->length = ipv6_hdr->len; |
||||
udp_hdr->checksum.u16 = 0; |
||||
memcpy(payload, data, data_len); |
||||
csum = inet_csum(csum, (uint8_t *)udp_hdr, udp_len); |
||||
if (csum == UINT16_MAX) { |
||||
udp_hdr->checksum = byteorder_htons(csum); |
||||
} |
||||
else { |
||||
udp_hdr->checksum = byteorder_htons(~csum); |
||||
} |
||||
_netdev_buffer_size = sizeof(ethernet_hdr_t) + sizeof(ipv6_hdr_t) + |
||||
sizeof(udp_hdr_t) + data_len; |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
((netdev2_t *)&netdev)->event_callback((netdev2_t *)&netdev, NETDEV2_EVENT_ISR); |
||||
|
||||
return true; |
||||
#else |
||||
(void)src; (void)dst; (void)src_port; (void)dst_port; (void)netif; |
||||
(void)data; (void)data_len; |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
bool _check_net(void) |
||||
{ |
||||
/* TODO maybe check packet buffer here too? */ |
||||
return true; |
||||
} |
||||
|
||||
bool _check_4packet(uint32_t src, uint32_t dst, uint16_t src_port, |
||||
uint16_t dst_port, void *data, size_t data_len, |
||||
uint16_t netif, bool random_src_port) |
||||
{ |
||||
#if LWIP_IPV4 |
||||
msg_t msg; |
||||
|
||||
(void)netif; |
||||
while (data_len != (msg.content.value - sizeof(struct ip_hdr))) { |
||||
msg_receive(&msg); |
||||
} |
||||
mutex_lock(&_netdev_buffer_mutex); |
||||
ethernet_hdr_t *eth_hdr = (ethernet_hdr_t *)_netdev_buffer; |
||||
struct ip_hdr *ip_hdr = (struct ip_hdr *)(eth_hdr + 1); |
||||
udp_hdr_t *udp_hdr = (udp_hdr_t *)(ip_hdr + 1); |
||||
uint8_t *payload = (uint8_t *)(udp_hdr + 1); |
||||
uint16_t payload_len = byteorder_ntohs(udp_hdr->length) - sizeof(udp_hdr_t); |
||||
const bool ip_correct = ((src == 0) || (src = ip_hdr->src.addr)) && |
||||
(dst = ip_hdr->dest.addr); |
||||
const bool udp_correct = (random_src_port || |
||||
(src_port == byteorder_ntohs(udp_hdr->src_port))) && |
||||
(dst_port == byteorder_ntohs(udp_hdr->dst_port)); |
||||
const bool payload_correct = (data_len == payload_len) && |
||||
(memcmp(data, payload, data_len) == 0); |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
return ip_correct && udp_correct && payload_correct; |
||||
#else |
||||
(void)src; (void)dst; (void)src_port; (void)dst_port; (void)netif; |
||||
(void)data; (void)data_len; (void)random_src_port; |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
bool _check_6packet(const ipv6_addr_t *src, const ipv6_addr_t *dst, |
||||
uint16_t src_port, uint16_t dst_port, |
||||
void *data, size_t data_len, uint16_t netif, |
||||
bool random_src_port) |
||||
{ |
||||
#if LWIP_IPV6 |
||||
msg_t msg; |
||||
|
||||
(void)netif; |
||||
while (data_len != (msg.content.value - sizeof(ipv6_hdr_t))) { |
||||
msg_receive(&msg); |
||||
} |
||||
mutex_lock(&_netdev_buffer_mutex); |
||||
ethernet_hdr_t *eth_hdr = (ethernet_hdr_t *)_netdev_buffer; |
||||
ipv6_hdr_t *ipv6_hdr = (ipv6_hdr_t *)(eth_hdr + 1); |
||||
udp_hdr_t *udp_hdr = (udp_hdr_t *)(ipv6_hdr + 1); |
||||
uint8_t *payload = (uint8_t *)(udp_hdr + 1); |
||||
uint16_t payload_len = byteorder_ntohs(udp_hdr->length) - sizeof(udp_hdr_t); |
||||
const bool ip_correct = (ipv6_addr_is_unspecified(src) || |
||||
ipv6_addr_equal(src, &ipv6_hdr->src)) && |
||||
ipv6_addr_equal(dst, &ipv6_hdr->dst); |
||||
const bool udp_correct = (random_src_port || |
||||
(src_port == byteorder_ntohs(udp_hdr->src_port))) && |
||||
(dst_port == byteorder_ntohs(udp_hdr->dst_port)); |
||||
const bool payload_correct = (data_len == payload_len) && |
||||
(memcmp(data, payload, data_len) == 0); |
||||
mutex_unlock(&_netdev_buffer_mutex); |
||||
return ip_correct && udp_correct && payload_correct; |
||||
#else |
||||
(void)src; (void)dst; (void)src_port; (void)dst_port; (void)netif; |
||||
(void)data; (void)data_len; (void)random_src_port; |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
/** @} */ |
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup |
||||
* @ingroup |
||||
* @brief |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
#ifndef STACK_H_ |
||||
#define STACK_H_ |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "net/ipv6/addr.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Initializes networking for tests |
||||
*/ |
||||
void _net_init(void); |
||||
|
||||
/**
|
||||
* @brief Does what ever preparations are needed to check the packets sent |
||||
*/ |
||||
void _prepare_send_checks(void); |
||||
|
||||
/**
|
||||
* @brief Injects a received UDPv4 packet into the stack |
||||
* |
||||
* @param[in] src The source address of the UDP packet |
||||
* @param[in] dst The destination address of the UDP packet |
||||
* @param[in] src_port The source port of the UDP packet |
||||
* @param[in] dst_port The destination port of the UDP packet |
||||
* @param[in] data The payload of the UDP packet |
||||
* @param[in] data_len The payload length of the UDP packet |
||||
* @param[in] netif The interface the packet came over |
||||
* |
||||
* @return true, if packet was successfully injected |
||||
* @return false, if an error occurred during injection |
||||
*/ |
||||
bool _inject_4packet(uint32_t src, uint32_t dst, uint16_t src_port, |
||||
uint16_t dst_port, void *data, size_t data_len, |
||||
uint16_t netif); |
||||
|
||||
/**
|
||||
* @brief Injects a received UDPv6 packet into the stack |
||||
* |
||||
* @param[in] src The source address of the UDP packet |
||||
* @param[in] dst The destination address of the UDP packet |
||||
* @param[in] src_port The source port of the UDP packet |
||||
* @param[in] dst_port The destination port of the UDP packet |
||||
* @param[in] data The payload of the UDP packet |
||||
* @param[in] data_len The payload length of the UDP packet |
||||
* @param[in] netif The interface the packet came over |
||||
* |
||||
* @return true, if packet was successfully injected |
||||
* @return false, if an error occurred during injection |
||||
*/ |
||||
bool _inject_6packet(const ipv6_addr_t *src, const ipv6_addr_t *dst, |
||||
uint16_t src_port, uint16_t dst_port, |
||||
void *data, size_t data_len, uint16_t netif); |
||||
|
||||
/**
|
||||
* @brief Checks networking state (e.g. packet buffer state) |
||||
* |
||||
* @return true, if networking component is still in valid state |
||||
* @return false, if networking component is in an invalid state |
||||
*/ |
||||
bool _check_net(void); |
||||
|
||||
/**
|
||||
* @brief Checks if a UDPv4 packet was sent by the networking component |
||||
* |
||||
* @param[in] src Expected source address of the UDP packet |
||||
* @param[in] dst Expected destination address of the UDP packet |
||||
* @param[in] src_port Expected source port of the UDP packet |
||||
* @param[in] dst_port Expected destination port of the UDP packet |
||||
* @param[in] data Expected payload of the UDP packet |
||||
* @param[in] data_len Expected payload length of the UDP packet |
||||
* @param[in] netif Expected interface the packet is supposed to |
||||
* be send over |
||||
* @param[in] random_src_port Do not check source port, it might be random |
||||
* |
||||
* @return true, if all parameters match as expected |
||||
* @return false, if not. |
||||
*/ |
||||
bool _check_4packet(uint32_t src, uint32_t dst, uint16_t src_port, |
||||
uint16_t dst_port, void *data, size_t data_len, |
||||
uint16_t netif, bool random_src_port); |
||||
|
||||
/**
|
||||
* @brief Checks if a UDPv6 packet was sent by the networking component |
||||
* |
||||
* @param[in] src Expected source address of the UDP packet |
||||
* @param[in] dst Expected destination address of the UDP packet |
||||
* @param[in] src_port Expected source port of the UDP packet |
||||
* @param[in] dst_port Expected destination port of the UDP packet |
||||
* @param[in] data Expected payload of the UDP packet |
||||
* @param[in] data_len Expected payload length of the UDP packet |
||||
* @param[in] netif Expected interface the packet is supposed to |
||||
* be send over |
||||
* @param[in] random_src_port Do not check source port, it might be random |
||||
* |
||||
* @return true, if all parameters match as expected |
||||
* @return false, if not. |
||||
*/ |
||||
bool _check_6packet(const ipv6_addr_t *src, const ipv6_addr_t *dst, |
||||
uint16_t src_port, uint16_t dst_port, |
||||
void *data, size_t data_len, uint16_t netif, |
||||
bool random_src_port); |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* STACK_H_ */ |
||||
/** @} */ |
@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
# Copyright (C) 2016 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 os |
||||
import sys |
||||
|
||||
from datetime import datetime |
||||
|
||||
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner')) |
||||
import testrunner |
||||
|
||||
class InvalidTimeout(Exception): |
||||
pass |
||||
|
||||
def _reuse_tests(code): |
||||
return code & 1 |
||||
|
||||
def _ipv6_tests(code): |
||||
return code & (1 << 6) |
||||
|
||||
def _ipv4_tests(code): |
||||
return code & (1 << 4) |
||||
|
||||
def testfunc(child): |
||||
child.expect(u"code (0x[0-9a-f]{2})") |
||||
code = int(child.match.group(1), base=16) |
||||
if _ipv4_tests(code): |
||||
if _reuse_tests(code): |
||||
child.expect_exact(u"Calling test_sock_udp_create4__EADDRINUSE()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__EAFNOSUPPORT()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__EINVAL_addr()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__EINVAL_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__no_endpoints()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__only_local()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__only_local_reuse_ep()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__only_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_create4__full()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__EADDRNOTAVAIL()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__EAGAIN()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__ENOBUFS()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__ETIMEDOUT()") |
||||
child.match # get to ensure program reached that point |
||||
start = datetime.now() |
||||
child.expect_exact(u" * Calling sock_udp_recv()") |
||||
child.expect(u" \\* \\(timed out with timeout (\\d+)\\)") |
||||
exp_diff = int(child.match.group(1)) |
||||
stop = datetime.now() |
||||
diff = (stop - start) |
||||
diff = (diff.seconds * 1000000) + diff.microseconds |
||||
# fail within 5% of expected |
||||
if diff > (exp_diff + (exp_diff * 0.05)) or \ |
||||
diff < (exp_diff - (exp_diff * 0.05)): |
||||
raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff)); |
||||
else: |
||||
print("Timed out correctly: %d (expected %d)" % (diff, exp_diff)) |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__socketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__socketed_with_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__unsocketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__unsocketed_with_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__with_timeout()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv4__non_blocking()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__EAFNOSUPPORT()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__EINVAL_addr()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__EINVAL_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__EINVAL_port()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__EHOSTUNREACH()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__ENOTCONN()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__socketed_no_local_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__socketed_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__socketed_no_local()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__socketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__socketed_other_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__unsocketed_no_local_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__unsocketed_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__unsocketed_no_local()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__unsocketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__no_sock_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send4__no_sock()") |
||||
if _ipv6_tests(code): |
||||
if _reuse_tests(code): |
||||
child.expect_exact(u"Calling test_sock_udp_create6__EADDRINUSE()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__EAFNOSUPPORT()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__EINVAL_addr()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__EINVAL_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__no_endpoints()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__only_local()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__only_local_reuse_ep()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__only_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_create6__full()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__EADDRNOTAVAIL()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__EAGAIN()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__ENOBUFS()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__ETIMEDOUT()") |
||||
child.match # get to ensure program reached that point |
||||
start = datetime.now() |
||||
child.expect_exact(u" * Calling sock_udp_recv()") |
||||
child.expect(u" \\* \\(timed out with timeout (\\d+)\\)") |
||||
exp_diff = int(child.match.group(1)) |
||||
stop = datetime.now() |
||||
diff = (stop - start) |
||||
diff = (diff.seconds * 1000000) + diff.microseconds |
||||
# fail within 5% of expected |
||||
if diff > (exp_diff + (exp_diff * 0.05)) or \ |
||||
diff < (exp_diff - (exp_diff * 0.05)): |
||||
raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff)); |
||||
else: |
||||
print("Timed out correctly: %d (expected %d)" % (diff, exp_diff)) |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__socketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__socketed_with_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__unsocketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__unsocketed_with_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__with_timeout()") |
||||
child.expect_exact(u"Calling test_sock_udp_recv6__non_blocking()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__EAFNOSUPPORT()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__EINVAL_addr()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__EINVAL_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__EINVAL_port()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__EHOSTUNREACH()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__ENOTCONN()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__socketed_no_local_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__socketed_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__socketed_no_local()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__socketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__socketed_other_remote()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__unsocketed_no_local_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__unsocketed_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__unsocketed_no_local()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__unsocketed()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__no_sock_no_netif()") |
||||
child.expect_exact(u"Calling test_sock_udp_send6__no_sock()") |
||||
child.expect_exact(u"ALL TESTS SUCCESSFUL") |
||||
|
||||
if __name__ == "__main__": |
||||
sys.exit(testrunner.run(testfunc)) |
Loading…
Reference in new issue