From 29515a7bb9f6b5abab9bef33826089991f4d79dd Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 3 Aug 2015 22:30:46 +0200 Subject: [PATCH 1/7] pkg: initial import of lwIP package --- Makefile.dep | 5 + pkg/lwip/Makefile | 11 ++ pkg/lwip/Makefile.include | 2 + pkg/lwip/doc.txt | 6 + pkg/lwip/patches/0001-Fix-warnings.patch | 29 +++++ .../patches/0002-Add-RIOT-Makefiles.patch | 119 ++++++++++++++++++ 6 files changed, 172 insertions(+) create mode 100644 pkg/lwip/Makefile create mode 100644 pkg/lwip/Makefile.include create mode 100644 pkg/lwip/doc.txt create mode 100644 pkg/lwip/patches/0001-Fix-warnings.patch create mode 100644 pkg/lwip/patches/0002-Add-RIOT-Makefiles.patch diff --git a/Makefile.dep b/Makefile.dep index 554aaf5e6a..7d78585519 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -354,6 +354,11 @@ ifneq (,$(filter posix_semaphore,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter lwip,$(USEMODULE))) + USEPKG += lwip + USEMODULE += lwip_core +endif + ifneq (,$(filter sema,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/pkg/lwip/Makefile b/pkg/lwip/Makefile new file mode 100644 index 0000000000..ea3d93ed5e --- /dev/null +++ b/pkg/lwip/Makefile @@ -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 diff --git a/pkg/lwip/Makefile.include b/pkg/lwip/Makefile.include new file mode 100644 index 0000000000..e944a48255 --- /dev/null +++ b/pkg/lwip/Makefile.include @@ -0,0 +1,2 @@ +INCLUDES += -I$(RIOTBASE)/pkg/lwip/include \ + -I$(BINDIRBASE)/pkg/$(BOARD)/lwip/src/include diff --git a/pkg/lwip/doc.txt b/pkg/lwip/doc.txt new file mode 100644 index 0000000000..7c603ca11d --- /dev/null +++ b/pkg/lwip/doc.txt @@ -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/ + */ diff --git a/pkg/lwip/patches/0001-Fix-warnings.patch b/pkg/lwip/patches/0001-Fix-warnings.patch new file mode 100644 index 0000000000..be2dc43362 --- /dev/null +++ b/pkg/lwip/patches/0001-Fix-warnings.patch @@ -0,0 +1,29 @@ +From 0e28e1cd26c1de2ccf48bea9013676ef1d4d69b7 Mon Sep 17 00:00:00 2001 +From: Martine Lenders +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 + diff --git a/pkg/lwip/patches/0002-Add-RIOT-Makefiles.patch b/pkg/lwip/patches/0002-Add-RIOT-Makefiles.patch new file mode 100644 index 0000000000..4b9ec25d19 --- /dev/null +++ b/pkg/lwip/patches/0002-Add-RIOT-Makefiles.patch @@ -0,0 +1,119 @@ +From 4f1f9c53db7ffeece81253d9b39d78296e5b68a8 Mon Sep 17 00:00:00 2001 +From: Martine Lenders +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 + From 932bec50ed1fce9ed06eae75c3970cc282043a70 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 15 Nov 2015 20:58:39 +0100 Subject: [PATCH 2/7] lwip: add port for RIOT --- Makefile.dep | 5 + pkg/lwip/Makefile.include | 4 + pkg/lwip/contrib/Makefile | 3 + pkg/lwip/contrib/doc.txt | 3 + pkg/lwip/contrib/lwip.c | 32 +++++ pkg/lwip/contrib/sys_arch.c | 221 +++++++++++++++++++++++++++++++ pkg/lwip/include/arch/cc.h | 132 ++++++++++++++++++ pkg/lwip/include/arch/sys_arch.h | 91 +++++++++++++ pkg/lwip/include/lwip.h | 45 +++++++ pkg/lwip/include/lwipopts.h | 54 ++++++++ sys/auto_init/auto_init.c | 9 +- 11 files changed, 598 insertions(+), 1 deletion(-) create mode 100644 pkg/lwip/contrib/Makefile create mode 100644 pkg/lwip/contrib/doc.txt create mode 100644 pkg/lwip/contrib/lwip.c create mode 100644 pkg/lwip/contrib/sys_arch.c create mode 100644 pkg/lwip/include/arch/cc.h create mode 100644 pkg/lwip/include/arch/sys_arch.h create mode 100644 pkg/lwip/include/lwip.h create mode 100644 pkg/lwip/include/lwipopts.h diff --git a/Makefile.dep b/Makefile.dep index 7d78585519..9854b0ee87 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -356,9 +356,14 @@ endif ifneq (,$(filter lwip,$(USEMODULE))) USEPKG += lwip + USEMODULE += lwip_contrib USEMODULE += lwip_core endif +ifneq (,$(filter lwip_contrib,$(USEMODULE))) + USEMODULE += sema +endif + ifneq (,$(filter sema,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/pkg/lwip/Makefile.include b/pkg/lwip/Makefile.include index e944a48255..de6a9f0069 100644 --- a/pkg/lwip/Makefile.include +++ b/pkg/lwip/Makefile.include @@ -1,2 +1,6 @@ INCLUDES += -I$(RIOTBASE)/pkg/lwip/include \ -I$(BINDIRBASE)/pkg/$(BOARD)/lwip/src/include + +ifneq (,$(filter lwip_contrib,$(USEMODULE))) + DIRS += $(RIOTBASE)/pkg/lwip/contrib +endif \ No newline at end of file diff --git a/pkg/lwip/contrib/Makefile b/pkg/lwip/contrib/Makefile new file mode 100644 index 0000000000..048d70b685 --- /dev/null +++ b/pkg/lwip/contrib/Makefile @@ -0,0 +1,3 @@ +MODULE := lwip_contrib + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lwip/contrib/doc.txt b/pkg/lwip/contrib/doc.txt new file mode 100644 index 0000000000..d11a87565b --- /dev/null +++ b/pkg/lwip/contrib/doc.txt @@ -0,0 +1,3 @@ +/** + * @defgroup lwip_contrib RIOT lwIP port + */ diff --git a/pkg/lwip/contrib/lwip.c b/pkg/lwip/contrib/lwip.c new file mode 100644 index 0000000000..83ee33a1ba --- /dev/null +++ b/pkg/lwip/contrib/lwip.c @@ -0,0 +1,32 @@ +/* + * 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 + */ + +#include "lwip/tcpip.h" +#include "lwip/netif/netdev2.h" +#include "lwip/netif.h" + +#include "netdev2_tap.h" + +#include "lwip.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +void lwip_bootstrap(void) +{ + tcpip_init(NULL, NULL); +} + +/** @} */ diff --git a/pkg/lwip/contrib/sys_arch.c b/pkg/lwip/contrib/sys_arch.c new file mode 100644 index 0000000000..767e74d7a2 --- /dev/null +++ b/pkg/lwip/contrib/sys_arch.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 +#include +#include + +#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; +} + +/** @} */ diff --git a/pkg/lwip/include/arch/cc.h b/pkg/lwip/include/arch/cc.h new file mode 100644 index 0000000000..663efe794a --- /dev/null +++ b/pkg/lwip/include/arch/cc.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +#include +#include +#include +#include + +#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 */ +/** @} */ diff --git a/pkg/lwip/include/arch/sys_arch.h b/pkg/lwip/include/arch/sys_arch.h new file mode 100644 index 0000000000..1b02458e2c --- /dev/null +++ b/pkg/lwip/include/arch/sys_arch.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#ifndef LWIP_ARCH_SYS_ARCH_H +#define LWIP_ARCH_SYS_ARCH_H + +#include +#include + +#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 */ +/** @} */ diff --git a/pkg/lwip/include/lwip.h b/pkg/lwip/include/lwip.h new file mode 100644 index 0000000000..999d07bca0 --- /dev/null +++ b/pkg/lwip/include/lwip.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#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_ */ +/** @} */ diff --git a/pkg/lwip/include/lwipopts.h b/pkg/lwip/include/lwipopts.h new file mode 100644 index 0000000000..5d9d9dfac1 --- /dev/null +++ b/pkg/lwip/include/lwipopts.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#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 + * @{ + */ +#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_ */ +/** @} */ diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 1d1f43d00a..ff98b4a8f9 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -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 From b0347527fd8eea21a2180ba6c112aef89f60f10a Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 15 Nov 2015 20:59:19 +0100 Subject: [PATCH 3/7] lwip: map lwIP modules to RIOT modules --- Makefile.dep | 35 +++++++++++++ Makefile.pseudomodules | 13 +++++ pkg/lwip/include/lwipopts.h | 97 +++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) diff --git a/Makefile.dep b/Makefile.dep index 9854b0ee87..4afce6fbeb 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -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,10 +357,42 @@ 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_%,$(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))) diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index ffd345d638..ee4ad6ec2c 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -16,6 +16,19 @@ PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc PSEUDOMODULES += gnrc_pktbuf PSEUDOMODULES += log PSEUDOMODULES += log_printfnoformat +PSEUDOMODULES += lwip_arp +PSEUDOMODULES += lwip_autoip +PSEUDOMODULES += lwip_conn +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 += newlib PSEUDOMODULES += newlib_nano diff --git a/pkg/lwip/include/lwipopts.h b/pkg/lwip/include/lwipopts.h index 5d9d9dfac1..5e29634c34 100644 --- a/pkg/lwip/include/lwipopts.h +++ b/pkg/lwip/include/lwipopts.h @@ -32,6 +32,103 @@ extern "C" { * @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) From 7f475573e6b222a3146cdde9677a9e8bedf4207c Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Fri, 13 Nov 2015 19:41:11 +0100 Subject: [PATCH 4/7] lwip_netdev2: initial import of a lwIP netdev2 wrapper --- pkg/lwip/Makefile.include | 5 +- pkg/lwip/contrib/lwip.c | 47 +++++ pkg/lwip/contrib/netdev2/Makefile | 3 + pkg/lwip/contrib/netdev2/lwip_netdev2.c | 262 ++++++++++++++++++++++++ pkg/lwip/include/lwip/netif/netdev2.h | 62 ++++++ 5 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 pkg/lwip/contrib/netdev2/Makefile create mode 100644 pkg/lwip/contrib/netdev2/lwip_netdev2.c create mode 100644 pkg/lwip/include/lwip/netif/netdev2.h diff --git a/pkg/lwip/Makefile.include b/pkg/lwip/Makefile.include index de6a9f0069..a59a21b64f 100644 --- a/pkg/lwip/Makefile.include +++ b/pkg/lwip/Makefile.include @@ -3,4 +3,7 @@ INCLUDES += -I$(RIOTBASE)/pkg/lwip/include \ ifneq (,$(filter lwip_contrib,$(USEMODULE))) DIRS += $(RIOTBASE)/pkg/lwip/contrib -endif \ No newline at end of file +endif +ifneq (,$(filter lwip_netdev2,$(USEMODULE))) + DIRS += $(RIOTBASE)/pkg/lwip/contrib/netdev2 +endif diff --git a/pkg/lwip/contrib/lwip.c b/pkg/lwip/contrib/lwip.c index 83ee33a1ba..a3e5babb00 100644 --- a/pkg/lwip/contrib/lwip.c +++ b/pkg/lwip/contrib/lwip.c @@ -16,16 +16,63 @@ #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); } diff --git a/pkg/lwip/contrib/netdev2/Makefile b/pkg/lwip/contrib/netdev2/Makefile new file mode 100644 index 0000000000..d6d2e10f9d --- /dev/null +++ b/pkg/lwip/contrib/netdev2/Makefile @@ -0,0 +1,3 @@ +MODULE := lwip_netdev2 + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lwip/contrib/netdev2/lwip_netdev2.c b/pkg/lwip/contrib/netdev2/lwip_netdev2.c new file mode 100644 index 0000000000..d80cf8716c --- /dev/null +++ b/pkg/lwip/contrib/netdev2/lwip_netdev2.c @@ -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 + */ + +#include +#include +#include + +#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; +} + +/** @} */ diff --git a/pkg/lwip/include/lwip/netif/netdev2.h b/pkg/lwip/include/lwip/netif/netdev2.h new file mode 100644 index 0000000000..93a7db9250 --- /dev/null +++ b/pkg/lwip/include/lwip/netif/netdev2.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#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_ */ +/** @} */ From 410f44f07dc3a1af1ee56c8acadc10e593b0e3d3 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Fri, 27 Nov 2015 17:14:25 +0100 Subject: [PATCH 5/7] lwip: initial import of conn_ip wrapper --- Makefile.dep | 8 + Makefile.pseudomodules | 1 - pkg/lwip/Makefile.include | 6 + pkg/lwip/contrib/conn/Makefile | 3 + pkg/lwip/contrib/conn/ip/Makefile | 3 + pkg/lwip/contrib/conn/ip/lwip_conn_ip.c | 73 +++++++++ pkg/lwip/contrib/conn/lwip_conn.c | 206 ++++++++++++++++++++++++ pkg/lwip/include/lwip/conn.h | 93 +++++++++++ sys/include/net/conn/ip.h | 4 + 9 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 pkg/lwip/contrib/conn/Makefile create mode 100644 pkg/lwip/contrib/conn/ip/Makefile create mode 100644 pkg/lwip/contrib/conn/ip/lwip_conn_ip.c create mode 100644 pkg/lwip/contrib/conn/lwip_conn.c create mode 100644 pkg/lwip/include/lwip/conn.h diff --git a/Makefile.dep b/Makefile.dep index 4afce6fbeb..4378b98f7b 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -373,6 +373,14 @@ 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_%,$(USEMODULE))) USEMODULE += lwip endif diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index ee4ad6ec2c..e75766de79 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -18,7 +18,6 @@ PSEUDOMODULES += log PSEUDOMODULES += log_printfnoformat PSEUDOMODULES += lwip_arp PSEUDOMODULES += lwip_autoip -PSEUDOMODULES += lwip_conn PSEUDOMODULES += lwip_dhcp PSEUDOMODULES += lwip_ethernet PSEUDOMODULES += lwip_igmp diff --git a/pkg/lwip/Makefile.include b/pkg/lwip/Makefile.include index a59a21b64f..1bd97c9b1a 100644 --- a/pkg/lwip/Makefile.include +++ b/pkg/lwip/Makefile.include @@ -1,6 +1,12 @@ 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_contrib,$(USEMODULE))) DIRS += $(RIOTBASE)/pkg/lwip/contrib endif diff --git a/pkg/lwip/contrib/conn/Makefile b/pkg/lwip/contrib/conn/Makefile new file mode 100644 index 0000000000..e89c126dda --- /dev/null +++ b/pkg/lwip/contrib/conn/Makefile @@ -0,0 +1,3 @@ +MODULE := lwip_conn + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lwip/contrib/conn/ip/Makefile b/pkg/lwip/contrib/conn/ip/Makefile new file mode 100644 index 0000000000..0e758e17e1 --- /dev/null +++ b/pkg/lwip/contrib/conn/ip/Makefile @@ -0,0 +1,3 @@ +MODULE := lwip_conn_ip + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lwip/contrib/conn/ip/lwip_conn_ip.c b/pkg/lwip/contrib/conn/ip/lwip_conn_ip.c new file mode 100644 index 0000000000..f30d93b1ee --- /dev/null +++ b/pkg/lwip/contrib/conn/ip/lwip_conn_ip.c @@ -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 + */ + +#include +#include + +#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; +} + +/** @} */ diff --git a/pkg/lwip/contrib/conn/lwip_conn.c b/pkg/lwip/contrib/conn/lwip_conn.c new file mode 100644 index 0000000000..589a0032cb --- /dev/null +++ b/pkg/lwip/contrib/conn/lwip_conn.c @@ -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 + */ + +#include +#include + +#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; +} + +/** @} */ diff --git a/pkg/lwip/include/lwip/conn.h b/pkg/lwip/include/lwip/conn.h new file mode 100644 index 0000000000..be7bda1cff --- /dev/null +++ b/pkg/lwip/include/lwip/conn.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#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_ */ +/** @} */ diff --git a/sys/include/net/conn/ip.h b/sys/include/net/conn/ip.h index ee7cf92081..4df3e8626b 100644 --- a/sys/include/net/conn/ip.h +++ b/sys/include/net/conn/ip.h @@ -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 From 5431df6a7e03d54f2d9d0d0bbf4b6aea12bf2980 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 1 Dec 2015 16:42:43 +0100 Subject: [PATCH 6/7] lwip: initial import of conn_udp wrapper --- Makefile.dep | 4 ++ pkg/lwip/Makefile.include | 3 + pkg/lwip/contrib/conn/udp/Makefile | 3 + pkg/lwip/contrib/conn/udp/lwip_conn_udp.c | 75 +++++++++++++++++++++++ sys/include/net/conn/udp.h | 4 ++ 5 files changed, 89 insertions(+) create mode 100644 pkg/lwip/contrib/conn/udp/Makefile create mode 100644 pkg/lwip/contrib/conn/udp/lwip_conn_udp.c diff --git a/Makefile.dep b/Makefile.dep index 4378b98f7b..601eea3eeb 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -381,6 +381,10 @@ 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 diff --git a/pkg/lwip/Makefile.include b/pkg/lwip/Makefile.include index 1bd97c9b1a..f858b60853 100644 --- a/pkg/lwip/Makefile.include +++ b/pkg/lwip/Makefile.include @@ -7,6 +7,9 @@ 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 diff --git a/pkg/lwip/contrib/conn/udp/Makefile b/pkg/lwip/contrib/conn/udp/Makefile new file mode 100644 index 0000000000..4ebff9f544 --- /dev/null +++ b/pkg/lwip/contrib/conn/udp/Makefile @@ -0,0 +1,3 @@ +MODULE := lwip_conn_udp + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lwip/contrib/conn/udp/lwip_conn_udp.c b/pkg/lwip/contrib/conn/udp/lwip_conn_udp.c new file mode 100644 index 0000000000..1c37ed0a60 --- /dev/null +++ b/pkg/lwip/contrib/conn/udp/lwip_conn_udp.c @@ -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 + */ + +#include +#include + +#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; +} + +/** @} */ diff --git a/sys/include/net/conn/udp.h b/sys/include/net/conn/udp.h index 02d7cb9361..2e400a0cf7 100644 --- a/sys/include/net/conn/udp.h +++ b/sys/include/net/conn/udp.h @@ -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 From 9b8417fbb9df0dc54bb485be619cca56a25e8bc6 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 15 Nov 2015 21:00:07 +0100 Subject: [PATCH 7/7] tests: intial import of lwIP test application --- tests/lwip/Makefile | 49 +++++++ tests/lwip/common.c | 57 ++++++++ tests/lwip/common.h | 81 +++++++++++ tests/lwip/ip.c | 160 ++++++++++++++++++++++ tests/lwip/main.c | 75 +++++++++++ tests/lwip/tests/01-run.py | 266 +++++++++++++++++++++++++++++++++++++ tests/lwip/udp.c | 168 +++++++++++++++++++++++ 7 files changed, 856 insertions(+) create mode 100644 tests/lwip/Makefile create mode 100644 tests/lwip/common.c create mode 100644 tests/lwip/common.h create mode 100644 tests/lwip/ip.c create mode 100644 tests/lwip/main.c create mode 100755 tests/lwip/tests/01-run.py create mode 100644 tests/lwip/udp.c diff --git a/tests/lwip/Makefile b/tests/lwip/Makefile new file mode 100644 index 0000000000..2e1c844b49 --- /dev/null +++ b/tests/lwip/Makefile @@ -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 diff --git a/tests/lwip/common.c b/tests/lwip/common.c new file mode 100644 index 0000000000..ec50688980 --- /dev/null +++ b/tests/lwip/common.c @@ -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 + */ + +#include + +#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; +} + +/** @} */ diff --git a/tests/lwip/common.h b/tests/lwip/common.h new file mode 100644 index 0000000000..635f1dae94 --- /dev/null +++ b/tests/lwip/common.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Martine Lenders + * + * 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 + */ +#ifndef MAIN_H_ +#define MAIN_H_ + +#include +#include + +#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_ */ +/** @} */ diff --git a/tests/lwip/ip.c b/tests/lwip/ip.c new file mode 100644 index 0000000000..dac3059e46 --- /dev/null +++ b/tests/lwip/ip.c @@ -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 + * + * @} + */ + +#include +#include +#include + +#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 [ []]\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 \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 + +/** @} */ diff --git a/tests/lwip/main.c b/tests/lwip/main.c new file mode 100644 index 0000000000..4a26afa2c3 --- /dev/null +++ b/tests/lwip/main.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + * + * 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 +#include + +#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; +} diff --git a/tests/lwip/tests/01-run.py b/tests/lwip/tests/01-run.py new file mode 100755 index 0000000000..2490f502d1 --- /dev/null +++ b/tests/lwip/tests/01-run.py @@ -0,0 +1,266 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# +# Copyright © 2016 Martine Lenders +# +# 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 ("" % + (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]) diff --git a/tests/lwip/udp.c b/tests/lwip/udp.c new file mode 100644 index 0000000000..748110cc6e --- /dev/null +++ b/tests/lwip/udp.c @@ -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 + * + * @} + */ + +#include +#include +#include + +#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 [ []]\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 \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 + +/** @} */