

16 changed files with 2770 additions and 1 deletions
@ -0,0 +1,3 @@
|
||||
MODULE := lwip_sock
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,3 @@
|
||||
MODULE := lwip_sock_ip
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -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); |
||||
} |
||||
|
||||
/** @} */ |
@ -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; |
||||
} |
||||
|
||||
/** @} */ |
@ -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_ */ |
||||
/** @} */ |
@ -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_ */ |
||||
/** @} */ |
@ -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
|
@ -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). |
@ -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_ */ |
||||
/** @} */ |
@ -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 |
||||
} |
||||
|
||||
/** @} */ |
@ -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" |
||||