1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-26 06:53:52 +01:00

Merge pull request #3551 from authmillenon/pkg/port/lwip

lwIP: Initial import
This commit is contained in:
Martine Lenders 2016-03-30 18:22:10 +02:00
commit 4dbc26fd4e
35 changed files with 2632 additions and 1 deletions

View File

@ -111,6 +111,9 @@ ifneq (,$(filter ieee802154,$(USEMODULE)))
ifneq (,$(filter gnrc_ipv6_router_default, $(USEMODULE)))
USEMODULE += gnrc_sixlowpan_router_default
endif
ifneq (,$(filter lwip%, $(USEMODULE)))
USEMODULE += lwip_sixlowpan
endif
endif
ifneq (,$(filter gnrc_sixlowpan_default,$(USEMODULE)))
@ -354,6 +357,60 @@ ifneq (,$(filter posix_semaphore,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter lwip_sixlowpan,$(USEMODULE)))
USEMODULE += lwip_ipv6_autoconfig
endif
ifneq (,$(filter lwip_ipv6_autoconfig,$(USEMODULE)))
USEMODULE += lwip_ipv6
endif
ifneq (,$(filter lwip_ipv6,$(USEMODULE)))
USEMODULE += random
endif
ifneq (,$(filter lwip_udplite,$(USEMODULE)))
USEMODULE += lwip_udp
endif
ifneq (,$(filter lwip_conn_%,$(USEMODULE)))
USEMODULE += lwip_conn
endif
ifneq (,$(filter lwip_conn_ip,$(USEMODULE)))
USEMODULE += lwip_raw
endif
ifneq (,$(filter lwip_conn_udp,$(USEMODULE)))
USEMODULE += lwip_udp
endif
ifneq (,$(filter lwip_%,$(USEMODULE)))
USEMODULE += lwip
endif
ifneq (,$(filter lwip,$(USEMODULE)))
USEPKG += lwip
USEMODULE += lwip_api
USEMODULE += lwip_contrib
USEMODULE += lwip_core
USEMODULE += lwip_netif
ifeq (,$(filter lwip_ipv4 lwip_ipv6,$(USEMODULE)))
USEMODULE += lwip_ipv4
endif
ifeq (,$(filter lwip_tcp lwip_udp lwip_udplite,$(USEMODULE)))
USEMODULE += lwip_raw
endif
endif
ifneq (,$(filter lwip_ppp,$(USEMODULE)))
USEMODULE += lwip_polarssl
endif
ifneq (,$(filter lwip_contrib,$(USEMODULE)))
USEMODULE += sema
endif
ifneq (,$(filter sema,$(USEMODULE)))
USEMODULE += xtimer
endif

View File

@ -17,6 +17,18 @@ PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc
PSEUDOMODULES += gnrc_pktbuf
PSEUDOMODULES += log
PSEUDOMODULES += log_printfnoformat
PSEUDOMODULES += lwip_arp
PSEUDOMODULES += lwip_autoip
PSEUDOMODULES += lwip_dhcp
PSEUDOMODULES += lwip_ethernet
PSEUDOMODULES += lwip_igmp
PSEUDOMODULES += lwip_ipv6_autoconfig
PSEUDOMODULES += lwip_raw
PSEUDOMODULES += lwip_sixlowpan
PSEUDOMODULES += lwip_stats
PSEUDOMODULES += lwip_tcp
PSEUDOMODULES += lwip_udp
PSEUDOMODULES += lwip_udplite
PSEUDOMODULES += netdev_default
PSEUDOMODULES += netstats_l2
PSEUDOMODULES += newlib

11
pkg/lwip/Makefile Normal file
View File

@ -0,0 +1,11 @@
PKG_NAME=lwip
PKG_URL=git://git.savannah.nongnu.org/lwip.git
PKG_VERSION=fd4a109ffa6513b28a0c780a952cef1110423717
PKG_BUILDDIR ?= $(BINDIRBASE)/pkg/$(BOARD)/$(PKG_NAME)
.PHONY: all
all: git-download
$(MAKE) -C $(PKG_BUILDDIR)
include $(RIOTBASE)/pkg/pkg.mk

18
pkg/lwip/Makefile.include Normal file
View File

