From 7f475573e6b222a3146cdde9677a9e8bedf4207c Mon Sep 17 00:00:00 2001 From: Martine Lenders <mlenders@inf.fu-berlin.de> Date: Fri, 13 Nov 2015 19:41:11 +0100 Subject: [PATCH] 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 <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; +} + +/** @} */ 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 <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_ */ +/** @} */ -- GitLab