diff --git a/Makefile.dep b/Makefile.dep index 8259071558f41ddaa15071e0269d0f5fc5b8a6e7..812d564d3101e76b98f89a02f32df4d3590fd238 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -425,6 +425,10 @@ ifneq (,$(filter lwip_sock_ip,$(USEMODULE))) USEMODULE += lwip_raw endif +ifneq (,$(filter lwip_sock_udp,$(USEMODULE))) + USEMODULE += lwip_udp +endif + ifneq (,$(filter lwip_%,$(USEMODULE))) USEMODULE += lwip endif diff --git a/pkg/lwip/Makefile.include b/pkg/lwip/Makefile.include index d2c632630124866c21ada3b83307767b88e40584..feb293bd91e023d118632596096433168666b2a8 100644 --- a/pkg/lwip/Makefile.include +++ b/pkg/lwip/Makefile.include @@ -25,3 +25,6 @@ endif ifneq (,$(filter lwip_sock_ip,$(USEMODULE))) DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/ip endif +ifneq (,$(filter lwip_sock_udp,$(USEMODULE))) + DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/udp +endif diff --git a/pkg/lwip/contrib/sock/udp/Makefile b/pkg/lwip/contrib/sock/udp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b1e42b208b5d7d0244d12b24ff9ccade145c0ece --- /dev/null +++ b/pkg/lwip/contrib/sock/udp/Makefile @@ -0,0 +1,3 @@ +MODULE := lwip_sock_udp + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c b/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c new file mode 100644 index 0000000000000000000000000000000000000000..96a49536ef52c1c1b6a26037da8afeabdb0caf65 --- /dev/null +++ b/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c @@ -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); +} + +/** @} */ diff --git a/pkg/lwip/include/sock_types.h b/pkg/lwip/include/sock_types.h index e0d80501164623d9c8df0ad9c2faac164f5d398b..a44439715ba8d55faef1a81a35fa1cd3b3bccbeb 100644 --- a/pkg/lwip/include/sock_types.h +++ b/pkg/lwip/include/sock_types.h @@ -33,6 +33,14 @@ struct sock_ip { struct netconn *conn; }; +/** + * @brief UDP sock type + * @internal + */ +struct sock_udp { + struct netconn *conn; +}; + #ifdef __cplusplus } #endif diff --git a/tests/lwip_sock_udp/Makefile b/tests/lwip_sock_udp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5974da7edd50c79bc963db49f6fff0207e94b010 --- /dev/null +++ b/tests/lwip_sock_udp/Makefile @@ -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 diff --git a/tests/lwip_sock_udp/README.md b/tests/lwip_sock_udp/README.md new file mode 100644 index 0000000000000000000000000000000000000000..102590da1b2b1835f16e4c75d0ab63b37c90b127 --- /dev/null +++ b/tests/lwip_sock_udp/README.md @@ -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). diff --git a/tests/lwip_sock_udp/constants.h b/tests/lwip_sock_udp/constants.h new file mode 100644 index 0000000000000000000000000000000000000000..86525107b7a353894e7e2c9a7518a08eebc89d15 --- /dev/null +++ b/tests/lwip_sock_udp/constants.h @@ -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_ */ +/** @} */ diff --git a/tests/lwip_sock_udp/main.c b/tests/lwip_sock_udp/main.c new file mode 100644 index 0000000000000000000000000000000000000000..d4ad3d7d23ec76a0792c646278f419bd4539d672 --- /dev/null +++ b/tests/lwip_sock_udp/main.c @@ -0,0 +1,1346 @@ +/* + * 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. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test for UDP socks + * + * @author Martine Lenders <m.lenders@fu-berlin.de> + * @} + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +#include "net/sock/udp.h" +#include "xtimer.h" + +#include "constants.h" +#include "stack.h" + +#define _TEST_BUFFER_SIZE (128) + +static uint8_t _test_buffer[_TEST_BUFFER_SIZE]; +static sock_udp_t _sock, _sock2; + +#define CALL(fn) puts("Calling " # fn); fn; tear_down() + +static void tear_down(void) +{ + sock_udp_close(&_sock); + memset(&_sock, 0, sizeof(_sock)); +} + +#ifdef MODULE_LWIP_IPV4 +#ifdef SO_REUSE +static void test_sock_udp_create4__EADDRINUSE(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, 0)); + assert(-EADDRINUSE == sock_udp_create(&_sock2, &local, NULL, 0)); +} +#endif + +static void test_sock_udp_create4__EAFNOSUPPORT(void) +{ + /* port may not be NULL according to doc */ + static const sock_udp_ep_t local = { .family = AF_UNSPEC, + .port = _TEST_PORT_LOCAL }; + /* port may not be NULL according to doc */ + static const sock_udp_ep_t remote = { .family = AF_UNSPEC, + .port = _TEST_PORT_REMOTE }; + + assert(-EAFNOSUPPORT == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EAFNOSUPPORT == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); +} + +static void test_sock_udp_create4__EINVAL_addr(void) +{ + /* port may not be NULL according to doc */ + static const sock_udp_ep_t local = { .family = AF_INET, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + /* port may not be NULL according to doc */ + static const sock_udp_ep_t remote = { .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(-EINVAL == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); +} + +static void test_sock_udp_create4__EINVAL_netif(void) +{ + /* port may not be NULL according to doc */ + static const sock_udp_ep_t local = { .family = AF_INET, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + /* port may not be NULL according to doc */ + const sock_udp_ep_t remote = { .family = AF_INET, + .netif = (_TEST_NETIF + 1), + .port = _TEST_PORT_REMOTE, + .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) } }; + + assert(-EINVAL == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); +} + +static void test_sock_udp_create4__no_endpoints(void) +{ + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EADDRNOTAVAIL == sock_udp_get_local(&_sock, &ep)); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + +static void test_sock_udp_create4__only_local(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET == ep.family); + assert(0 == ep.addr.ipv4_u32); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_LOCAL == ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + +static void test_sock_udp_create4__only_local_reuse_ep(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t ep, ep2; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_create(&_sock2, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(0 == sock_udp_get_local(&_sock2, &ep2)); + assert(AF_INET == ep.family); + assert(0 == ep.addr.ipv4_u32); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_LOCAL == ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); + assert(AF_INET == ep2.family); + assert(0 == ep.addr.ipv4_u32); + assert(SOCK_ADDR_ANY_NETIF == ep2.netif); + assert(_TEST_PORT_LOCAL == ep2.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep2)); + sock_udp_close(&_sock2); +} + +static void test_sock_udp_create4__only_remote(void) +{ + const sock_udp_ep_t remote = { .family = AF_INET, + .port = _TEST_PORT_REMOTE, + .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) } }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); + /* lwIP binds connected sock implicitly */ + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(0 == sock_udp_get_remote(&_sock, &ep)); + assert(AF_INET == ep.family); + assert(HTONL(_TEST_ADDR4_REMOTE) == ep.addr.ipv4_u32); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_REMOTE == ep.port); +} + +static void test_sock_udp_create4__full(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .family = AF_INET, + .port = _TEST_PORT_REMOTE, + .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) } }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET == ep.family); + /* this can't be guaranteed with lwIP */ + /* assert(0 == ep.addr.ipv4_u32); */ + assert(_TEST_NETIF == ep.netif); + assert(_TEST_PORT_LOCAL == ep.port); + assert(0 == sock_udp_get_remote(&_sock, &ep)); + assert(AF_INET == ep.family); + assert(HTONL(_TEST_ADDR4_REMOTE) == ep.addr.ipv4_u32); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_REMOTE == ep.port); +} + +static void test_sock_udp_recv4__EADDRNOTAVAIL(void) +{ + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + + assert(-EADDRNOTAVAIL == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, NULL)); +} + +static void test_sock_udp_recv4__EAGAIN(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + + assert(-EAGAIN == sock_udp_recv(&_sock, _test_buffer, sizeof(_test_buffer), + 0, NULL)); +} + +static void test_sock_udp_recv4__ENOBUFS(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), _TEST_NETIF)); + assert(-ENOBUFS == sock_udp_recv(&_sock, _test_buffer, 2, SOCK_NO_TIMEOUT, + NULL)); + assert(_check_net()); +} + +static void test_sock_udp_recv4__ETIMEDOUT(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + + puts(" * Calling sock_udp_recv()"); + assert(-ETIMEDOUT == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), _TEST_TIMEOUT, + NULL)); + printf(" * (timed out with timeout %u)\n", _TEST_TIMEOUT); +} + +static void test_sock_udp_recv4__socketed(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, NULL)); + assert(_check_net()); +} + +static void test_sock_udp_recv4__socketed_with_remote(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, &result)); + assert(AF_INET == result.family); + assert(HTONL(_TEST_ADDR4_REMOTE) == result.addr.ipv4_u32); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_recv4__unsocketed(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, NULL)); + assert(_check_net()); +} + +static void test_sock_udp_recv4__unsocketed_with_remote(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, &result)); + assert(AF_INET == result.family); + assert(HTONL(_TEST_ADDR4_REMOTE) == result.addr.ipv4_u32); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_recv4__with_timeout(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), _TEST_TIMEOUT, + &result)); + assert(AF_INET == result.family); + assert(HTONL(_TEST_ADDR4_REMOTE) == result.addr.ipv4_u32); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_recv4__non_blocking(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), 0, &result)); + assert(AF_INET == result.family); + assert(HTONL(_TEST_ADDR4_REMOTE) == result.addr.ipv4_u32); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_send4__EAFNOSUPPORT(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_UNSPEC, + .port = _TEST_PORT_REMOTE }; + + assert(-EAFNOSUPPORT == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send4__EINVAL_addr(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF }; + static const sock_udp_ep_t remote = { .family = AF_INET, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EINVAL == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send4__EINVAL_netif(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF + 1 }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EINVAL == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send4__EHOSTUNREACH(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_WRONG) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(-EHOSTUNREACH == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); +} + +static void test_sock_udp_send4__EINVAL_port(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET }; + + assert(-EINVAL == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send4__ENOTCONN(void) +{ + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-ENOTCONN == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), NULL)); + assert(_check_net()); +} + +static void test_sock_udp_send4__socketed_no_local_no_netif(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_4packet(0, _TEST_ADDR4_REMOTE, 0, _TEST_PORT_REMOTE, + "ABCD", sizeof("ABCD"), SOCK_ADDR_ANY_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__socketed_no_netif(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_4packet(_TEST_ADDR4_LOCAL, _TEST_ADDR4_REMOTE, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__socketed_no_local(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_4packet(0, _TEST_ADDR4_REMOTE, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), _TEST_NETIF, + true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__socketed(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_4packet(_TEST_ADDR4_LOCAL, _TEST_ADDR4_REMOTE, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__socketed_other_remote(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t sock_remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_WRONG) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE + _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &sock_remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(_TEST_ADDR4_LOCAL, _TEST_ADDR4_REMOTE, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__unsocketed_no_local_no_netif(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(0, _TEST_ADDR4_REMOTE, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__unsocketed_no_netif(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(_TEST_ADDR4_LOCAL, _TEST_ADDR4_REMOTE, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__unsocketed_no_local(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(0, _TEST_ADDR4_REMOTE, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), _TEST_NETIF, + true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__unsocketed(void) +{ + const sock_udp_ep_t local = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_LOCAL) }, + .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(_TEST_ADDR4_LOCAL, _TEST_ADDR4_REMOTE, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__no_sock_no_netif(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .port = _TEST_PORT_REMOTE }; + + assert(sizeof("ABCD") == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(0, _TEST_ADDR4_REMOTE, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send4__no_sock(void) +{ + const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = HTONL(_TEST_ADDR4_REMOTE) }, + .family = AF_INET, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(sizeof("ABCD") == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_4packet(0, _TEST_ADDR4_REMOTE, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} +#endif /* MODULE_LWIP_IPV4 */ + +#ifdef MODULE_LWIP_IPV6 +#ifdef SO_REUSE +static void test_sock_udp_create6__EADDRINUSE(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, 0)); + assert(-EADDRINUSE == sock_udp_create(&_sock2, &local, NULL, 0)); +} +#endif + +static void test_sock_udp_create6__EAFNOSUPPORT(void) +{ + /* port may not be NULL according to doc */ + static const sock_udp_ep_t local = { .family = AF_UNSPEC, + .port = _TEST_PORT_LOCAL }; + /* port may not be NULL according to doc */ + static const sock_udp_ep_t remote = { .family = AF_UNSPEC, + .port = _TEST_PORT_REMOTE }; + + assert(-EAFNOSUPPORT == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EAFNOSUPPORT == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); +} + +static void test_sock_udp_create6__EINVAL_addr(void) +{ + /* port may not be NULL according to doc */ + static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + /* port may not be NULL according to doc */ + static const sock_udp_ep_t remote = { .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(-EINVAL == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); +} + +static void test_sock_udp_create6__EINVAL_netif(void) +{ + /* port may not be NULL according to doc */ + static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + /* port may not be NULL according to doc */ + static const sock_udp_ep_t remote = { .family = AF_INET6, + .netif = (_TEST_NETIF + 1), + .port = _TEST_PORT_REMOTE, + .addr = { .ipv6 = _TEST_ADDR6_REMOTE } }; + + assert(-EINVAL == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); +} + +static void test_sock_udp_create6__no_endpoints(void) +{ + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EADDRNOTAVAIL == sock_udp_get_local(&_sock, &ep)); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + +static void test_sock_udp_create6__only_local(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET6 == ep.family); + assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6, + sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_LOCAL == ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + +static void test_sock_udp_create6__only_local_reuse_ep(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t ep, ep2; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_create(&_sock2, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(0 == sock_udp_get_local(&_sock2, &ep2)); + assert(AF_INET6 == ep.family); + assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6, + sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_LOCAL == ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); + assert(AF_INET6 == ep2.family); + assert(memcmp(&ipv6_addr_unspecified, &ep2.addr.ipv6, + sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep2.netif); + assert(_TEST_PORT_LOCAL == ep2.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep2)); + sock_udp_close(&_sock2); +} + +static void test_sock_udp_create6__only_remote(void) +{ + static const ipv6_addr_t remote_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .family = AF_INET6, + .port = _TEST_PORT_REMOTE, + .addr = { .ipv6 = _TEST_ADDR6_REMOTE } }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); + /* lwIP binds connected sock implicitly */ + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(0 == sock_udp_get_remote(&_sock, &ep)); + assert(AF_INET6 == ep.family); + assert(memcmp(&remote_addr, &ep.addr.ipv6, sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_REMOTE == ep.port); +} + +static void test_sock_udp_create6__full(void) +{ + static const ipv6_addr_t remote_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .family = AF_INET6, + .port = _TEST_PORT_REMOTE, + .addr = { .ipv6 = _TEST_ADDR6_REMOTE } }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET6 == ep.family); + /* this can't be guaranteed with lwIP */ + /* assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6, */ + /* sizeof(ipv6_addr_t)) == 0); */ + assert(_TEST_NETIF == ep.netif); + assert(_TEST_PORT_LOCAL == ep.port); + assert(0 == sock_udp_get_remote(&_sock, &ep)); + assert(AF_INET6 == ep.family); + assert(memcmp(&remote_addr, &ep.addr.ipv6, sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(_TEST_PORT_REMOTE == ep.port); +} + +static void test_sock_udp_recv6__EADDRNOTAVAIL(void) +{ + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + + assert(-EADDRNOTAVAIL == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, NULL)); +} + +static void test_sock_udp_recv6__EAGAIN(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + + assert(-EAGAIN == sock_udp_recv(&_sock, _test_buffer, sizeof(_test_buffer), + 0, NULL)); +} + +static void test_sock_udp_recv6__ENOBUFS(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), _TEST_NETIF)); + assert(-ENOBUFS == sock_udp_recv(&_sock, _test_buffer, 2, + SOCK_NO_TIMEOUT, NULL)); + assert(_check_net()); +} + +static void test_sock_udp_recv6__ETIMEDOUT(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + + puts(" * Calling sock_udp_recv()"); + assert(-ETIMEDOUT == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), _TEST_TIMEOUT, + NULL)); + printf(" * (timed out with timeout %u)\n", _TEST_TIMEOUT); +} + +static void test_sock_udp_recv6__socketed(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, NULL)); + assert(_check_net()); +} + +static void test_sock_udp_recv6__socketed_with_remote(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, &result)); + assert(AF_INET6 == result.family); + assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_recv6__unsocketed(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, NULL)); + assert(_check_net()); +} + +static void test_sock_udp_recv6__unsocketed_with_remote(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), + SOCK_NO_TIMEOUT, &result)); + assert(AF_INET6 == result.family); + assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_recv6__with_timeout(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), _TEST_TIMEOUT, + &result)); + assert(AF_INET6 == result.family); + assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_recv6__non_blocking(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + sock_udp_ep_t result; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE, + _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), + _TEST_NETIF)); + assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer, + sizeof(_test_buffer), 0, &result)); + assert(AF_INET6 == result.family); + assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0); + assert(_TEST_PORT_REMOTE == result.port); +#if LWIP_NETBUF_RECVINFO + assert(_TEST_NETIF == result.netif); +#endif + assert(_check_net()); +} + +static void test_sock_udp_send6__EAFNOSUPPORT(void) +{ + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_UNSPEC, + .port = _TEST_PORT_REMOTE }; + + assert(-EAFNOSUPPORT == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send6__EINVAL_addr(void) +{ + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF }; + static const sock_udp_ep_t remote = { .family = AF_INET6, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EINVAL == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send6__EINVAL_netif(void) +{ + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE, + .netif = _TEST_NETIF + 1 }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-EINVAL == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send6__EHOSTUNREACH(void) +{ + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_WRONG }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + /* lwIP returns ENOMEM on failed neighbor cache lookup, since it "tries" to + * create one so we have to live with this weird behavior */ + assert(-ENOMEM == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); +} + +static void test_sock_udp_send6__EINVAL_port(void) +{ + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6 }; + + assert(-EINVAL == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), &remote)); + assert(_check_net()); +} + +static void test_sock_udp_send6__ENOTCONN(void) +{ + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(-ENOTCONN == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), NULL)); + assert(_check_net()); +} + +static void test_sock_udp_send6__socketed_no_local_no_netif(void) +{ + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_6packet(&ipv6_addr_unspecified, &dst_addr, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__socketed_no_netif(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_6packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__socketed_no_local(void) +{ + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_6packet(&ipv6_addr_unspecified, &dst_addr, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), _TEST_NETIF, + true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__socketed(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + NULL)); + assert(_check_6packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__socketed_other_remote(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t sock_remote = { .addr = { .ipv6 = _TEST_ADDR6_WRONG }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE + _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, &sock_remote, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__unsocketed_no_local_no_netif(void) +{ + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&ipv6_addr_unspecified, &dst_addr, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__unsocketed_no_netif(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__unsocketed_no_local(void) +{ + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&ipv6_addr_unspecified, &dst_addr, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), _TEST_NETIF, + true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__unsocketed(void) +{ + static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_LOCAL }; + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR6_LOCAL }, + .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_LOCAL }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, false)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__no_sock_no_netif(void) +{ + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .port = _TEST_PORT_REMOTE }; + + assert(sizeof("ABCD") == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&ipv6_addr_unspecified, &dst_addr, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + SOCK_ADDR_ANY_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} + +static void test_sock_udp_send6__no_sock(void) +{ + static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_REMOTE }; + static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE }, + .family = AF_INET6, + .netif = _TEST_NETIF, + .port = _TEST_PORT_REMOTE }; + + assert(sizeof("ABCD") == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), + &remote)); + assert(_check_6packet(&ipv6_addr_unspecified, &dst_addr, 0, + _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), + _TEST_NETIF, true)); + xtimer_usleep(1000); /* let lwIP stack finish */ + assert(_check_net()); +} +#endif /* MODULE_LWIP_IPV6 */ + +int main(void) +{ + uint8_t code = 0; + +#ifdef SO_REUSE + code |= 1; +#endif +#ifdef MODULE_LWIP_IPV4 + code |= (1 << 4); +#endif +#ifdef MODULE_LWIP_IPV6 + code |= (1 << 6); +#endif + printf("code 0x%02x\n", code); + xtimer_init(); + _net_init(); + tear_down(); +#ifdef MODULE_LWIP_IPV4 +#ifdef SO_REUSE + CALL(test_sock_udp_create4__EADDRINUSE()); +#endif + CALL(test_sock_udp_create4__EAFNOSUPPORT()); + CALL(test_sock_udp_create4__EINVAL_addr()); + CALL(test_sock_udp_create4__EINVAL_netif()); + CALL(test_sock_udp_create4__no_endpoints()); + CALL(test_sock_udp_create4__only_local()); + CALL(test_sock_udp_create4__only_local_reuse_ep()); + CALL(test_sock_udp_create4__only_remote()); + CALL(test_sock_udp_create4__full()); + /* sock_udp_close() is tested in tear_down() */ + /* sock_udp_get_local() is tested in sock_udp_create() tests */ + /* sock_udp_get_remote() is tested in sock_udp_create() tests */ + CALL(test_sock_udp_recv4__EADDRNOTAVAIL()); + CALL(test_sock_udp_recv4__EAGAIN()); + CALL(test_sock_udp_recv4__ENOBUFS()); + /* EPROTO not applicable for lwIP */ + CALL(test_sock_udp_recv4__ETIMEDOUT()); + CALL(test_sock_udp_recv4__socketed()); + CALL(test_sock_udp_recv4__socketed_with_remote()); + CALL(test_sock_udp_recv4__unsocketed()); + CALL(test_sock_udp_recv4__unsocketed_with_remote()); + CALL(test_sock_udp_recv4__with_timeout()); + CALL(test_sock_udp_recv4__non_blocking()); + _prepare_send_checks(); + CALL(test_sock_udp_send4__EAFNOSUPPORT()); + CALL(test_sock_udp_send4__EINVAL_addr()); + CALL(test_sock_udp_send4__EINVAL_netif()); + CALL(test_sock_udp_send4__EINVAL_port()); + CALL(test_sock_udp_send4__EHOSTUNREACH()); + CALL(test_sock_udp_send4__ENOTCONN()); + CALL(test_sock_udp_send4__socketed_no_local_no_netif()); + CALL(test_sock_udp_send4__socketed_no_netif()); + CALL(test_sock_udp_send4__socketed_no_local()); + CALL(test_sock_udp_send4__socketed()); + CALL(test_sock_udp_send4__socketed_other_remote()); + CALL(test_sock_udp_send4__unsocketed_no_local_no_netif()); + CALL(test_sock_udp_send4__unsocketed_no_netif()); + CALL(test_sock_udp_send4__unsocketed_no_local()); + CALL(test_sock_udp_send4__unsocketed()); + CALL(test_sock_udp_send4__no_sock_no_netif()); + CALL(test_sock_udp_send4__no_sock()); +#endif /* MODULE_LWIP_IPV4 */ +#ifdef MODULE_LWIP_IPV6 +#ifdef SO_REUSE + CALL(test_sock_udp_create6__EADDRINUSE()); +#endif + CALL(test_sock_udp_create6__EAFNOSUPPORT()); + CALL(test_sock_udp_create6__EINVAL_addr()); + CALL(test_sock_udp_create6__EINVAL_netif()); + CALL(test_sock_udp_create6__no_endpoints()); + CALL(test_sock_udp_create6__only_local()); + CALL(test_sock_udp_create6__only_local_reuse_ep()); + CALL(test_sock_udp_create6__only_remote()); + CALL(test_sock_udp_create6__full()); + /* sock_udp_close() is tested in tear_down() */ + /* sock_udp_get_local() is tested in sock_udp_create() tests */ + /* sock_udp_get_remote() is tested in sock_udp_create() tests */ + CALL(test_sock_udp_recv6__EADDRNOTAVAIL()); + CALL(test_sock_udp_recv6__EAGAIN()); + CALL(test_sock_udp_recv6__ENOBUFS()); + /* EPROTO not applicable for lwIP */ + CALL(test_sock_udp_recv6__ETIMEDOUT()); + CALL(test_sock_udp_recv6__socketed()); + CALL(test_sock_udp_recv6__socketed_with_remote()); + CALL(test_sock_udp_recv6__unsocketed()); + CALL(test_sock_udp_recv6__unsocketed_with_remote()); + CALL(test_sock_udp_recv6__with_timeout()); + CALL(test_sock_udp_recv6__non_blocking()); + _prepare_send_checks(); + CALL(test_sock_udp_send6__EAFNOSUPPORT()); + CALL(test_sock_udp_send6__EINVAL_addr()); + CALL(test_sock_udp_send6__EINVAL_netif()); + CALL(test_sock_udp_send6__EINVAL_port()); + CALL(test_sock_udp_send6__EHOSTUNREACH()); + CALL(test_sock_udp_send6__ENOTCONN()); + CALL(test_sock_udp_send6__socketed_no_local_no_netif()); + CALL(test_sock_udp_send6__socketed_no_netif()); + CALL(test_sock_udp_send6__socketed_no_local()); + CALL(test_sock_udp_send6__socketed()); + CALL(test_sock_udp_send6__socketed_other_remote()); + CALL(test_sock_udp_send6__unsocketed_no_local_no_netif()); + CALL(test_sock_udp_send6__unsocketed_no_netif()); + CALL(test_sock_udp_send6__unsocketed_no_local()); + CALL(test_sock_udp_send6__unsocketed()); + CALL(test_sock_udp_send6__no_sock_no_netif()); + CALL(test_sock_udp_send6__no_sock()); +#endif /* MODULE_LWIP_IPV6 */ + + puts("ALL TESTS SUCCESSFUL"); + + return 0; +} diff --git a/tests/lwip_sock_udp/stack.c b/tests/lwip_sock_udp/stack.c new file mode 100644 index 0000000000000000000000000000000000000000..5c90f6654d91aaad9602f0662919c813e36812f4 --- /dev/null +++ b/tests/lwip_sock_udp/stack.c @@ -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 +} + +/** @} */ diff --git a/tests/lwip_sock_udp/stack.h b/tests/lwip_sock_udp/stack.h new file mode 100644 index 0000000000000000000000000000000000000000..3f856f2a888ae8bcac55bbc0514055344789c563 --- /dev/null +++ b/tests/lwip_sock_udp/stack.h @@ -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_ */ +/** @} */ diff --git a/tests/lwip_sock_udp/tests/01-run.py b/tests/lwip_sock_udp/tests/01-run.py new file mode 100755 index 0000000000000000000000000000000000000000..645fcfa8d5aba38bf6e3b91da8b23815e434f7b0 --- /dev/null +++ b/tests/lwip_sock_udp/tests/01-run.py @@ -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))