@ -0,0 +1,18 @@
INCLUDES += -I$(RIOTBASE)/pkg/lwip/include \
-I$(BINDIRBASE)/pkg/$(BOARD)/lwip/src/include
ifneq (,$(filter lwip_conn,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib/conn
endif
ifneq (,$(filter lwip_conn_ip,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib/conn/ip
endif
ifneq (,$(filter lwip_conn_udp,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib/conn/udp
endif
ifneq (,$(filter lwip_contrib,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib
endif
ifneq (,$(filter lwip_netdev2,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib/netdev2
endif

View File

@ -0,0 +1,3 @@
MODULE := lwip_contrib
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,3 @@
MODULE := lwip_conn
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,3 @@
MODULE := lwip_conn_ip
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 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 <assert.h>
#include <errno.h>
#include "net/ipv4/addr.h"
#include "net/ipv6/addr.h"
#include "net/conn/ip.h"
#include "lwip/api.h"
#include "lwip/conn.h"
int conn_ip_create(conn_ip_t *conn, const void *addr, size_t addr_len, int family, int proto)
{
struct netconn *tmp;
int res;
res = lwip_conn_create(&tmp, addr, addr_len, family, NETCONN_RAW, proto, 0);
if (res < 0) {
return res;
}
conn->lwip_conn = tmp;
return res;
}
void conn_ip_close(conn_ip_t *conn)
{
assert(conn != NULL);
netconn_delete(conn->lwip_conn);
}
int conn_ip_getlocaladdr(conn_ip_t *conn, void *addr)
{
assert(conn != NULL);
return lwip_conn_getlocaladdr(conn->lwip_conn, addr, NULL);
}
int conn_ip_recvfrom(conn_ip_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len)
{
assert(conn != NULL);
return lwip_conn_recvfrom(conn->lwip_conn, data, max_len, addr, addr_len, NULL);
}
int conn_ip_sendto(const void *data, size_t len, const void *src, size_t src_len,
void *dst, size_t dst_len, int family, int proto)
{
struct netconn *tmp;
int res;
res = lwip_conn_create(&tmp, src, src_len, family, NETCONN_RAW, proto, 0);
if (res < 0) {
return res;
}
res = lwip_conn_sendto(tmp, data, len, dst, dst_len, 0);
netconn_delete(tmp);
return res;
}
/** @} */

View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2015 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 <errno.h>
#include <stdbool.h>
#include "byteorder.h"
#include "net/af.h"
#include "net/ipv4/addr.h"
#include "net/ipv6/addr.h"
#include "net/conn.h"
#include "lwip/api.h"
#include "lwip/opt.h"
int lwip_conn_create(struct netconn **netconn, const void *addr, size_t addr_len, int family,
int type, int proto, uint16_t port)
{
struct netconn *tmp;
int res = 0;
switch (family) {
#if LWIP_IPV4
case AF_INET:
if (addr_len != sizeof(ipv4_addr_t)) {
return -EINVAL;
}
break;
#endif
#if LWIP_IPV6
case AF_INET6:
if (addr_len != sizeof(ipv6_addr_t)) {
return -EINVAL;
}
type |= NETCONN_TYPE_IPV6;
break;
#endif
default:
return -EAFNOSUPPORT;
}
if ((tmp = netconn_new_with_proto_and_callback(type, proto, NULL)) == NULL) {
return -ENOMEM;
}
switch (netconn_bind(tmp, (ip_addr_t *)addr, port)) {
case ERR_USE:
netconn_delete(tmp);
res = -EADDRINUSE;
break;
case ERR_VAL:
netconn_delete(tmp);
res = -EINVAL;
break;
default:
break;
}
*netconn = tmp;
return res;
}
int lwip_conn_getlocaladdr(struct netconn *netconn, void *addr, uint16_t *port)
{
uint16_t tmp;
if (netconn_getaddr(netconn, addr, &tmp, 1) != ERR_OK) {
return -EOPNOTSUPP;
}
if (port != NULL) {
*port = tmp;
}
#if LWIP_IPV6
if (netconn->type & NETCONN_TYPE_IPV6) {
return sizeof(ipv6_addr_t);
}
#endif
#if LWIP_IPV4
return sizeof(ipv4_addr_t);
#else
return -EOPNOTSUPP;
#endif
}
int lwip_conn_recvfrom(struct netconn *netconn, void *data, size_t max_len, void *addr,
size_t *addr_len, uint16_t *port)
{
struct netbuf *buf;
size_t len = 0;
err_t res = 0;
uint8_t *data_ptr = data;
if (netconn == NULL) {
return -ENOTSOCK;
}
if ((res = netconn_recv(netconn, &buf))) {
switch (res) {
#if LWIP_SO_RCVTIMEO
case ERR_TIMEOUT:
return -ETIMEDOUT;
#endif
case ERR_MEM:
return -ENOMEM;
default:
return -EIO;
}
}
len = buf->p->tot_len;
if (len > max_len) {
netbuf_delete(buf);
return -ENOBUFS;
}
#if LWIP_IPV6
if (netconn->type & NETCONN_TYPE_IPV6) {
*addr_len = sizeof(ipv6_addr_t);
}
else {
#endif
#if LWIP_IPV4
*addr_len = sizeof(ipv4_addr_t);
#else
netbuf_delete(buf);
return -EOPNOTSUPP;
#endif
#if LWIP_IPV6
}
#endif
/* copy address */
memcpy(addr, &buf->addr, *addr_len);
/* copy port */
if (port != NULL) {
*port = buf->port;
}
/* copy data */
for (struct pbuf *q = buf->p; q != NULL; q = q->next) {
memcpy(data_ptr, q->payload, q->len);
data_ptr += q->len;
}
netbuf_delete(buf);
return (int)len;
}
int lwip_conn_sendto(struct netconn *netconn, const void *data, size_t len,
const void *addr, size_t addr_len, uint16_t port)
{
struct netbuf *buf;
int res;
#if LWIP_IPV6
if (netconn->type & NETCONN_TYPE_IPV6) {
if (addr_len != sizeof(ipv6_addr_t)) {
return -EINVAL;
}
}
else {
#endif
#if LWIP_IPV4
if (addr_len != sizeof(ipv4_addr_t)) {
return -EINVAL;
}
#endif
#if LWIP_IPV6
}
#endif
buf = netbuf_new();
if ((buf == NULL) || (netbuf_alloc(buf, len) == NULL)) {
netbuf_delete(buf);
return -ENOMEM;
}
if (netbuf_take(buf, data, len) != ERR_OK) {
netbuf_delete(buf);
return -ENOBUFS;
}
switch ((res = netconn_sendto(netconn, buf, addr, port))) {
case ERR_OK:
res = len;
break;
case ERR_RTE:
res = -EHOSTUNREACH;
break;
case ERR_VAL:
res = -EINVAL;
break;
case ERR_IF:
res = -EAFNOSUPPORT;
break;
default:
res = -EIO;
break;
}
netbuf_delete(buf);
return res;
}
/** @} */

View File

@ -0,0 +1,3 @@
MODULE := lwip_conn_udp
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2015 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 <assert.h>
#include <errno.h>
#include "net/ipv4/addr.h"
#include "net/ipv6/addr.h"
#include "net/conn/udp.h"
#include "lwip/api.h"
#include "lwip/conn.h"
int conn_udp_create(conn_udp_t *conn, const void *addr, size_t addr_len, int family, uint16_t port)
{
struct netconn *tmp;
int res;
res = lwip_conn_create(&tmp, addr, addr_len, family, NETCONN_UDP, 0, port);
if (res < 0) {
return res;
}
conn->lwip_conn = tmp;
return res;
}
void conn_udp_close(conn_udp_t *conn)
{
assert(conn != NULL);
netconn_delete(conn->lwip_conn);
}
int conn_udp_getlocaladdr(conn_udp_t *conn, void *addr, uint16_t *port)
{
assert(conn != NULL);
return lwip_conn_getlocaladdr(conn->lwip_conn, addr, port);
}
int conn_udp_recvfrom(conn_udp_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len,
uint16_t *port)
{
assert(conn != NULL);
return lwip_conn_recvfrom(conn->lwip_conn, data, max_len, addr, addr_len, port);
}
int conn_udp_sendto(const void *data, size_t len, const void *src, size_t src_len,
const void *dst, size_t dst_len, int family, uint16_t sport,
uint16_t dport)
{
struct netconn *tmp;
int res;
res = lwip_conn_create(&tmp, src, src_len, family, NETCONN_UDP, 0, sport);
if (res < 0) {
return res;
}
res = lwip_conn_sendto(tmp, data, len, dst, dst_len, dport);
netconn_delete(tmp);
return res;
}
/** @} */

3
pkg/lwip/contrib/doc.txt Normal file
View File

@ -0,0 +1,3 @@
/**
* @defgroup lwip_contrib RIOT lwIP port
*/

79
pkg/lwip/contrib/lwip.c Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 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/tcpip.h"
#include "lwip/netif/netdev2.h"
#include "lwip/netif.h"
#include "netif/lowpan6.h"
#ifdef MODULE_NETDEV2_TAP
#include "netdev2_tap.h"
#endif
#ifdef MODULE_AT86RF2XX
#include "at86rf2xx.h"
#include "at86rf2xx_params.h"
#endif
#include "lwip.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifdef MODULE_NETDEV2_TAP
#define LWIP_NETIF_NUMOF (1)
#endif
#ifdef MODULE_AT86RF2XX /* is mutual exclusive with above ifdef */
#define LWIP_NETIF_NUMOF (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0]))
#endif
#ifdef LWIP_NETIF_NUMOF
static struct netif netif[LWIP_NETIF_NUMOF];
#endif
#ifdef MODULE_AT86RF2XX
static at86rf2xx_t at86rf2xx_devs[LWIP_NETIF_NUMOF];
#endif
void lwip_bootstrap(void)
{
/* TODO: do for every eligable netdev2 */
#ifdef LWIP_NETIF_NUMOF
#ifdef MODULE_NETDEV2_TAP
if (netif_add(&netif[0], &netdev2_tap, lwip_netdev2_init, tcpip_input) == NULL) {
DEBUG("Could not add netdev2_tap device\n");
return;
}
#elif defined(MODULE_AT86RF2XX)
for (int i = 0; i < LWIP_NETIF_NUMOF; i++) {
at86rf2xx_setup(&at86rf2xx_devs[i], &at86rf2xx_params[i]);
if (netif_add(&netif[i], &at86rf2xx_devs[i], lwip_netdev2_init,
tcpip_6lowpan_input) == NULL) {
DEBUG("Could not add at86rf2xx device\n");
return;
}
}
#endif
if (netif[0].state != NULL) {
/* state is set to a netdev2_t in the netif_add() functions above */
netif_set_default(&netif[0]);
}
#endif
/* also allow for external interface definition */
tcpip_init(NULL, NULL);
}
/** @} */

View File

@ -0,0 +1,3 @@
MODULE := lwip_netdev2
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,262 @@
/*
* Copyright (C) 2015 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 <assert.h>
#include <sys/uio.h>
#include <inttypes.h>
#include "lwip/err.h"
#include "lwip/ethip6.h"
#include "lwip/netif.h"
#include "lwip/netif/netdev2.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "netif/etharp.h"
#include "netif/lowpan6.h"
#include "net/ieee802154.h"
#include "net/netdev2.h"
#include "net/netopt.h"
#include "utlist.h"
#include "thread.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define LWIP_NETDEV2_NAME "lwip_netdev2_mux"
#define LWIP_NETDEV2_PRIO (THREAD_PRIORITY_MAIN - 4)
#define LWIP_NETDEV2_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#define LWIP_NETDEV2_QUEUE_LEN (8)
#define LWIP_NETDEV2_MSG_TYPE_EVENT 0x1235
#define ETHERNET_IFNAME1 'E'
#define ETHERNET_IFNAME2 'T'
/* running number for different interfaces */
static uint8_t _num = 0;
static kernel_pid_t _pid = KERNEL_PID_UNDEF;
static char _stack[LWIP_NETDEV2_STACKSIZE];
static msg_t _queue[LWIP_NETDEV2_QUEUE_LEN];
static char _tmp_buf[LWIP_NETDEV2_BUFLEN];
#ifdef MODULE_NETDEV2_ETH
static err_t _eth_link_output(struct netif *netif, struct pbuf *p);
#endif
#ifdef MODULE_LWIP_SIXLOWPAN
static err_t _ieee802154_link_output(struct netif *netif, struct pbuf *p);
#endif
static void _event_cb(netdev2_t *dev, netdev2_event_t event, void *arg);
static void *_event_loop(void *arg);
err_t lwip_netdev2_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
netdev2_t *netdev;
uint16_t dev_type;
err_t res = ERR_OK;
/* start multiplexing thread (only one needed) */
if (_pid <= KERNEL_PID_UNDEF) {
_pid = thread_create(_stack, LWIP_NETDEV2_STACKSIZE, LWIP_NETDEV2_PRIO,
THREAD_CREATE_STACKTEST, _event_loop, netif,
LWIP_NETDEV2_NAME);
if (_pid <= 0) {
return ERR_IF;
}
}
/* initialize netdev and netif */
netdev = (netdev2_t *)netif->state;
netdev->driver->init(netdev);
netdev->event_callback = _event_cb;
if (netdev->driver->get(netdev, NETOPT_DEVICE_TYPE, &dev_type,
sizeof(dev_type)) < 0) {
return ERR_IF;
}
netif->num = _num++;
#if LWIP_NETIF_HOSTNAME
netif->hostname = "riot";
#endif /* LWIP_NETIF_HOSTNAME */
/* XXX: for now assume its Ethernet, since netdev2 is implemented only by ethernet drivers */
netif->flags = 0;
switch (dev_type) {
#ifdef MODULE_NETDEV2_ETH
case NETDEV2_TYPE_ETHERNET:
netif->name[0] = ETHERNET_IFNAME1;
netif->name[1] = ETHERNET_IFNAME2;
netif->hwaddr_len = (u8_t)netdev->driver->get(netdev, NETOPT_ADDRESS, netif->hwaddr,
sizeof(netif->hwaddr));
if (netif->hwaddr_len > sizeof(netif->hwaddr)) {
return ERR_IF;
}
/* TODO: get from driver (currently not in netdev2_eth) */
netif->mtu = ETHERNET_DATA_LEN;
netif->linkoutput = _eth_link_output;
#if LWIP_IPV4
netif->output = etharp_output;
#endif
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
netif_create_ip6_linklocal_address(netif, 1); /* 1: hwaddr is 48-bit MAC addr */
#endif
netif->flags |= NETIF_FLAG_BROADCAST;
netif->flags |= NETIF_FLAG_ETHARP;
netif->flags |= NETIF_FLAG_ETHERNET;
break;
#endif
#ifdef MODULE_LWIP_SIXLOWPAN
case NETDEV2_TYPE_IEEE802154:
{
u16_t pan_id;
if (netdev->driver->get(netdev, NETOPT_NID, &pan_id,
sizeof(pan_id)) < 0) {
return ERR_IF;
}
lowpan6_set_pan_id(pan_id);
netif->hwaddr_len = (u8_t)netdev->driver->get(netdev, NETOPT_ADDRESS_LONG,
netif->hwaddr, sizeof(netif->hwaddr));
if (netif->hwaddr_len > sizeof(netif->hwaddr)) {
return ERR_IF;
}
netif->linkoutput = _ieee802154_link_output;
res = lowpan6_if_init(netif);
if (res != ERR_OK) {
return res;
}
netif_create_ip6_linklocal_address(netif, 0); /* 0: hwaddr is assumed to be 64-bit */
break;
}
#endif
default:
return ERR_IF; /* device type not supported yet */
}
netif->flags |= NETIF_FLAG_UP;
netif->flags |= NETIF_FLAG_LINK_UP;
netif->flags |= NETIF_FLAG_IGMP;
netif->flags |= NETIF_FLAG_MLD6;
netdev->isr_arg = netif;
netdev->event_callback = _event_cb;
#if LWIP_IPV6_AUTOCONFIG
netif->ip6_autoconfig_enabled = 1;
#endif
return res;
}
#ifdef MODULE_NETDEV2_ETH
static err_t _eth_link_output(struct netif *netif, struct pbuf *p)
{
netdev2_t *netdev = (netdev2_t *)netif->state;
struct pbuf *q;
unsigned int count = 0;
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
LL_COUNT(p, q, count);
struct iovec pkt[count];
for (q = p, count = 0; q != NULL; q = q->next, count++) {
pkt[count].iov_base = q->payload;
pkt[count].iov_len = (size_t)q->len;
}
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
return (netdev->driver->send(netdev, pkt, count) > 0) ? ERR_OK : ERR_BUF;
}
#endif
#ifdef MODULE_LWIP_SIXLOWPAN
static err_t _ieee802154_link_output(struct netif *netif, struct pbuf *p)
{
LWIP_ASSERT("p->next == NULL", p->next == NULL);
netdev2_t *netdev = (netdev2_t *)netif->state;
struct iovec pkt = {
.iov_base = p->payload,
.iov_len = (p->len - IEEE802154_FCS_LEN), /* FCS is written by driver */
};
return (netdev->driver->send(netdev, &pkt, 1) > 0) ? ERR_OK : ERR_BUF;
}
#endif
static struct pbuf *_get_recv_pkt(netdev2_t *dev)
{
int len = dev->driver->recv(dev, _tmp_buf, sizeof(_tmp_buf), NULL);
assert(((unsigned)len) <= UINT16_MAX);
struct pbuf *p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL);
if (p == NULL) {
DEBUG("lwip_netdev2: can not allocate in pbuf\n");
return NULL;
}
pbuf_take(p, _tmp_buf, len);
return p;
}
static void _event_cb(netdev2_t *dev, netdev2_event_t event, void *arg)
{
(void)arg;
if (event == NETDEV2_EVENT_ISR) {
assert(_pid != KERNEL_PID_UNDEF);
msg_t msg;
msg.type = LWIP_NETDEV2_MSG_TYPE_EVENT;
msg.content.ptr = (char *)dev;
if (msg_send(&msg, _pid) <= 0) {
DEBUG("lwip_netdev2: possibly lost interrupt.\n");
}
}
else {
struct netif *netif = dev->isr_arg;
switch (event) {
case NETDEV2_EVENT_RX_COMPLETE: {
struct pbuf *p = _get_recv_pkt(dev);
if (p == NULL) {
DEBUG("lwip_netdev2: error receiving packet\n");
return;
}
if (netif->input(p, netif) != ERR_OK) {
DEBUG("lwip_netdev2: error inputing packet\n");
return;
}
}
break;
default:
break;
}
}
}
static void *_event_loop(void *arg)
{
(void)arg;
msg_init_queue(_queue, LWIP_NETDEV2_QUEUE_LEN);
while (1) {
msg_t msg;
msg_receive(&msg);
if (msg.type == LWIP_NETDEV2_MSG_TYPE_EVENT) {
netdev2_t *dev = (netdev2_t *)msg.content.ptr;
dev->driver->isr(dev);
}
}
return NULL;
}
/** @} */

221
pkg/lwip/contrib/sys_arch.c Normal file
View File

@ -0,0 +1,221 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @{
*
* @file
*/
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include "arch/cc.h"
#include "arch/sys_arch.h"
#include "lwip/err.h"
#include "lwip/mem.h"
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "msg.h"
#include "sema.h"
#include "thread.h"
#include "xtimer.h"
void sys_init(void)
{
return;
}
err_t sys_mutex_new(sys_mutex_t *mutex)
{
mutex_init((mutex_t *)mutex);
return ERR_OK;
}
void sys_mutex_lock(sys_mutex_t *mutex)
{
mutex_lock((mutex_t *)mutex);
}
void sys_mutex_unlock(sys_mutex_t *mutex)
{
mutex_unlock((mutex_t *)mutex);
}
void sys_mutex_free(sys_mutex_t *mutex)
{
mem_free(mutex);
}
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{
if (sema_create((sema_t *)sem, (unsigned int)count) < 0) {
return ERR_VAL;
}
return ERR_OK;
}
void sys_sem_free(sys_sem_t *sem)
{
sema_destroy((sema_t *)sem);
}
void sys_sem_signal(sys_sem_t *sem)
{
LWIP_ASSERT("invalid semaphor", sys_sem_valid(sem));
sema_post((sema_t *)sem);
}
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t count)
{
LWIP_ASSERT("invalid semaphor", sys_sem_valid(sem));
if (count != 0) {
uint64_t stop, start;
start = xtimer_now64();
int res = sema_wait_timed((sema_t *)sem, count * MS_IN_USEC);
stop = xtimer_now64() - start;
if (res == -ETIMEDOUT) {
return SYS_ARCH_TIMEOUT;
}
return (u32_t)(stop / MS_IN_USEC);
}
else {
sema_wait_timed((sema_t *)sem, 0);
return 0;
}
}
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
(void)size;
mbox->waiting = 0;
cib_init(&mbox->cib, SYS_MBOX_SIZE);
mutex_init(&mbox->mutex);
if (sema_create(&mbox->not_empty, 0) < 0) {
return ERR_VAL;
}
if (sema_create(&mbox->not_full, 0) < 0) {
return ERR_VAL;
}
return ERR_OK;
}
void sys_mbox_free(sys_mbox_t *mbox)
{
sema_destroy(&mbox->not_empty);
sema_destroy(&mbox->not_full);
}
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
int idx;
LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
mutex_lock(&mbox->mutex);
while ((idx = cib_put(&mbox->cib)) < 0) {
mbox->waiting++;
mutex_unlock(&mbox->mutex);
sema_wait_timed(&mbox->not_full, 0);
mutex_lock(&mbox->mutex);
mbox->waiting--;
}
mbox->msgs[idx] = msg;
if (cib_avail(&mbox->cib) == 1) {
sema_post(&mbox->not_empty);
}
mutex_unlock(&mbox->mutex);
}
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
int idx;
LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
mutex_lock(&mbox->mutex);
if ((idx = cib_put(&mbox->cib)) < 0) {
mutex_unlock(&mbox->mutex);
return ERR_MEM;
}
mbox->msgs[idx] = msg;
if (cib_avail(&mbox->cib) == 1) {
sema_post(&mbox->not_empty);
}
mutex_unlock(&mbox->mutex);
return ERR_OK;
}
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
u32_t time_needed = 0;
unsigned int idx;
LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
mutex_lock(&mbox->mutex);
while (cib_avail(&mbox->cib) == 0) {
sys_sem_t *not_empty = (sys_sem_t *)(&mbox->not_empty);
mutex_unlock(&mbox->mutex);
if (timeout != 0) {
time_needed = sys_arch_sem_wait(not_empty, timeout);
if (time_needed == SYS_ARCH_TIMEOUT) {
return SYS_ARCH_TIMEOUT;
}
}
else {
sys_arch_sem_wait(not_empty, 0);
}
mutex_lock(&mbox->mutex);
}
idx = cib_get(&mbox->cib);
if (msg != NULL) {
*msg = mbox->msgs[idx];
}
if (mbox->waiting) {
sema_post(&mbox->not_full);
}
mutex_unlock(&mbox->mutex);
return time_needed;
}
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
int idx;
LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
mutex_lock(&mbox->mutex);
if (cib_avail(&mbox->cib) == 0) {
mutex_unlock(&mbox->mutex);
return SYS_MBOX_EMPTY;
}
idx = cib_get(&mbox->cib);
if (msg != NULL) {
*msg = mbox->msgs[idx];
}
mutex_unlock(&mbox->mutex);
return 0;
}
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg,
int stacksize, int prio)
{
kernel_pid_t res;
char *stack = mem_malloc((size_t)stacksize);
if (stack == NULL) {
return ERR_MEM;
}
if ((res = thread_create(stack, stacksize, prio, THREAD_CREATE_STACKTEST,
(thread_task_func_t)thread, arg, name)) <= KERNEL_PID_UNDEF) {
abort();
}
sched_switch((char)prio);
return res;
}
/** @} */

6
pkg/lwip/doc.txt Normal file
View File

@ -0,0 +1,6 @@
/**
* @defgroup pkg_lwip lwIP network stack
* @ingroup pkg
* @brief Provides the lwIP network stack
* @see http://savannah.nongnu.org/projects/lwip/
*/

132
pkg/lwip/include/arch/cc.h Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @defgroup lwip_arch_cc Compiler and processor description
* @ingroup lwip
* @brief Describes compiler and processor to lwIP
* @{
*
* @file
* @brief Compiler and processor definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "irq.h"
#include "byteorder.h"
#include "mutex.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BYTE_ORDER
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define BYTE_ORDER (LITTLE_ENDIAN) /**< platform's endianess */
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define BYTE_ORDER (BIG_ENDIAN) /**< platform's endianess */
#else
# error "Byte order is neither little nor big!"
#endif
#endif
/**
* @brief Generic types for lwIP
* @{
*/
typedef uint8_t u8_t; /**< unsigned 8-bit type */
typedef int8_t s8_t; /**< signed 8-bit type */
typedef uint16_t u16_t; /**< unsigned 16-bit type */
typedef int16_t s16_t; /**< signed 16-bit type */
typedef uint32_t u32_t; /**< unsigned 32-bit type */
typedef int32_t s32_t; /**< signed 32-bit type */
typedef unsigned long mem_ptr_t; /**< A generic pointer type. It has to be an integer type
* (not void*, due to some pointer arithmetics). */
/**
* @}
*/
/**
* @brief (sn)printf formatters for the generic lwIP types
* @{
*/
#define X8_F "02" PRIx8
#define U16_F PRIu16
#define S16_F PRId16
#define X16_F PRIx16
#define U32_F PRIu32
#define S32_F PRId32
#define X32_F PRIx32
#define SZT_F "lu"
/**
* @}
*/
/**
* @brief Compiler hints for packing structures
* @{
*/
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
/**
* @}
*/
/**
* @todo check for best value
*/
#define LWIP_CHKSUM_ALGORITHM (3)
#ifdef MODULE_LOG
# define LWIP_PLATFORM_DIAG(x) LOG_INFO x
# ifdef NDEBUG
# define LWIP_PLATFORM_ASSERT(x)
# else
# define LWIP_PLATFORM_ASSERT(x) \
do { \
LOG_ERROR("Assertion \"%s\" failed at %s:%d\n", x, __FILE__, __LINE__); \
fflush(NULL); \
abort(); \
} while (0)
# endif
#else
# define LWIP_PLATFORM_DIAG(x) printf x
# ifdef NDEBUG
# define LWIP_PLATFORM_ASSERT(x)
# else
# define LWIP_PLATFORM_ASSERT(x) \
do { \
printf("Assertion \"%s\" failed at %s:%d\n", x, __FILE__, __LINE__); \
fflush(NULL); \
abort(); \
} while (0)
# endif
#endif
#define SYS_ARCH_PROTECT(x) mutex_lock(&x)
#define SYS_ARCH_UNPROTECT(x) mutex_unlock(&x)
#define SYS_ARCH_DECL_PROTECT(x) mutex_t x = MUTEX_INIT
#ifdef __cplusplus
}
#endif
#endif /* LWIP_ARCH_CC_H */
/** @} */

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @defgroup lwip_arch_sys_arch Architecture depentent definitions
* @ingroup lwip
* @brief Semaphores and mailboxes.
* @{
*
* @file
* @brief Semaphore and mailboxes definitions.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H
#include <stdbool.h>
#include <stdint.h>
#include "cib.h"
#include "kernel_types.h"
#include "mutex.h"
#include "random.h"
#include "sema.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LWIP_COMPAT_MUTEX (0)
#define SYS_SEM_NULL { 0, PRIORITY_QUEUE_INIT }
#define SYS_MBOX_SIZE (8)
typedef struct {
cib_t cib;
void *msgs[SYS_MBOX_SIZE];
mutex_t mutex;
sema_t not_empty;
sema_t not_full;
volatile int waiting;
} sys_mbox_t;
typedef mutex_t sys_mutex_t;
typedef sema_t sys_sem_t;
typedef kernel_pid_t sys_thread_t;
static inline bool sys_mutex_valid(sys_mutex_t *mutex)
{
return mutex != NULL;
}
static inline bool sys_sem_valid(sys_sem_t *sem)
{
return sem != NULL;
}
static inline bool sys_mbox_valid(sys_mbox_t *mbox)
{
return (mbox != NULL) && (mbox->cib.mask != 0);
}
static inline void sys_mbox_set_invalid(sys_mbox_t *mbox)
{
if (mbox != NULL) {
mbox->cib.mask = 0;
}
}
#define sys_mutex_valid(mutex) (sys_mutex_valid(mutex))
#define sys_mutex_set_invalid(mutex)
#define sys_sem_valid(sem) (sys_sem_valid(sem))
#define sys_sem_set_invalid(sem)
#define sys_mbox_valid(mbox) (sys_mbox_valid(mbox))
#define sys_mbox_set_invalid(mbox) (sys_mbox_set_invalid(mbox))
#ifdef MODULE_RANDOM
#define LWIP_RAND() (random_uint32())
#endif
#ifdef __cplusplus
}
#endif
#endif /* LWIP_ARCH_SYS_ARCH_H */
/** @} */

45
pkg/lwip/include/lwip.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @defgroup pkg_lwip lwIP
* @ingroup pkg
* @brief A lightweight TCP/IP stack
* @see http://savannah.nongnu.org/projects/lwip/
*
* lwIP is a lightweight TCP/IP stack primarily for usage with Ethernet.
* It can be used with the the @ref conn.
*
* @{
*
* @file
* @brief lwIP bootstrap definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef LWIP_H_
#define LWIP_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes lwIP stack.
*
* This initializes lwIP, i.e. all netdevs are added to as interfaces to the
* stack and the stack's thread is started.
*/
void lwip_bootstrap(void);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_H_ */
/** @} */

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @defgroup pkg_lwip_conn Connection type definitions for lwIP
* @ingroup pkg_lwip
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef LWIP_CONN_H_
#define LWIP_CONN_H_
#include "lwip/api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Generic @ref net_conn object for lwIP (used internally)
*/
struct conn {
struct netconn *lwip_conn; /**< stack-internal connection object */
};
/**
* @brief @ref net_conn_ip definition for lwIP
*/
struct conn_ip {
struct netconn *lwip_conn; /**< stack-internal connection object */
};
/**
* @brief @ref net_conn_udp definition for lwIP
*/
struct conn_udp {
struct netconn *lwip_conn; /**< stack-internal connection object */
};
/**
* @brief Internal consolidation functions
* @{
*/
/**
* @brief consolidation function for @ref conn_ip_create() and @ref
* conn_udp_create()
*
* @internal
*/
int lwip_conn_create(struct netconn **netconn, const void *addr, size_t addr_len,
int family, int type, int proto, uint16_t port);
/**
* @brief consolidation function for @ref conn_ip_getlocaladdr() and @ref
* conn_udp_getlocaladdr()
*
* @internal
*/
int lwip_conn_getlocaladdr(struct netconn *netconn, void *addr, uint16_t *port);
/**
* @brief consolidation function for @ref conn_ip_recvfrom() and @ref
* conn_udp_recvfrom()
*
* @internal
*/
int lwip_conn_recvfrom(struct netconn *netconn, void *data, size_t max_len,
void *addr, size_t *addr_len, uint16_t *port);
/**
* @brief consolidation function for @ref conn_ip_sendto() and @ref
* conn_udp_sendto()
*
* @internal
*/
int lwip_conn_sendto(struct netconn *netconn, const void *data, size_t len,
const void *addr, size_t addr_len, uint16_t port);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_CONN_H_ */
/** @} */

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @defgroup pkg_lwip_netdev2 lwIP netdev2 adapter
* @ingroup pkg_lwip
* @brief netdev2 adapter for lwIP
* @{
*
* @file
* @brief lwIP netdev2 adapter definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NETDEV2_H_
#define NETDEV2_H_
#include "net/ethernet.h"
#include "net/netdev2.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#include "lwip/tcpip.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Length of the temporary copying buffer for receival.
* @note It should be as long as the maximum packet length of all the netdev you use.
*/
#ifndef LWIP_NETDEV2_BUFLEN
#define LWIP_NETDEV2_BUFLEN (ETHERNET_MAX_LEN)
#endif
/**
* @brief Initializes the netdev2 adapter.
*
* Should be passed to lwIP's netif_add() with the state parameter parameter of that function set
* to an existing netdev2_t instance
*
* @pre netif->state is set to an existing netdev2_t instance.
*
* @param[in] netif The network interface intended to be initialized.
*
* @return ERR_OK on success.
* @return ERR_IF on error.
*/
err_t lwip_netdev2_init(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif /* NETDEV2_H_ */
/** @} */

151
pkg/lwip/include/lwipopts.h Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @defgroup lwip_opts lwIP options
* @ingroup lwip
* @brief Options for the lwIP stack
* @{
*
* @file
* @brief Option definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef LWIP_LWIPOPTS_H_
#define LWIP_LWIPOPTS_H_
#include "thread.h"
#include "net/gnrc/netif/hdr.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief lwIP configuration macros.
* @see lwIP documentation
* @{
*/
#ifdef MODULE_LWIP_ARP
#define LWIP_ARP (1)
#else /* MODULE_LWIP_ARP */
#define LWIP_ARP (0)
#endif /* MODULE_LWIP_ARP */
#ifdef MODULE_LWIP_AUTOIP
#define LWIP_AUTOIP (1)
#else /* MODULE_LWIP_AUTOIP */
#define LWIP_AUTOIP (0)
#endif /* MODULE_LWIP_AUTOIP */
#ifdef MODULE_LWIP_DHCP
#define LWIP_DHCP (1)
#else /* MODULE_LWIP_DHCP */
#define LWIP_DHCP (0)
#endif /* MODULE_LWIP_DHCP */
#ifdef MODULE_LWIP_ETHERNET
#define LWIP_ETHERNET (1)
#else /* MODULE_LWIP_IPV4 */
#define LWIP_ETHERNET (0)
#endif /* MODULE_LWIP_IPV4 */
#ifdef MODULE_LWIP_IGMP
#define LWIP_IGMP (1)
#else /* MODULE_LWIP_IGMP */
#define LWIP_IGMP (0)
#endif /* MODULE_LWIP_IGMP */
#ifdef MODULE_LWIP_IPV4
#define LWIP_IPV4 (1)
#else /* MODULE_LWIP_IPV4 */
#define LWIP_IPV4 (0)
#endif /* MODULE_LWIP_IPV4 */
#ifdef MODULE_LWIP_IPV6_AUTOCONFIG
#define LWIP_IPV6_AUTOCONFIG (1)
#else /* MODULE_LWIP_IPV6_AUTOCONFIG */
#define LWIP_IPV6_AUTOCONFIG (0)
#endif /* MODULE_LWIP_IPV6_AUTOCONFIG */
#ifdef MODULE_LWIP_IPV6
#define LWIP_IPV6 (1)
#else /* MODULE_LWIP_IPV6 */
#define LWIP_IPV6 (0)
#endif /* MODULE_LWIP_IPV6 */
#ifdef MODULE_LWIP_NETIF_PPP
#define PPP_SUPPORT (1)
#else /* MODULE_LWIP_NETIF_PPP */
#define PPP_SUPPORT (0)
#endif /* MODULE_LWIP_NETIF_PPP */
#ifdef MODULE_LWIP_RAW
#define LWIP_RAW (1)
#else /* MODULE_LWIP_RAW */
#define LWIP_RAW (0)
#endif /* MODULE_LWIP_RAW */
#ifdef MODULE_LWIP_SIXLOWPAN
#define LWIP_6LOWPAN (1)
#else /* MODULE_LWIP_STATS */
#define LWIP_6LOWPAN (0)
#endif /* MODULE_LWIP_STATS */
#ifdef MODULE_LWIP_STATS
#define LWIP_STATS (1)
#else /* MODULE_LWIP_STATS */
#define LWIP_STATS (0)
#endif /* MODULE_LWIP_STATS */
#ifdef MODULE_LWIP_TCP
#define LWIP_TCP (1)
#else /* MODULE_LWIP_TCP */
#define LWIP_TCP (0)
#endif /* MODULE_LWIP_TCP */
#ifdef MODULE_LWIP_UDP
#define LWIP_UDP (1)
#else /* MODULE_LWIP_UDP */
#define LWIP_UDP (0)
#endif /* MODULE_LWIP_UDP */
#ifdef MODULE_LWIP_UDPLITE
#define LWIP_UDPLITE (1)
#else /* MODULE_LWIP_UDPLITE */
#define LWIP_UDPLITE (0)
#endif /* MODULE_LWIP_UDPLITE */
#ifdef MODULE_LWIP_CONN
#define LWIP_NETCONN (1)
#else
#define LWIP_NETCONN (0)
#endif
#define LWIP_SOCKET (0)
#define MEMP_MEM_MALLOC (1)
#define NETIF_MAX_HWADDR_LEN (GNRC_NETIF_HDR_L2ADDR_MAX_LEN)
#define TCPIP_THREAD_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#define MEM_ALIGNMENT (4)
#ifndef MEM_SIZE
/* packet buffer size of GNRC + stack for TCP/IP */
#define MEM_SIZE (TCPIP_THREAD_STACKSIZE + 6144)
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_LWIPOPTS_H_ */
/** @} */

View File

@ -0,0 +1,29 @@
From 0e28e1cd26c1de2ccf48bea9013676ef1d4d69b7 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mail@martine-lenders.eu>
Date: Thu, 12 Nov 2015 16:36:00 +0100
Subject: [PATCH 1/2] Fix warnings
---
src/include/lwip/debug.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h
index 973a633..c7b3c9c 100644
--- a/src/include/lwip/debug.h
+++ b/src/include/lwip/debug.h
@@ -67,8 +67,10 @@
* -- To disable assertions define LWIP_NOASSERT in arch/cc.h.
*/
#ifndef LWIP_NOASSERT
-#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
- LWIP_PLATFORM_ASSERT(message); } while(0)
+#define LWIP_ASSERT(message, assertion) \
+ if(!(assertion)) { \
+ LWIP_PLATFORM_ASSERT(message); \
+ }
#ifndef LWIP_PLATFORM_ASSERT
#error "If you want to use LWIP_ASSERT, LWIP_PLATFORM_ASSERT(message) needs to be defined in your arch/cc.h"
#endif
--
1.9.1

View File

@ -0,0 +1,119 @@
From 4f1f9c53db7ffeece81253d9b39d78296e5b68a8 Mon Sep 17 00:00:00 2001
From: Martine Lenders <mail@martine-lenders.eu>
Date: Thu, 12 Nov 2015 15:43:31 +0100
Subject: [PATCH 2/2] Add RIOT Makefiles
---
Makefile | 23 +++++++++++++++++++++++
src/api/Makefile | 3 +++
src/core/Makefile | 3 +++
src/core/ipv4/Makefile | 3 +++
src/core/ipv6/Makefile | 3 +++
src/netif/Makefile | 3 +++
src/netif/ppp/Makefile | 3 +++
src/netif/ppp/polarssl/Makefile | 3 +++
8 files changed, 44 insertions(+)
create mode 100644 Makefile
create mode 100644 src/api/Makefile
create mode 100644 src/core/Makefile
create mode 100644 src/core/ipv4/Makefile
create mode 100644 src/core/ipv6/Makefile
create mode 100644 src/netif/Makefile
create mode 100644 src/netif/ppp/Makefile
create mode 100644 src/netif/ppp/polarssl/Makefile
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..dbfb087
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+ifneq (,$(filter lwip_api,$(USEMODULE)))
+ DIRS += src/api
+endif
+ifneq (,$(filter lwip_core,$(USEMODULE)))
+ DIRS += src/core
+endif
+ifneq (,$(filter lwip_ipv4,$(USEMODULE)))
+ DIRS += src/core/ipv4
+endif
+ifneq (,$(filter lwip_ipv6,$(USEMODULE)))
+ DIRS += src/core/ipv6
+endif
+ifneq (,$(filter lwip_netif,$(USEMODULE)))
+ DIRS += src/netif
+endif
+ifneq (,$(filter lwip_netif_ppp,$(USEMODULE)))
+ DIRS += src/netif/ppp
+endif
+ifneq (,$(filter lwip_polarssl,$(USEMODULE)))
+ DIRS += src/netif/ppp/polarssl
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/api/Makefile b/src/api/Makefile
new file mode 100644
index 0000000..84b4323
--- /dev/null
+++ b/src/api/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_api
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/core/Makefile b/src/core/Makefile
new file mode 100644
index 0000000..2943234
--- /dev/null
+++ b/src/core/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_core
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/core/ipv4/Makefile b/src/core/ipv4/Makefile
new file mode 100644
index 0000000..b3a7a5e
--- /dev/null
+++ b/src/core/ipv4/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_ipv4
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/core/ipv6/Makefile b/src/core/ipv6/Makefile
new file mode 100644
index 0000000..e26e51f
--- /dev/null
+++ b/src/core/ipv6/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_ipv6
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/netif/Makefile b/src/netif/Makefile
new file mode 100644
index 0000000..bb86d8f
--- /dev/null
+++ b/src/netif/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_netif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/netif/ppp/Makefile b/src/netif/ppp/Makefile
new file mode 100644
index 0000000..bd21288
--- /dev/null
+++ b/src/netif/ppp/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_netif_ppp
+
+include $(RIOTBASE)/Makefile.base
diff --git a/src/netif/ppp/polarssl/Makefile b/src/netif/ppp/polarssl/Makefile
new file mode 100644
index 0000000..6030171
--- /dev/null
+++ b/src/netif/ppp/polarssl/Makefile
@@ -0,0 +1,3 @@
+MODULE := lwip_polarssl
+
+include $(RIOTBASE)/Makefile.base
--
1.9.1

View File

@ -76,6 +76,10 @@
#include "net/gnrc/udp.h"
#endif
#ifdef MODULE_LWIP
#include "lwip.h"
#endif
#ifdef MODULE_FIB
#include "net/fib.h"
#endif
@ -150,7 +154,10 @@ void auto_init(void)
extern void dht_auto_init(void);
dht_auto_init();
#endif
#ifdef MODULE_LWIP
DEBUG("Bootstraping lwIP.\n");
lwip_bootstrap();
#endif
/* initialize network devices */
#ifdef MODULE_AUTO_INIT_GNRC_NETIF

View File

@ -27,6 +27,10 @@
#include "net/gnrc/conn.h"
#endif
#ifdef MODULE_LWIP_CONN_IP
#include "lwip/conn.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -27,6 +27,10 @@
#include "net/gnrc/conn.h"
#endif
#ifdef MODULE_LWIP_CONN_UDP
#include "lwip/conn.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif

49
tests/lwip/Makefile Normal file
View File

@ -0,0 +1,49 @@
APPLICATION = lwip
BOARD ?= iotlab-m3
RIOTBASE ?= $(CURDIR)/../..
BOARD_BLACKLIST := arduino-mega2560 msb-430h z1
BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-mega2560 msb-430h nrf6310 \
nucleo-f334 pca10005 stm32f0discovery weio \
yunjia-nrf51822 z1
USEMODULE += lwip lwip_ipv6_autoconfig lwip_conn_ip lwip_netdev2
USEMODULE += lwip_udp lwip_conn_udp
USEMODULE += ipv6_addr
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
USEMODULE += od
# use the at86rf231 as fallback device
DRIVER := at86rf231
# define the driver to be used for selected boards
ifneq (,$(filter samr21-xpro,$(BOARD)))
DRIVER := at86rf233
endif
ifneq (,$(filter iotlab-m3 fox,$(BOARD)))
DRIVER := at86rf231
endif
ifneq (,$(filter mulle,$(BOARD)))
DRIVER := at86rf212b
endif
ifneq (,$(filter native,$(BOARD)))
DRIVER := netdev2_tap
USEMODULE += lwip_ethernet
endif
ifneq (,$(filter at86rf2%,$(DRIVER)))
FEATURES_REQUIRED = periph_spi periph_gpio
endif
USEMODULE += $(DRIVER)
QUIET ?= 1
include $(RIOTBASE)/Makefile.include
test:
./tests/01-run.py

57
tests/lwip/common.c Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 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 <stdbool.h>
#include "common.h"
size_t hex2ints(uint8_t *out, const char *in)
{
bool upper = true;
size_t out_size = 0;
while (*in != '\0') {
char c;
if ((*in >= '0') && (*in <= '9')) {
c = '0';
}
else if ((*in >= 'a') && (*in <= 'f')) {
c = 'a' - 10;
}
else if ((*in >= 'A') && (*in <= 'F')) {
c = 'A' - 10;
}
else {
in++;
continue;
}
if (upper) {
*out = (char)(*in - c) << 4;
}
else {
*out |= (char)(*in - c);
out++;
out_size++;
}
upper = !upper;
in++;
}
if (!upper) {
out_size++;
}
return out_size;
}
/** @} */

81
tests/lwip/common.h Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2016 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Definitions for tests/lwip/
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef MAIN_H_
#define MAIN_H_
#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Application configuration
* @{
*/
#define CONN_INBUF_SIZE (256)
#define SERVER_MSG_QUEUE_SIZE (8)
#define SERVER_BUFFER_SIZE (64)
/**
* @}
*/
/**
* @brief Converts hex string to byte array.
*
* @param[out] out Resulting byte array
* @param[in] in `\0` terminated string. Non-hex characters (all except 0-9, a-f, A-F)
* will be ignored.
*
* @return Length of @p out.
*/
size_t hex2ints(uint8_t *out, const char *in);
#ifdef MODULE_CONN_IP
/**
* @brief Raw IP shell command
*
* @param[in] argc number of arguments
* @param[in] argv array of arguments
*
* @return 0 on success
* @return other on error
*/
int ip_cmd(int argc, char **argv);
#endif
#ifdef MODULE_CONN_UDP
/**
* @brief UDP IP shell command
*
* @param[in] argc number of arguments
* @param[in] argv array of arguments
*
* @return 0 on success
* @return other on error
*/
int udp_cmd(int argc, char **argv);
#endif
#ifdef __cplusplus
}
#endif
#endif /* MAIN_H_ */
/** @} */

160
tests/lwip/ip.c Normal file
View File

@ -0,0 +1,160 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Demonstrating the sending and receiving of UDP data over POSIX sockets.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* @}
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "common.h"
#include "od.h"
#include "net/af.h"
#include "net/conn/ip.h"
#include "net/ipv6.h"
#include "thread.h"
#include "xtimer.h"
#ifdef MODULE_CONN_IP
static char conn_inbuf[CONN_INBUF_SIZE];
static bool server_running;
static conn_ip_t server_conn;
static char server_stack[THREAD_STACKSIZE_DEFAULT];
static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE];
static void *_server_thread(void *args)
{
ipv6_addr_t server_addr = IPV6_ADDR_UNSPECIFIED;
uint8_t protocol;
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);
/* parse protocol */
protocol = (uint8_t)atoi((char *)args);
if (conn_ip_create(&server_conn, &server_addr, sizeof(server_addr), AF_INET6, protocol) < 0) {
return NULL;
}
server_running = true;
printf("Success: started IP server on protocol %u\n", protocol);
while (1) {
int res;
ipv6_addr_t src;
size_t src_len = sizeof(ipv6_addr_t);
if ((res = conn_ip_recvfrom(&server_conn, conn_inbuf, sizeof(conn_inbuf), &src,
&src_len)) < 0) {
puts("Error on receive");
}
else if (res == 0) {
puts("No data received");
}
else {
od_hex_dump(conn_inbuf, res, 0);
}
}
return NULL;
}
static int ip_send(char *addr_str, char *port_str, char *data, unsigned int num,
unsigned int delay)
{
ipv6_addr_t src = IPV6_ADDR_UNSPECIFIED, dst;
uint8_t protocol;
uint8_t byte_data[strlen(data) / 2];
size_t data_len;
/* parse destination address */
if (ipv6_addr_from_str(&dst, addr_str) == NULL) {
puts("Error: unable to parse destination address");
return 1;
}
/* parse protocol */
protocol = (uint8_t)atoi(port_str);
data_len = hex2ints(byte_data, data);
for (unsigned int i = 0; i < num; i++) {
if (conn_ip_sendto(byte_data, data_len, &src, sizeof(src), (struct sockaddr *)&dst,
sizeof(dst), AF_INET6, protocol) < 0) {
puts("could not send");
}
else {
printf("Success: send %u byte to %s (next header: %u)\n",
(unsigned)data_len, addr_str, protocol);
}
xtimer_usleep(delay);
}
return 0;
}
static int ip_start_server(char *port_str)
{
if (thread_create(server_stack, sizeof(server_stack), THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST, _server_thread, port_str,
"IP server") <= KERNEL_PID_UNDEF) {
return 1;
}
return 0;
}
int ip_cmd(int argc, char **argv)
{
if (argc < 2) {
printf("usage: %s [send|server]\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "send") == 0) {
uint32_t num = 1;
uint32_t delay = 1000000;
if (argc < 5) {
printf("usage: %s send <addr> <protocol> <hex data> [<num> [<delay in us>]]\n",
argv[0]);
return 1;
}
if (argc > 5) {
num = (uint32_t)atoi(argv[5]);
}
if (argc > 6) {
delay = (uint32_t)atoi(argv[6]);
}
return ip_send(argv[2], argv[3], argv[4], num, delay);
}
else if (strcmp(argv[1], "server") == 0) {
if (argc < 3) {
printf("usage: %s server [start|stop]\n", argv[0]);
return 1;
}
if (strcmp(argv[2], "start") == 0) {
if (argc < 4) {
printf("usage %s server start <protocol>\n", argv[0]);
return 1;
}
return ip_start_server(argv[3]);
}
else {
puts("error: invalid command");
return 1;
}
}
else {
puts("error: invalid command");
return 1;
}
}
#else
typedef int dont_be_pedantic;
#endif
/** @} */

75
tests/lwip/main.c Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.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.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Test for raw IPv6 connections
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This test application tests the gnrc_conn_ip module. If you select protocol 58 you can also
* test if gnrc is able to deal with multiple subscribers to ICMPv6 (gnrc_icmpv6 and this
* application).
*
* @}
*/
#include <errno.h>
#include <stdio.h>
#include "common.h"
#include "lwip.h"
#include "lwip/netif.h"
#include "net/ipv6/addr.h"
#include "shell.h"
static int ifconfig(int argc, char **argv)
{
(void)argc;
(void)argv;
for (struct netif *iface = netif_list; iface != NULL; iface = iface->next) {
printf("%s_%02u: ", iface->name, iface->num);
#ifdef MODULE_LWIP_IPV6
char addrstr[IPV6_ADDR_MAX_STR_LEN];
for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ipv6_addr_is_unspecified((ipv6_addr_t *)&iface->ip6_addr[i])) {
printf(" inet6 %s\n", ipv6_addr_to_str(addrstr, (ipv6_addr_t *)&iface->ip6_addr[i],
sizeof(addrstr)));
}
}
#endif
puts("");
}
return 0;
}
static const shell_command_t shell_commands[] = {
#ifdef MODULE_CONN_IP
{ "ip", "Send IP packets and listen for packets of certain type", ip_cmd },
#endif
#ifdef MODULE_CONN_UDP
{ "udp", "Send UDP messages and listen for messages on UDP port", udp_cmd },
#endif
{ "ifconfig", "Shows assigned IPv6 addresses", ifconfig },
{ NULL, NULL, NULL }
};
static char line_buf[SHELL_DEFAULT_BUFSIZE];
char conn_inbuf[CONN_INBUF_SIZE];
int main(void)
{
puts("RIOT lwip test application");
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should be never reached */
return 0;
}

266
tests/lwip/tests/01-run.py Executable file
View File

@ -0,0 +1,266 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2016 Martine Lenders <mail@martine-lenders.eu>
#
# Distributed under terms of the MIT license.
from __future__ import print_function
import argparse
import os, sys
import random
import pexpect
import subprocess
import time
import types
DEFAULT_TIMEOUT = 5
class Strategy(object):
def __init__(self, func=None):
if func != None:
if sys.version_info < (3,):
self.__class__.execute = types.MethodType(func, self, self.__class__)
else:
self.__class__.execute = types.MethodType(func, self)
def execute(self, *args, **kwargs):
raise NotImplementedError()
class ApplicationStrategy(Strategy):
def __init__(self, app_dir=os.getcwd(), func=None):
super(ApplicationStrategy, self).__init__(func)
self.app_dir = app_dir
class BoardStrategy(Strategy):
def __init__(self, board, func=None):
super(BoardStrategy, self).__init__(func)
self.board = board
def __run_make(self, application, make_targets, env=None):
env = os.environ.copy()
if env != None:
env.update(env)
env.update(self.board.to_env())
cmd = ("make", "-C", application) + make_targets
print(' '.join(cmd))
print(subprocess.check_output(cmd, env=env))
def execute(self, application):
super(BoardStrategy, self).execute(application)
class CleanStrategy(BoardStrategy):
def execute(self, application, env=None):
super(CleanStrategy, self).__run_make(application, ("-B", "clean"), env)
class BuildStrategy(BoardStrategy):
def execute(self, application, env=None):
super(BuildStrategy, self).__run_make(application, ("all",), env)
class FlashStrategy(BoardStrategy):
def execute(self, application, env=None):
super(FlashStrategy, self).__run_make(application, ("all",), env)
class ResetStrategy(BoardStrategy):
def execute(self, application, env=None):
super(ResetStrategy, self).__run_make(application, ("reset",), env)
class Board(object):
def __init__(self, name, port=None, serial=None, clean=None,
build=None, flash=None,
reset=None, term=None):
def _reset_native_execute(obj, application, env=None, *args, **kwargs):
pass
if (name == "native") and (reset == None):
reset = _reset_native_execute
self.name = name
self.port = port
self.serial = serial
self.clean_strategy = CleanStrategy(self, clean)
self.build_strategy = BuildStrategy(self, build)
self.flash_strategy = FlashStrategy(self, flash)
self.reset_strategy = ResetStrategy(self, reset)
def __len__(self):
return 1
def __iter__(self):
return self
def next(self):
raise StopIteration()
def __repr__(self):
return ("<Board %s,port=%s,serial=%s>" %
(repr(self.name), repr(self.port), repr(self.serial)))
def to_env(self):
env = {}
if self.name:
env['BOARD'] = self.name
if self.port:
env['PORT'] = self.port
if self.serial:
env['SERIAL'] = self.serial
return env
def clean(self, application=os.getcwd(), env=None):
self.build_strategy.execute(application, env)
def build(self, application=os.getcwd(), env=None):
self.build_strategy.execute(application, env)
def flash(self, application=os.getcwd(), env=None):
self.flash_strategy.execute(application, env)
def reset(self, application=os.getcwd(), env=None):
self.reset_strategy.execute(application, env)
class BoardGroup(object):
def __init__(self, boards):
self.boards = boards
def __len__(self):
return len(self.boards)
def __iter__(self):
return iter(self.boards)
def __repr__(self):
return str(self.boards)
def clean(self, application=os.getcwd(), env=None):
for board in self.boards:
board.clean(application, env)
def build(self, application=os.getcwd(), env=None):
for board in self.boards:
board.build(application, env)
def flash(self, application=os.getcwd(), env=None):
for board in self.boards:
board.flash(application, env)
def reset(self, application=os.getcwd(), env=None):
for board in self.boards:
board.reset(application, env)
def default_test_case(board_group, application, env=None):
for board in board_group:
env = os.environ.copy()
if env != None:
env.update(env)
env.update(board.to_env())
with pexpect.spawn("make", ["-C", application, "term"], env=env,
timeout=DEFAULT_TIMEOUT,
logfile=sys.stdout) as spawn:
spawn.expect("TEST: SUCCESS")
class TestStrategy(ApplicationStrategy):
def execute(self, board_groups, test_cases=[default_test_case],
timeout=DEFAULT_TIMEOUT, env=None):
for board_group in board_groups:
print("Testing for %s: " % board_group)
for test_case in test_cases:
board_group.reset()
test_case(board_group, self.app_dir, env=None)
sys.stdout.write('.')
sys.stdout.flush()
print()
def get_ipv6_address(spawn):
spawn.sendline(u"ifconfig")
spawn.expect(u"[A-Za-z0-9]{2}[0-9]+: inet6 (fe80::[0-9a-f:]+)")
return spawn.match.group(1)
def test_ipv6_send(board_group, application, env=None):
env_sender = os.environ.copy()
if env != None:
env_sender.update(env)
env_sender.update(board_group.boards[0].to_env())
env_receiver = os.environ.copy()
if env != None:
env_receiver.update(env)
env_receiver.update(board_group.boards[1].to_env())
with pexpect.spawn("make", ["-C", application, "term"], env=env_sender,
timeout=DEFAULT_TIMEOUT) as sender, \
pexpect.spawn("make", ["-C", application, "term"], env=env_receiver,
timeout=DEFAULT_TIMEOUT) as receiver:
ipprot = random.randint(0x00, 0xff)
receiver_ip = get_ipv6_address(receiver)
receiver.sendline(u"ip server start %d" % ipprot)
# wait for neighbor discovery to be done
time.sleep(5)
sender.sendline(u"ip send %s %d 01:23:45:67:89:ab:cd:ef" % (receiver_ip, ipprot))
sender.expect_exact(u"Success: send 8 byte to %s (next header: %d)" %
(receiver_ip, ipprot))
receiver.expect(u"000000 60 00 00 00 00 08 %s ff fe 80 00 00 00 00 00 00" % hex(ipprot)[2:])
receiver.expect(u"000010( [0-9a-f]{2}){8} fe 80 00 00 00 00 00 00")
receiver.expect(u"000020( [0-9a-f]{2}){8} 01 23 45 67 89 ab cd ef")
def test_udpv6_send(board_group, application, env=None):
env_sender = os.environ.copy()
if env != None:
env_sender.update(env)
env_sender.update(board_group.boards[0].to_env())
env_receiver = os.environ.copy()
if env != None:
env_receiver.update(env)
env_receiver.update(board_group.boards[1].to_env())
with pexpect.spawn("make", ["-C", application, "term"], env=env_sender,
timeout=DEFAULT_TIMEOUT) as sender, \
pexpect.spawn("make", ["-C", application, "term"], env=env_receiver,
timeout=DEFAULT_TIMEOUT) as receiver:
port = random.randint(0x0000, 0xffff)
receiver_ip = get_ipv6_address(receiver)
receiver.sendline(u"udp server start %d" % port)
# wait for neighbor discovery to be done
time.sleep(5)
sender.sendline(u"udp send %s %d ab:cd:ef" % (receiver_ip, port))
sender.expect_exact(u"Success: send 3 byte to [%s]:%d" %
(receiver_ip, port))
receiver.expect(u"000000 ab cd ef")
def test_dual_send(board_group, application, env=None):
env_sender = os.environ.copy()
if env != None:
env_sender.update(env)
env_sender.update(board_group.boards[0].to_env())
env_receiver = os.environ.copy()
if env != None:
env_receiver.update(env)
env_receiver.update(board_group.boards[1].to_env())
with pexpect.spawn("make", ["-C", application, "term"], env=env_sender,
timeout=DEFAULT_TIMEOUT) as sender, \
pexpect.spawn("make", ["-C", application, "term"], env=env_receiver,
timeout=DEFAULT_TIMEOUT) as receiver:
port = random.randint(0x0000, 0xffff)
ipprot = random.randint(0x00, 0xff)
receiver_ip = get_ipv6_address(receiver)
receiver.sendline(u"ip server start %d" % ipprot)
receiver.sendline(u"udp server start %d" % port)
# wait for neighbor discovery to be done
time.sleep(5)
sender.sendline(u"udp send %s %d 01:23" % (receiver_ip, port))
sender.expect_exact(u"Success: send 2 byte to [%s]:%d" %
(receiver_ip, port))
receiver.expect(u"000000 01 23")
sender.sendline(u"ip send %s %d 01:02:03:04" % (receiver_ip, ipprot))
sender.expect_exact(u"Success: send 4 byte to %s (next header: %d)" %
(receiver_ip, ipprot))
receiver.expect(u"000000 60 00 00 00 00 04 %s ff fe 80 00 00 00 00 00 00" % hex(ipprot)[2:])
receiver.expect(u"000010( [0-9a-f]{2}){8} fe 80 00 00 00 00 00 00")
receiver.expect(u"000020( [0-9a-f]{2}){8} 01 02 03 04")
if __name__ == "__main__":
del os.environ['TERMFLAGS']
TestStrategy().execute([BoardGroup((Board("native", "tap0"), \
Board("native", "tap1")))], \
[test_ipv6_send, test_udpv6_send, test_dual_send])

168
tests/lwip/udp.c Normal file
View File

@ -0,0 +1,168 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Demonstrating the sending and receiving of UDP data over POSIX sockets.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* @}
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "common.h"
#include "od.h"
#include "net/af.h"
#include "net/conn/udp.h"
#include "net/ipv6.h"
#include "thread.h"
#include "xtimer.h"
#ifdef MODULE_CONN_UDP
static char conn_inbuf[CONN_INBUF_SIZE];
static bool server_running;
static conn_udp_t server_conn;
static char server_stack[THREAD_STACKSIZE_DEFAULT];
static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE];
static void *_server_thread(void *args)
{
ipv6_addr_t server_addr = IPV6_ADDR_UNSPECIFIED;
uint16_t port;
int res;
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);
/* parse port */
port = (uint16_t)atoi((char *)args);
if ((res = conn_udp_create(&server_conn, &server_addr,
sizeof(server_addr), AF_INET6, port)) < 0) {
printf("Unable to open UDP server on port %" PRIu16 " (error code %d)\n",
port, -res);
return NULL;
}
server_running = true;
printf("Success: started UDP server on port %" PRIu16 "\n", port);
while (1) {
int res;
ipv6_addr_t src;
size_t src_len = sizeof(ipv6_addr_t);
uint16_t sport;
if ((res = conn_udp_recvfrom(&server_conn, conn_inbuf, sizeof(conn_inbuf), &src,
&src_len, &sport)) < 0) {
puts("Error on receive");
}
else if (res == 0) {
puts("No data received");
}
else {
char addrstr[IPV6_ADDR_MAX_STR_LEN];
printf("Received from [%s]:%" PRIu16 ":\n", ipv6_addr_to_str(addrstr, &src,
sizeof(addrstr)), sport);
od_hex_dump(conn_inbuf, res, 0);
}
}
return NULL;
}
static int udp_send(char *addr_str, char *port_str, char *data, unsigned int num,
unsigned int delay)
{
ipv6_addr_t src = IPV6_ADDR_UNSPECIFIED, dst;
uint16_t port;
uint8_t byte_data[strlen(data) / 2];
size_t data_len;
/* parse destination address */
if (ipv6_addr_from_str(&dst, addr_str) == NULL) {
puts("Error: unable to parse destination address");
return 1;
}
/* parse port */
port = (uint16_t)atoi(port_str);
data_len = hex2ints(byte_data, data);
for (unsigned int i = 0; i < num; i++) {
if (conn_udp_sendto(byte_data, data_len, &src, sizeof(src), (struct sockaddr *)&dst,
sizeof(dst), AF_INET6, port, port) < 0) {
puts("could not send");
}
else {
printf("Success: send %u byte to [%s]:%" PRIu16 ")\n",
(unsigned)data_len, addr_str, port);
}
xtimer_usleep(delay);
}
return 0;
}
static int udp_start_server(char *port_str)
{
if (thread_create(server_stack, sizeof(server_stack), THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST, _server_thread, port_str,
"UDP server") <= KERNEL_PID_UNDEF) {
return 1;
}
return 0;
}
int udp_cmd(int argc, char **argv)
{
if (argc < 2) {
printf("usage: %s [send|server]\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "send") == 0) {
uint32_t num = 1;
uint32_t delay = 1000000;
if (argc < 5) {
printf("usage: %s send <addr> <port> <hex data> [<num> [<delay in us>]]\n",
argv[0]);
return 1;
}
if (argc > 5) {
num = (uint32_t)atoi(argv[5]);
}
if (argc > 6) {
delay = (uint32_t)atoi(argv[6]);
}
return udp_send(argv[2], argv[3], argv[4], num, delay);
}
else if (strcmp(argv[1], "server") == 0) {
if (argc < 3) {
printf("usage: %s server [start|stop]\n", argv[0]);
return 1;
}
if (strcmp(argv[2], "start") == 0) {
if (argc < 4) {
printf("usage %s server start <port>\n", argv[0]);
return 1;
}
return udp_start_server(argv[3]);
}
else {
puts("error: invalid command");
return 1;
}
}
else {
puts("error: invalid command");
return 1;
}
}
#else
typedef int dont_be_pedantic;
#endif
/** @} */