mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pkg: provide sock_ip support for lwip
This commit is contained in:
parent
e547ff1d60
commit
bf60c2fbfa
@ -413,6 +413,14 @@ ifneq (,$(filter lwip_conn_udp,$(USEMODULE)))
|
||||
USEMODULE += lwip_udp
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lwip_sock_%,$(USEMODULE)))
|
||||
USEMODULE += lwip_sock
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lwip_sock_ip,$(USEMODULE)))
|
||||
USEMODULE += lwip_raw
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lwip_%,$(USEMODULE)))
|
||||
USEMODULE += lwip
|
||||
endif
|
||||
@ -438,6 +446,7 @@ endif
|
||||
|
||||
ifneq (,$(filter lwip_contrib,$(USEMODULE)))
|
||||
USEMODULE += sema
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sema,$(USEMODULE)))
|
||||
|
@ -16,3 +16,12 @@ endif
|
||||
ifneq (,$(filter lwip_netdev2,$(USEMODULE)))
|
||||
DIRS += $(RIOTBASE)/pkg/lwip/contrib/netdev2
|
||||
endif
|
||||
ifneq (,$(filter lwip_sock,$(USEMODULE)))
|
||||
ifneq (,$(filter lwip_ipv6,$(USEMODULE)))
|
||||
CFLAGS += -DSOCK_HAS_IPV6
|
||||
endif
|
||||
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock
|
||||
endif
|
||||
ifneq (,$(filter lwip_sock_ip,$(USEMODULE)))
|
||||
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/ip
|
||||
endif
|
||||
|
3
pkg/lwip/contrib/sock/Makefile
Normal file
3
pkg/lwip/contrib/sock/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE := lwip_sock
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
pkg/lwip/contrib/sock/ip/Makefile
Normal file
3
pkg/lwip/contrib/sock/ip/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE := lwip_sock_ip
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
181
pkg/lwip/contrib/sock/ip/lwip_sock_ip.c
Normal file
181
pkg/lwip/contrib/sock/ip/lwip_sock_ip.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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/ipv6/hdr.h"
|
||||
#include "net/sock/ip.h"
|
||||
#include "timex.h"
|
||||
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/ip4.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/sock_internal.h"
|
||||
|
||||
|
||||
int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
|
||||
const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
|
||||
{
|
||||
assert(sock != NULL);
|
||||
|
||||
int res;
|
||||
struct netconn *tmp = NULL;
|
||||
|
||||
/* we pay attention in lwip_sock_create that _sock_tl_ep::port is not
|
||||
* touched for RAW */
|
||||
if ((res = lwip_sock_create(&tmp, (struct _sock_tl_ep *)local,
|
||||
(struct _sock_tl_ep *)remote, proto, flags,
|
||||
NETCONN_RAW)) == 0) {
|
||||
sock->conn = tmp;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void sock_ip_close(sock_ip_t *sock)
|
||||
{
|
||||
assert(sock != NULL);
|
||||
if (sock->conn != NULL) {
|
||||
netconn_delete(sock->conn);
|
||||
sock->conn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *ep)
|
||||
{
|
||||
assert(sock != NULL);
|
||||
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
|
||||
1)) ? -EADDRNOTAVAIL : 0;
|
||||
}
|
||||
|
||||
int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *ep)
|
||||
{
|
||||
assert(sock != NULL);
|
||||
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
|
||||
0)) ? -ENOTCONN : 0;
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
static uint16_t _ip4_addr_to_netif(const ip4_addr_p_t *addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
|
||||
if (!ip4_addr_isany(addr)) {
|
||||
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (netif_ip4_addr(netif)->addr == addr->addr) {
|
||||
return (int)netif->num + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SOCK_ADDR_ANY_NETIF;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV6
|
||||
static uint16_t _ip6_addr_to_netif(const ip6_addr_p_t *_addr)
|
||||
{
|
||||
ip6_addr_t addr;
|
||||
|
||||
assert(_addr != NULL);
|
||||
ip6_addr_copy(addr, *_addr);
|
||||
if (!ip6_addr_isany_val(addr)) {
|
||||
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (netif_get_ip6_addr_match(netif, &addr) >= 0) {
|
||||
return (int)netif->num + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SOCK_ADDR_ANY_NETIF;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _parse_iphdr(const struct netbuf *buf, void *data, size_t max_len,
|
||||
sock_ip_ep_t *remote)
|
||||
{
|
||||
uint8_t *data_ptr = buf->p->payload;
|
||||
size_t data_len = buf->p->len;
|
||||
|
||||
assert(buf->p->next == NULL); /* TODO this might not be generally the case
|
||||
* check later with larger payloads */
|
||||
switch (data_ptr[0] >> 4) {
|
||||
#if LWIP_IPV4
|
||||
case 4:
|
||||
if ((data_len - sizeof(struct ip_hdr)) > max_len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (remote != NULL) {
|
||||
struct ip_hdr *iphdr = (struct ip_hdr *)data_ptr;
|
||||
|
||||
assert(buf->p->len > sizeof(struct ip_hdr));
|
||||
remote->family = AF_INET;
|
||||
memcpy(&remote->addr, &iphdr->src, sizeof(ip4_addr_t));
|
||||
remote->netif = _ip4_addr_to_netif(&iphdr->dest);
|
||||
}
|
||||
data_ptr += sizeof(struct ip_hdr);
|
||||
data_len -= sizeof(struct ip_hdr);
|
||||
break;
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
case 6:
|
||||
if ((data_len - sizeof(struct ip6_hdr)) > max_len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (remote != NULL) {
|
||||
struct ip6_hdr *iphdr = (struct ip6_hdr *)data_ptr;
|
||||
|
||||
assert(buf->p->len > sizeof(struct ip6_hdr));
|
||||
remote->family = AF_INET6;
|
||||
memcpy(&remote->addr, &iphdr->src, sizeof(ip6_addr_t));
|
||||
remote->netif = _ip6_addr_to_netif(&iphdr->dest);
|
||||
}
|
||||
data_ptr += sizeof(struct ip6_hdr);
|
||||
data_len -= sizeof(struct ip6_hdr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EPROTO;
|
||||
}
|
||||
memcpy(data, data_ptr, data_len);
|
||||
return (ssize_t)data_len;
|
||||
}
|
||||
|
||||
ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
|
||||
uint32_t timeout, sock_ip_ep_t *remote)
|
||||
{
|
||||
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 = _parse_iphdr(buf, data, max_len, remote);
|
||||
netbuf_delete(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
|
||||
uint8_t proto, const sock_ip_ep_t *remote)
|
||||
{
|
||||
assert((sock != NULL) || (remote != NULL));
|
||||
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
|
||||
return lwip_sock_send(&sock->conn, data, len, proto,
|
||||
(struct _sock_tl_ep *)remote, NETCONN_RAW);
|
||||
}
|
||||
|
||||
/** @} */
|
526
pkg/lwip/contrib/sock/lwip_sock.c
Normal file
526
pkg/lwip/contrib/sock/lwip_sock.c
Normal file
@ -0,0 +1,526 @@
|
||||
/*
|
||||
* 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 "lwip/sock_internal.h"
|
||||
|
||||
#include "net/af.h"
|
||||
#include "net/ipv4/addr.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/sock.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if !LWIP_IPV4 && !LWIP_IPV6
|
||||
#error "lwip_sock needs IPv4 or IPv6 support"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Checks if an address family is *not* supported by the lwIP
|
||||
* implementation
|
||||
*
|
||||
* @param[in] af An address family
|
||||
*
|
||||
* @return true, if @p af is *not* supported.
|
||||
* @return false, if @p af is supported.
|
||||
*/
|
||||
static inline bool _af_not_supported(int af)
|
||||
{
|
||||
switch (af) {
|
||||
#if LWIP_IPV4
|
||||
case AF_INET:
|
||||
return false;
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
case AF_INET6:
|
||||
return false;
|
||||
#endif
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
static inline u8_t lwip_af_to_ip_addr_type(int af)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return IPADDR_TYPE_V4;
|
||||
case AF_INET6:
|
||||
case AF_UNSPEC: /* in case of any address */
|
||||
return IPADDR_TYPE_V6;
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool _ep_isany(const struct _sock_tl_ep *ep)
|
||||
{
|
||||
uint8_t *ep_addr;
|
||||
|
||||
if (ep == NULL) {
|
||||
return true;
|
||||
}
|
||||
ep_addr = (uint8_t *)&ep->addr;
|
||||
for (unsigned i = 0; i < sizeof(ep->addr); i++) {
|
||||
#if LWIP_IPV4
|
||||
/* stop checking IPv6 for IPv4 addresses */
|
||||
if ((ep->family == AF_INET) && i >= sizeof(ep->addr.ipv4)) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (ep_addr[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const ip_addr_t *_netif_to_bind_addr(int family, uint16_t netif_num)
|
||||
{
|
||||
if (netif_num > UINT8_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (netif->num == (netif_num - 1)) {
|
||||
switch (family) {
|
||||
#if LWIP_IPV4
|
||||
case AF_INET:
|
||||
return &netif->ip_addr;
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
case AF_INET6:
|
||||
/* link-local address is always the 0th */
|
||||
return &netif->ip6_addr[0];
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool _addr_on_netif(int family, int netif_num, const ip_addr_t *addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert((netif_num >= 0) && (netif_num <= UINT8_MAX));
|
||||
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (netif->num == (netif_num - 1)) {
|
||||
switch (family) {
|
||||
#if LWIP_IPV4
|
||||
case AF_INET:
|
||||
return ip_2_ip4(&netif->ip_addr)->addr == ip_2_ip4(addr)->addr;
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
case AF_INET6:
|
||||
/* link-local address is always the 0th */
|
||||
return (netif_get_ip6_addr_match(netif, ip_2_ip6(addr)) >= 0);
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MODULE_LWIP_SOCK_IP
|
||||
#define _set_port(p, ep, type) \
|
||||
if (!((type) & NETCONN_RAW)) { \
|
||||
p = (ep)->port; \
|
||||
}
|
||||
#else
|
||||
#define _set_port(p, ep, type) \
|
||||
p = (ep)->port;
|
||||
#endif
|
||||
|
||||
static int _sock_ep_to_netconn_pars(const struct _sock_tl_ep *local,
|
||||
const struct _sock_tl_ep *remote,
|
||||
ip_addr_t *local_addr, u16_t *local_port,
|
||||
ip_addr_t *remote_addr, u16_t *remote_port,
|
||||
int *type)
|
||||
{
|
||||
bool res = 0;
|
||||
int family = AF_UNSPEC;
|
||||
uint16_t netif = SOCK_ADDR_ANY_NETIF;
|
||||
|
||||
if ((local != NULL) && (remote != NULL) &&
|
||||
(remote->netif != SOCK_ADDR_ANY_NETIF) &&
|
||||
(local->netif != SOCK_ADDR_ANY_NETIF) &&
|
||||
(remote->netif != local->netif)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
*type &= ~NETCONN_TYPE_IPV6;
|
||||
#else
|
||||
(void)type; /* is read but not set => compiler complains */
|
||||
#endif
|
||||
if (local != NULL) {
|
||||
if (_af_not_supported(local->family)) {
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
if (local->netif != SOCK_ADDR_ANY_NETIF) {
|
||||
netif = local->netif;
|
||||
}
|
||||
family = local->family;
|
||||
_set_port(*local_port, local, *type);
|
||||
}
|
||||
if (remote != NULL) {
|
||||
if (_af_not_supported(remote->family) ||
|
||||
((local != NULL) && (local->family != remote->family))) {
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
if ((remote->netif != SOCK_ADDR_ANY_NETIF) &&
|
||||
(local != NULL) && (local->netif != SOCK_ADDR_ANY_NETIF)) {
|
||||
netif = remote->netif;
|
||||
}
|
||||
family = remote->family;
|
||||
memcpy(remote_addr, &remote->addr, sizeof(remote->addr));
|
||||
#if LWIP_IPV6 && LWIP_IPV4
|
||||
remote_addr->type = lwip_af_to_ip_addr_type(family);
|
||||
#endif
|
||||
if (ip_addr_isany(remote_addr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
_set_port(*remote_port, remote, *type);
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (family == AF_INET6) {
|
||||
*type |= NETCONN_TYPE_IPV6;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (netif != SOCK_ADDR_ANY_NETIF) {
|
||||
if (_ep_isany(local)) {
|
||||
const ip_addr_t *tmp = _netif_to_bind_addr(family, netif);
|
||||
if (tmp != NULL) {
|
||||
memcpy(local_addr, tmp, sizeof(ip_addr_t));
|
||||
res = 1;
|
||||
}
|
||||
else {
|
||||
/* netif was not a valid interface */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
/* case (local == NULL) is included in _ep_isany() */
|
||||
/* cast to ip_addr_t alright, since type field is never used */
|
||||
else if (_addr_on_netif(family, netif, (ip_addr_t *)&local->addr)) {
|
||||
memcpy(local_addr, &local->addr, sizeof(local->addr));
|
||||
res = 1;
|
||||
}
|
||||
else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else if (local != NULL) {
|
||||
memcpy(local_addr, &local->addr, sizeof(local->addr));
|
||||
res = 1;
|
||||
}
|
||||
#if LWIP_IPV6 && LWIP_IPV4
|
||||
if (local_addr != NULL) {
|
||||
local_addr->type = lwip_af_to_ip_addr_type(family);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _create(int type, int proto, uint16_t flags, struct netconn **out)
|
||||
{
|
||||
if ((*out = netconn_new_with_proto_and_callback(type, proto, NULL)) == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
#if SO_REUSE
|
||||
if (flags & SOCK_FLAGS_REUSE_EP) {
|
||||
ip_set_option((*out)->pcb.ip, SOF_REUSEADDR);
|
||||
}
|
||||
#else
|
||||
(void)flags;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int lwip_sock_create(struct netconn **conn, const struct _sock_tl_ep *local,
|
||||
const struct _sock_tl_ep *remote, int proto,
|
||||
uint16_t flags, int type)
|
||||
{
|
||||
assert(conn != NULL);
|
||||
#if LWIP_IPV6
|
||||
assert(!(type & NETCONN_TYPE_IPV6));
|
||||
#endif
|
||||
|
||||
ip_addr_t local_addr, remote_addr;
|
||||
u16_t local_port = 0, remote_port = 0; /* 0 is used by lwIP to
|
||||
* automatically generate
|
||||
* port */
|
||||
/* convert parameters */
|
||||
int bind = _sock_ep_to_netconn_pars(local, remote, &local_addr, &local_port,
|
||||
&remote_addr, &remote_port, &type);
|
||||
|
||||
/* error occurred during parameter conversion */
|
||||
if (bind < 0) {
|
||||
return bind;
|
||||
}
|
||||
if ((remote != NULL) && ip_addr_isany_val(remote_addr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
/* if local or remote parameters are given */
|
||||
else if ((local != NULL) || (remote != NULL)) {
|
||||
int res = 0;
|
||||
if ((res = _create(type, proto, flags, conn)) < 0) {
|
||||
return res;
|
||||
}
|
||||
/* if parameters (local->netif, remote->netif, local->addr or
|
||||
* local->port) demand binding */
|
||||
if (bind) {
|
||||
switch (netconn_bind(*conn, &local_addr, local_port)) {
|
||||
case ERR_USE:
|
||||
res = -EADDRINUSE;
|
||||
break;
|
||||
case ERR_VAL:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (res < 0) {
|
||||
netconn_delete(*conn);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (remote != NULL) {
|
||||
switch (netconn_connect(*conn, &remote_addr, remote_port)) {
|
||||
case ERR_USE:
|
||||
res = -EADDRINUSE;
|
||||
break;
|
||||
case ERR_VAL:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (res < 0) {
|
||||
netconn_delete(*conn);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t lwip_sock_bind_addr_to_netif(const ip_addr_t *bind_addr)
|
||||
{
|
||||
assert(bind_addr != NULL);
|
||||
|
||||
if (!ip_addr_isany(bind_addr)) {
|
||||
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (IP_IS_V6(bind_addr)) { /* XXX crappy API yields crappy code */
|
||||
#if LWIP_IPV6
|
||||
if (netif_get_ip6_addr_match(netif, ip_2_ip6(bind_addr)) >= 0) {
|
||||
return (int)netif->num + 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#if LWIP_IPV4
|
||||
if (netif_ip4_addr(netif)->addr == ip_2_ip4(bind_addr)->addr) {
|
||||
return (int)netif->num + 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return SOCK_ADDR_ANY_NETIF;
|
||||
}
|
||||
|
||||
int lwip_sock_get_addr(struct netconn *conn, struct _sock_tl_ep *ep, u8_t local)
|
||||
{
|
||||
ip_addr_t addr;
|
||||
int res;
|
||||
#ifdef MODULE_LWIP_SOCK_IP
|
||||
u16_t port = UINT16_MAX;
|
||||
u16_t *port_ptr = &port;
|
||||
/* addr needs to be NULL because netconn_getaddr returns error on connected
|
||||
* conns as "as connecting is only a helper for upper layers [sic]" */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#else
|
||||
u16_t *port_ptr = &ep->port;
|
||||
#endif
|
||||
|
||||
assert(ep != NULL);
|
||||
if (conn == NULL) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef MODULE_LWIP_SOCK_IP
|
||||
if (!(conn->type & NETCONN_RAW)) {
|
||||
port_ptr = &ep->port;
|
||||
}
|
||||
#endif
|
||||
if ((res = netconn_getaddr(conn, &addr, port_ptr, local)) != ERR_OK
|
||||
#ifdef MODULE_LWIP_SOCK_IP
|
||||
/* XXX lwIP's API is very inconsistent here so we need to check if addr
|
||||
* was changed */
|
||||
&& !local && ip_addr_isany_val(addr)
|
||||
#endif
|
||||
) {
|
||||
return res;
|
||||
}
|
||||
#if LWIP_IPV6 && LWIP_IPV4
|
||||
ep->family = (addr.type == IPADDR_TYPE_V6) ? AF_INET6 : AF_INET;
|
||||
#elif LWIP_IPV6
|
||||
ep->family = (conn->type & NETCONN_TYPE_IPV6) ? AF_INET6 : AF_INET;
|
||||
#elif LWIP_IPV4
|
||||
ep->family = AF_INET;
|
||||
#endif
|
||||
if (local) {
|
||||
ep->netif = lwip_sock_bind_addr_to_netif(&addr);
|
||||
}
|
||||
else {
|
||||
ep->netif = SOCK_ADDR_ANY_NETIF;
|
||||
}
|
||||
memcpy(&ep->addr, &addr, sizeof(ep->addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lwip_sock_recv(struct netconn *conn, uint32_t timeout, struct netbuf **buf)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (conn == NULL) {
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if ((timeout != 0) && (timeout != SOCK_NO_TIMEOUT)) {
|
||||
netconn_set_recvtimeout(conn, timeout / MS_IN_USEC);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((timeout == 0) && !cib_avail(&conn->recvmbox.mbox.cib)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
switch (netconn_recv(conn, buf)) {
|
||||
case ERR_OK:
|
||||
res = 0;
|
||||
break;
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case ERR_TIMEOUT:
|
||||
res = -ETIMEDOUT;
|
||||
break;
|
||||
#endif
|
||||
case ERR_MEM:
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
default:
|
||||
res = -EPROTO;
|
||||
break;
|
||||
}
|
||||
/* unset flags */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
netconn_set_recvtimeout(conn, 0);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t lwip_sock_send(struct netconn **conn, const void *data, size_t len,
|
||||
int proto, const struct _sock_tl_ep *remote, int type)
|
||||
{
|
||||
ip_addr_t remote_addr;
|
||||
struct netconn *tmp;
|
||||
struct netbuf *buf;
|
||||
int res;
|
||||
err_t err;
|
||||
u16_t remote_port = 0;
|
||||
|
||||
#if LWIP_IPV6
|
||||
assert(!(type & NETCONN_TYPE_IPV6));
|
||||
#endif
|
||||
if (remote != NULL) {
|
||||
if ((res = _sock_ep_to_netconn_pars(NULL, remote, NULL, NULL,
|
||||
&remote_addr, &remote_port,
|
||||
&type)) < 0) {
|
||||
return res;
|
||||
}
|
||||
if (ip_addr_isany_val(remote_addr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
buf = netbuf_new();
|
||||
if ((buf == NULL) || (netbuf_alloc(buf, len) == NULL) ||
|
||||
(netbuf_take(buf, data, len) != ERR_OK)) {
|
||||
netbuf_delete(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (((conn == NULL) || (*conn == NULL)) && (remote != NULL)) {
|
||||
if ((res = _create(type, proto, 0, &tmp)) < 0) {
|
||||
netbuf_delete(buf);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else if (*conn != NULL) {
|
||||
ip_addr_t addr;
|
||||
u16_t port;
|
||||
|
||||
if (((remote != NULL) &&
|
||||
(remote->netif != SOCK_ADDR_ANY_NETIF) &&
|
||||
(netconn_getaddr(*conn, &addr, &port, 1) == 0) &&
|
||||
(remote->netif != lwip_sock_bind_addr_to_netif(&addr)))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
tmp = *conn;
|
||||
}
|
||||
else {
|
||||
netbuf_delete(buf);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (remote != NULL) {
|
||||
err = netconn_sendto(tmp, buf, &remote_addr, remote_port);
|
||||
}
|
||||
else {
|
||||
err = netconn_send(tmp, buf);
|
||||
}
|
||||
switch (err) {
|
||||
case ERR_OK:
|
||||
res = len;
|
||||
if (conn != NULL) {
|
||||
*conn = tmp;
|
||||
}
|
||||
break;
|
||||
case ERR_BUF:
|
||||
case ERR_MEM:
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
case ERR_RTE:
|
||||
case ERR_IF:
|
||||
res = -EHOSTUNREACH;
|
||||
break;
|
||||
case ERR_VAL:
|
||||
default:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
netbuf_delete(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
59
pkg/lwip/include/lwip/sock_internal.h
Normal file
59
pkg/lwip/include/lwip/sock_internal.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 pkg_lwip_sock lwIP-specific implementation of sock API
|
||||
* @ingroup pkg_lwip
|
||||
* @brief Provides an implementation of the @ref net_sock for the
|
||||
* @ref pkg_lwip
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief lwIP-specific function @ref definitions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef SOCK_INTERNAL_H_
|
||||
#define SOCK_INTERNAL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "net/af.h"
|
||||
#include "net/sock.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Internal helper functions for lwIP
|
||||
* @internal
|
||||
* @{
|
||||
*/
|
||||
int lwip_sock_create(struct netconn **conn, const struct _sock_tl_ep *local,
|
||||
const struct _sock_tl_ep *remote, int proto,
|
||||
uint16_t flags, int type);
|
||||
uint16_t lwip_sock_bind_addr_to_netif(const ip_addr_t *bind_addr);
|
||||
int lwip_sock_get_addr(struct netconn *conn, struct _sock_tl_ep *ep, u8_t local);
|
||||
int lwip_sock_recv(struct netconn *conn, uint32_t timeout, struct netbuf **buf);
|
||||
ssize_t lwip_sock_send(struct netconn **conn, const void *data, size_t len,
|
||||
int proto, const struct _sock_tl_ep *remote, int type);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SOCK_INTERNAL_H_ */
|
||||
/** @} */
|
@ -129,7 +129,7 @@ extern "C" {
|
||||
#define LWIP_UDPLITE (0)
|
||||
#endif /* MODULE_LWIP_UDPLITE */
|
||||
|
||||
#ifdef MODULE_LWIP_CONN
|
||||
#if defined(MODULE_LWIP_CONN) || defined(MODULE_LWIP_SOCK)
|
||||
#define LWIP_NETCONN (1)
|
||||
#else
|
||||
#define LWIP_NETCONN (0)
|
||||
|
41
pkg/lwip/include/sock_types.h
Normal file
41
pkg/lwip/include/sock_types.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup pkg_lwip_sokc
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief lwIP-specific types
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef SOCK_TYPES_H_
|
||||
#define SOCK_TYPES_H_
|
||||
|
||||
#include "net/af.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Raw IP sock type
|
||||
* @internal
|
||||
*/
|
||||
struct sock_ip {
|
||||
struct netconn *conn;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SOCK_TYPES_H_ */
|
||||
/** @} */
|
46
tests/lwip_sock_ip/Makefile
Normal file
46
tests/lwip_sock_ip/Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
APPLICATION = lwip_sock_ip
|
||||
|
||||
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 = 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_ip
|
||||
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
|
33
tests/lwip_sock_ip/README.md
Normal file
33
tests/lwip_sock_ip/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
Tests for lwIP's sock_ip port
|
||||
=============================
|
||||
|
||||
This tests the `sock_ip` 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).
|
48
tests/lwip_sock_ip/constants.h
Normal file
48
tests/lwip_sock_ip/constants.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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_PROTO (254) /* https://tools.ietf.org/html/rfc3692#section-2.1 */
|
||||
#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_ */
|
||||
/** @} */
|
1190
tests/lwip_sock_ip/main.c
Normal file
1190
tests/lwip_sock_ip/main.c
Normal file
File diff suppressed because it is too large
Load Diff
370
tests/lwip_sock_ip/stack.c
Normal file
370
tests/lwip_sock_ip/stack.c
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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 "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/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)
|
||||
{
|
||||
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);
|
||||
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, uint8_t proto, 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);
|
||||
uint8_t *payload = (uint8_t *)(ip_hdr + 1);
|
||||
(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) + data_len));
|
||||
IPH_TTL_SET(ip_hdr, 64);
|
||||
IPH_PROTO_SET(ip_hdr, proto);
|
||||
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)));
|
||||
|
||||
memcpy(payload, data, data_len);
|
||||
_netdev_buffer_size = sizeof(ethernet_hdr_t) + sizeof(struct ip_hdr) +
|
||||
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)proto; (void)netif; (void)data; (void)data_len;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool _inject_6packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||
uint8_t proto, 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);
|
||||
uint8_t *payload = (uint8_t *)(ipv6_hdr + 1);
|
||||
(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(data_len);
|
||||
ipv6_hdr->nh = proto;
|
||||
ipv6_hdr->hl = 64;
|
||||
memcpy(&ipv6_hdr->src, src, sizeof(ipv6_hdr->src));
|
||||
memcpy(&ipv6_hdr->dst, dst, sizeof(ipv6_hdr->dst));
|
||||
|
||||
memcpy(payload, data, data_len);
|
||||
_netdev_buffer_size = sizeof(ethernet_hdr_t) + sizeof(ipv6_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)proto; (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, uint8_t proto,
|
||||
void *data, size_t data_len, uint16_t netif)
|
||||
{
|
||||
#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);
|
||||
uint8_t *payload = (uint8_t *)(ip_hdr + 1);
|
||||
uint16_t payload_len = HTONS(IPH_LEN(ip_hdr)) - sizeof(struct ip_hdr);
|
||||
const bool ip_correct = ((src == 0) || (src = ip_hdr->src.addr)) &&
|
||||
(dst = ip_hdr->dest.addr) &&
|
||||
(IPH_PROTO(ip_hdr) == proto);
|
||||
const bool payload_correct = (data_len == payload_len) &&
|
||||
(memcmp(data, payload, data_len) == 0);
|
||||
mutex_unlock(&_netdev_buffer_mutex);
|
||||
return ip_correct && payload_correct;
|
||||
#else
|
||||
(void)src; (void)dst; (void)proto; (void)netif; (void)data; (void)data_len;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool _check_6packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||
uint8_t proto, void *data, size_t data_len, uint16_t netif)
|
||||
{
|
||||
#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);
|
||||
uint8_t *payload = (uint8_t *)(ipv6_hdr + 1);
|
||||
uint16_t payload_len = byteorder_ntohs(ipv6_hdr->len);
|
||||
bool ip_correct = (ipv6_addr_is_unspecified(src) || ipv6_addr_equal(src, &ipv6_hdr->src)) &&
|
||||
ipv6_addr_equal(dst, &ipv6_hdr->dst) && (proto == ipv6_hdr->nh);
|
||||
bool payload_correct = (data_len == payload_len) &&
|
||||
(memcmp(data, payload, data_len) == 0);
|
||||
mutex_unlock(&_netdev_buffer_mutex);
|
||||
return ip_correct && payload_correct;
|
||||
#else
|
||||
(void)src; (void)dst; (void)proto; (void)netif; (void)data; (void)data_len;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @} */
|
123
tests/lwip_sock_ip/stack.h
Normal file
123
tests/lwip_sock_ip/stack.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 IPv4 packet into the stack
|
||||
*
|
||||
* @param[in] src The source address of the IPv4 packet
|
||||
* @param[in] dst The destination address of the IPv4 packet
|
||||
* @param[in] proto The protocol field of the IPv4 packet
|
||||
* @param[in] data The payload of the IPv4 packet
|
||||
* @param[in] data_len The payload length of the IPv4 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, uint8_t proto, void *data,
|
||||
size_t data_len, uint16_t netif);
|
||||
|
||||
/**
|
||||
* @brief Injects a received IPv6 packet into the stack
|
||||
*
|
||||
* @param[in] src The source address of the IPv6 packet
|
||||
* @param[in] dst The destination address of the IPv6 packet
|
||||
* @param[in] proto The next header field of the IPv6 packet
|
||||
* @param[in] data The payload of the IPv6 packet
|
||||
* @param[in] data_len The payload length of the IPv6 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,
|
||||
uint8_t proto, 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 IPv4 packet was sent by the networking component
|
||||
*
|
||||
* @param[in] src Expected source address of the IPv4 packet
|
||||
* @param[in] dst Expected destination address of the IPv4 packet
|
||||
* @param[in] proto Expected next header field of the IPv4 packet
|
||||
* @param[in] data Expected payload of the IPv4 packet
|
||||
* @param[in] data_len Expected payload length of the IPv4 packet
|
||||
* @param[in] netif Expected interface the packet is supposed to
|
||||
* be send over
|
||||
*
|
||||
* @return true, if all parameters match as expected
|
||||
* @return false, if not.
|
||||
*/
|
||||
bool _check_4packet(uint32_t src, uint32_t dst, uint8_t proto,
|
||||
void *data, size_t data_len, uint16_t netif);
|
||||
|
||||
/**
|
||||
* @brief Checks if a IPv6 packet was sent by the networking component
|
||||
*
|
||||
* @param[in] src Expected source address of the IPv6 packet
|
||||
* @param[in] dst Expected destination address of the IPv6 packet
|
||||
* @param[in] proto Expected next header field of the IPv6 packet
|
||||
* @param[in] data Expected payload of the IPv6 packet
|
||||
* @param[in] data_len Expected payload length of the IPv6 packet
|
||||
* @param[in] netif Expected interface the packet is supposed to
|
||||
* be send over
|
||||
*
|
||||
* @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,
|
||||
uint8_t proto, void *data, size_t data_len, uint16_t netif);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STACK_H_ */
|
||||
/** @} */
|
128
tests/lwip_sock_ip/tests/01-run.py
Executable file
128
tests/lwip_sock_ip/tests/01-run.py
Executable file
@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
#
|
||||
# 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 _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):
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__EAFNOSUPPORT()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__EINVAL_addr()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__EINVAL_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__no_endpoints()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__only_local()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__only_local_reuse_ep()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__only_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create4__full()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__EADDRNOTAVAIL()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__EAGAIN()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__ENOBUFS()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__ETIMEDOUT()")
|
||||
child.match # get to ensure program reached that point
|
||||
start = datetime.now()
|
||||
child.expect_exact(u" * Calling sock_ip_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_ip_recv4__socketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__socketed_with_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__unsocketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__unsocketed_with_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__with_timeout()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv4__non_blocking()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__EAFNOSUPPORT()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__EINVAL_addr()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__EINVAL_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__ENOTCONN()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__socketed_no_local_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__socketed_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__socketed_no_local()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__socketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__socketed_other_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__unsocketed_no_local_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__unsocketed_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__unsocketed_no_local()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__unsocketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__no_sock_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send4__no_sock()")
|
||||
if _ipv6_tests(code):
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__EAFNOSUPPORT()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__EINVAL_addr()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__EINVAL_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__no_endpoints()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__only_local()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__only_local_reuse_ep()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__only_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_create6__full()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__EADDRNOTAVAIL()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__EAGAIN()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__ENOBUFS()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__ETIMEDOUT()")
|
||||
child.match # get to ensure program reached that point
|
||||
start = datetime.now()
|
||||
child.expect_exact(u" * Calling sock_ip_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_ip_recv6__socketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__socketed_with_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__unsocketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__unsocketed_with_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__with_timeout()")
|
||||
child.expect_exact(u"Calling test_sock_ip_recv6__non_blocking()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__EAFNOSUPPORT()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__EINVAL_addr()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__EINVAL_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__ENOTCONN()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__socketed_no_local_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__socketed_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__socketed_no_local()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__socketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__socketed_other_remote()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__unsocketed_no_local_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__unsocketed_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__unsocketed_no_local()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__unsocketed()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__no_sock_no_netif()")
|
||||
child.expect_exact(u"Calling test_sock_ip_send6__no_sock()")
|
||||
child.expect_exact(u"ALL TESTS SUCCESSFUL")
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(testrunner.run(testfunc))
|
Loading…
Reference in New Issue
Block a user