From 81ef15287a96bfe2db0c528e9b0aae148e8440f8 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Fri, 28 Oct 2016 15:21:08 +0200 Subject: [PATCH] native: provide socket-based ZEP device --- boards/native/Makefile.dep | 6 + cpu/native/Makefile | 5 + cpu/native/include/native_internal.h | 2 + cpu/native/include/socket_zep.h | 84 ++++ cpu/native/include/socket_zep_params.h | 54 +++ cpu/native/socket_zep/Makefile | 3 + cpu/native/socket_zep/socket_zep.c | 443 +++++++++++++++++++++ cpu/native/startup.c | 103 ++++- cpu/native/syscalls.c | 4 + sys/auto_init/auto_init.c | 5 + sys/auto_init/netif/auto_init_socket_zep.c | 60 +++ sys/include/net/zep.h | 102 +++++ 12 files changed, 869 insertions(+), 2 deletions(-) create mode 100644 cpu/native/include/socket_zep.h create mode 100644 cpu/native/include/socket_zep_params.h create mode 100644 cpu/native/socket_zep/Makefile create mode 100644 cpu/native/socket_zep/socket_zep.c create mode 100644 sys/auto_init/netif/auto_init_socket_zep.c create mode 100644 sys/include/net/zep.h diff --git a/boards/native/Makefile.dep b/boards/native/Makefile.dep index 81853370f6..2639777a1d 100644 --- a/boards/native/Makefile.dep +++ b/boards/native/Makefile.dep @@ -12,3 +12,9 @@ ifneq (,$(filter can,$(USEMODULE))) CFLAGS += -DCAN_DLL_NUMOF=2 endif endif + +ifneq (,$(filter socket_zep,$(USEMODULE))) + USEMODULE += netdev_ieee802154 + USEMODULE += checksum + USEMODULE += random +endif diff --git a/cpu/native/Makefile b/cpu/native/Makefile index 55c4961b4e..343092dfab 100644 --- a/cpu/native/Makefile +++ b/cpu/native/Makefile @@ -6,6 +6,11 @@ DIRS += vfs ifneq (,$(filter netdev_tap,$(USEMODULE))) DIRS += netdev_tap endif + +ifneq (,$(filter socket_zep,$(USEMODULE))) + DIRS += socket_zep +endif + ifneq (,$(filter mtd_native,$(USEMODULE))) DIRS += mtd endif diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index 716c526cd5..e00fbaa87b 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -94,6 +94,7 @@ extern void (*real_srandom)(unsigned int seed); extern int (*real_accept)(int socket, ...); /* The ... is a hack to save includes: */ extern int (*real_bind)(int socket, ...); +extern int (*real_connect)(int socket, ...); extern int (*real_chdir)(const char *path); extern int (*real_close)(int); extern int (*real_fcntl)(int, int, ...); @@ -108,6 +109,7 @@ extern int (*real_fork)(void); extern int (*real_getaddrinfo)(const char *node, ...); extern int (*real_getifaddrs)(struct ifaddrs **ifap); extern int (*real_getpid)(void); +extern int (*real_gettimeofday)(struct timeval *t, ...); extern int (*real_ioctl)(int fildes, int request, ...); extern int (*real_listen)(int socket, int backlog); extern int (*real_open)(const char *path, int oflag, ...); diff --git a/cpu/native/include/socket_zep.h b/cpu/native/include/socket_zep.h new file mode 100644 index 0000000000..8797f03369 --- /dev/null +++ b/cpu/native/include/socket_zep.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup netdev_socket_zep Socket-based ZEP + * @ingroup netdev + * @brief UDP socket-based IEEE 802.15.4 device over ZEP + * @{ + * + * @file + * @brief Socket ZEP definitions + * + * @author Martine Lenders + */ +#ifndef SOCKET_ZEP_H +#define SOCKET_ZEP_H + +#include +#include "net/netdev.h" +#include "net/netdev/ieee802154.h" +#include "net/zep.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 127 - 25 as in at86rf2xx */ +#define SOCKET_ZEP_FRAME_PAYLOAD_LEN (102) /**< maximum possible payload size */ + +/** + * @brief ZEP device state + */ +typedef struct { + netdev_ieee802154_t netdev; /**< netdev internal member */ + int sock_fd; /**< socket fd */ + netdev_event_t last_event; /**< event triggered */ + uint32_t seq; /**< ZEP sequence number */ + /** + * @brief Receive buffer + */ + uint8_t rcv_buf[sizeof(zep_v2_data_hdr_t) + IEEE802154_FRAME_LEN_MAX]; + /** + * @brief Buffer for send header + */ + uint8_t snd_hdr_buf[sizeof(zep_v2_data_hdr_t)]; + uint16_t chksum_buf; /**< buffer for send checksum calculation */ +} socket_zep_t; + +/** + * @brief ZEP device initialization parameters + */ +typedef struct { + char *local_addr; /**< local address string */ + char *local_port; /**< local address string */ + char *remote_addr; /**< remote address string */ + char *remote_port; /**< local address string */ +} socket_zep_params_t; + +/** + * @brief Setup socket_zep_t structure + * + * @param[in] dev the preallocated socket_zep_t device handle to setup + * @param[in] params initialization parameters + */ +void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params); + +/** + * @brief Cleanup socket resources + * + * @param dev the socket_zep device handle to cleanup + */ +void socket_zep_cleanup(socket_zep_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* SOCKET_ZEP_H */ +/** @} */ diff --git a/cpu/native/include/socket_zep_params.h b/cpu/native/include/socket_zep_params.h new file mode 100644 index 0000000000..b8a73bfeb8 --- /dev/null +++ b/cpu/native/include/socket_zep_params.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup netdev_socket_zep + * @{ + * + * @file + * @brief Configuration parameters for the @ref netdev_socket_zep driver + * + * @author Martine Lenders + */ +#ifndef SOCKET_ZEP_PARAMS_H +#define SOCKET_ZEP_PARAMS_H + +#include "socket_zep.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Number of allocated parameters at @ref socket_zep_params + * + * @note This was desided to only be confiruable on compile-time to be + * more similar to actual boards + */ +#ifndef SOCKET_ZEP_MAX +#define SOCKET_ZEP_MAX (1) +#endif + +/** + * @name Default parameters for native argument parsing + * @{ + */ +#define SOCKET_ZEP_PORT_DEFAULT "17754" /**< default port */ +#define SOCKET_ZEP_LOCAL_ADDR_DEFAULT "::" /**< default local address */ +/** + * @} + */ + +extern socket_zep_params_t socket_zep_params[SOCKET_ZEP_MAX]; + +#ifdef __cplusplus +} +#endif + +#endif /* SOCKET_ZEP_PARAMS_H */ +/** @} */ diff --git a/cpu/native/socket_zep/Makefile b/cpu/native/socket_zep/Makefile new file mode 100644 index 0000000000..7d178b6174 --- /dev/null +++ b/cpu/native/socket_zep/Makefile @@ -0,0 +1,3 @@ +include $(RIOTBASE)/Makefile.base + +INCLUDES = $(NATIVEINCLUDES) diff --git a/cpu/native/socket_zep/socket_zep.c b/cpu/native/socket_zep/socket_zep.c new file mode 100644 index 0000000000..d3e51c69ed --- /dev/null +++ b/cpu/native/socket_zep/socket_zep.c @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "async_read.h" +#include "byteorder.h" +#include "checksum/ucrc16.h" +#include "native_internal.h" +#include "random.h" + +#include "socket_zep.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define _UNIX_NTP_ERA_OFFSET (2208988800U) + +static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n); +static int _recv(netdev_t *netdev, void *buf, size_t n, void *info); +static void _isr(netdev_t *netdev); +static int _init(netdev_t *netdev); +static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len); +static int _set(netdev_t *netdev, netopt_t opt, const void *value, + size_t value_len); + +static const netdev_driver_t socket_zep_driver = { + .send = _send, + .recv = _recv, + .init = _init, + .isr = _isr, + .get = _get, + .set = _set, +}; + +static size_t _zep_hdr_fill_v2_data(socket_zep_t *dev, zep_v2_data_hdr_t *hdr, + size_t payload_len) +{ + struct timeval tv; + + real_gettimeofday(&tv, NULL); + hdr->hdr.version = 2; + hdr->type = ZEP_V2_TYPE_DATA; + hdr->chan = dev->netdev.chan; + hdr->dev = byteorder_htons((uint16_t)((((intptr_t)dev)) & 0xffff)); + hdr->lqi_mode = 1; + hdr->lqi_val = 0xff; /* TODO: set */ + hdr->time.seconds = byteorder_htonl(tv.tv_sec + _UNIX_NTP_ERA_OFFSET); + hdr->time.fraction = byteorder_htonl((tv.tv_usec * 1000000) / 232); + hdr->seq = byteorder_htonl(dev->seq); + memset(hdr->resv, 0, sizeof(hdr->resv)); + hdr->length = payload_len; + + return sizeof(zep_v2_data_hdr_t); +} + +static inline size_t _zep_hdr_fill(socket_zep_t *dev, zep_hdr_t *hdr, + size_t payload_len) +{ + hdr->preamble[0] = 'E'; + hdr->preamble[1] = 'X'; + + /* keep possibility for ZEPv1 open */ + return _zep_hdr_fill_v2_data(dev, (zep_v2_data_hdr_t *)hdr, + payload_len); +} + +static size_t _prep_vector(socket_zep_t *dev, const struct iovec *vector, + unsigned n, struct iovec *out) +{ + size_t bytes = 0; + dev->chksum_buf = 0; + + for (unsigned i = 0; i < n; i++) { + bytes += vector[i].iov_len; + } + bytes += sizeof(uint16_t); /* FCS field */ + out[0].iov_base = &dev->snd_hdr_buf; + out[0].iov_len = _zep_hdr_fill(dev, out[0].iov_base, bytes); + for (unsigned i = 0; i < n; i++) { + /* discard const qualifier, we won't change anything. Promise! */ + out[i + 1].iov_base = vector[i].iov_base; + out[i + 1].iov_len = vector[i].iov_len; + dev->chksum_buf = ucrc16_calc_le(out[i + 1].iov_base, out[i + 1].iov_len, + UCRC16_CCITT_POLY_LE, dev->chksum_buf); + } + dev->chksum_buf = byteorder_btols(byteorder_htons(dev->chksum_buf)).u16; + out[n + 1].iov_base = &dev->chksum_buf; + out[n + 1].iov_len = sizeof(uint16_t); + return bytes; +} + +static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n) +{ + socket_zep_t *dev = (socket_zep_t *)netdev; + struct iovec v[n + 2]; + size_t bytes; + int res; + + assert((dev != NULL) && (dev->sock_fd != 0)); + bytes = _prep_vector(dev, vector, n, v); + DEBUG("socket_zep::send(%p, %p, %u)\n", (void *)netdev, (void *)vector, n); + /* simulate TX_STARTED interrupt */ + if (netdev->event_callback) { + dev->last_event = NETDEV_EVENT_TX_STARTED; + netdev->event_callback(netdev, NETDEV_EVENT_ISR); + thread_yield(); + } + res = writev(dev->sock_fd, v, n + 2); + if (res < 0) { + DEBUG("socket_zep::send: error writing packet: %s\n", strerror(errno)); + return res; + } + /* simulate TX_COMPLETE interrupt */ + if (netdev->event_callback) { + dev->last_event = NETDEV_EVENT_TX_COMPLETE; + netdev->event_callback(netdev, NETDEV_EVENT_ISR); + thread_yield(); + } +#ifdef MODULE_NETSTATS_L2 + netdev->stats.tx_bytes += bytes; +#else + (void)bytes; +#endif + + return res - v[0].iov_len - v[n + 1].iov_len; +} + +static void _continue_reading(socket_zep_t *dev) +{ + /* work around lost signals */ + fd_set rfds; + struct timeval t; + memset(&t, 0, sizeof(t)); + FD_ZERO(&rfds); + FD_SET(dev->sock_fd, &rfds); + + _native_in_syscall++; /* no switching here */ + + if (real_select(dev->sock_fd + 1, &rfds, NULL, NULL, &t) == 1) { + int sig = SIGIO; + extern int _sig_pipefd[2]; + extern ssize_t (*real_write)(int fd, const void * buf, size_t count); + real_write(_sig_pipefd[1], &sig, sizeof(int)); + _native_sigpend++; + } + else { + native_async_read_continue(dev->sock_fd); + } + + _native_in_syscall--; +} + +static inline bool _dst_not_me(socket_zep_t *dev, const void *buf) +{ + uint8_t dst_addr[IEEE802154_LONG_ADDRESS_LEN] = { 0 }; + int dst_len; + le_uint16_t dst_pan = { .u16 = 0 }; + + dst_len = ieee802154_get_dst(buf, dst_addr, + &dst_pan); + switch (dst_len) { + case IEEE802154_LONG_ADDRESS_LEN: + return memcmp(dst_addr, dev->netdev.long_addr, dst_len) != 0; + case IEEE802154_SHORT_ADDRESS_LEN: + return (memcmp(dst_addr, ieee802154_addr_bcast, dst_len) != 0) && + (memcmp(dst_addr, dev->netdev.short_addr, dst_len) != 0); + default: + return false; /* better safe than sorry ;-) */ + } +} + +static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) +{ + socket_zep_t *dev = (socket_zep_t *)netdev; + int size = 0; + + DEBUG("socket_zep::recv(%p, %p, %u, %p)\n", (void *)netdev, buf, + (unsigned)len, (void *)info); + if ((buf == NULL) || (len == 0)) { + int res = real_ioctl(dev->sock_fd, FIONREAD, &size); +#if ENABLE_DEBUG + if (res < 0) { + DEBUG("socket_zep::recv: error reading FIONREAD: %s", + strerror(errno)); + } +#else + (void)res; +#endif + return size; + } + else if (len > 0) { + size = real_read(dev->sock_fd, dev->rcv_buf, sizeof(dev->rcv_buf)); + + if (size > 0) { + zep_hdr_t *tmp = (zep_hdr_t *)&dev->rcv_buf; + + if ((tmp->preamble[0] != 'E') || (tmp->preamble[1] != 'X')) { + DEBUG("socket_zep::recv: invalid ZEP header"); + return -1; + } + switch (tmp->version) { + case 2: { + zep_v2_data_hdr_t *zep = (zep_v2_data_hdr_t *)tmp; + void *payload = &dev->rcv_buf[sizeof(zep_v2_data_hdr_t)]; + + if (zep->type != ZEP_V2_TYPE_DATA) { + DEBUG("socket_zep::recv: unexpect ZEP type\n"); + /* don't support ACK frames for now*/ + return -1; + } + if (((sizeof(zep_v2_data_hdr_t) + zep->length) != (unsigned)size) || + (zep->length > len) || (zep->chan != dev->netdev.chan) || + /* TODO promiscous mode */ + _dst_not_me(dev, payload)) { + /* TODO: check checksum */ + return -1; + } + /* don't hand FCS to stack */ + size = zep->length - sizeof(uint16_t); + if (buf != NULL) { + memcpy(buf, payload, size); + if (info != NULL) { + struct netdev_radio_rx_info *rx_info = info; + rx_info->lqi = zep->lqi_val; + rx_info->rssi = UINT8_MAX; + } + } + break; + } + default: + DEBUG("socket_zep::recv: unexpected ZEP version\n"); + return -1; + } + } + else if (size == 0) { + DEBUG("socket_zep::recv: ignoring null-event\n"); + return -1; + } + else if (size == -1) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + } + else { + err(EXIT_FAILURE, "zep: read"); + } + } + else { + errx(EXIT_FAILURE, "internal error _rx_event"); + } + } + _continue_reading(dev); +#ifdef MODULE_NETSTATS_L2 + netdev->stats.rx_count++; + netdev->stats.rx_bytes += size; +#endif + return size; +} + +static void _isr(netdev_t *netdev) +{ + if (netdev->event_callback) { + socket_zep_t *dev = (socket_zep_t *)netdev; + + DEBUG("socket_zep::isr: firing %u\n", (unsigned)dev->last_event); + netdev->event_callback(netdev, dev->last_event); + } + return; +} + +static void _socket_isr(int fd, void *arg) +{ + (void)fd; + (void)arg; + netdev_t *netdev = (netdev_t *)arg; + + DEBUG("socket_zep::_socket_isr: %d, %p (netdev == %p)\n", + fd, arg, (void *)netdev); + if (netdev == NULL) { + return; + } + if (netdev->event_callback) { + socket_zep_t *dev = (socket_zep_t *)netdev; + + dev->last_event = NETDEV_EVENT_RX_COMPLETE; + netdev->event_callback(netdev, NETDEV_EVENT_ISR); + } +} + +static int _init(netdev_t *netdev) +{ + socket_zep_t *dev = (socket_zep_t *)netdev; + + assert(dev != NULL); + dev->netdev.chan = IEEE802154_DEFAULT_CHANNEL; + dev->netdev.pan = IEEE802154_DEFAULT_PANID; +#ifdef MODULE_GNRC_SIXLOWPAN + dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN; +#elif MODULE_GNRC + dev->netdev.proto = GNRC_NETTYPE_UNDEF; +#endif + dev->seq = random_uint32(); + + return 0; +} + +static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len) +{ + socket_zep_t *dev = (socket_zep_t *)netdev; + uint16_t *v = value; + + assert((dev != NULL)); + switch (opt) { + case NETOPT_MAX_PACKET_SIZE: + assert(value != NULL); + if (max_len != sizeof(uint16_t)) { + return -EOVERFLOW; + } + *v = SOCKET_ZEP_FRAME_PAYLOAD_LEN; + return sizeof(uint16_t); + default: + return netdev_ieee802154_get(&dev->netdev, opt, value, max_len); + } +} + +static int _set(netdev_t *netdev, netopt_t opt, const void *value, + size_t value_len) +{ + assert(netdev != NULL); + return netdev_ieee802154_set((netdev_ieee802154_t *)netdev, opt, + value, value_len); +} + + +void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params) +{ + static const struct addrinfo hints = { .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM }; + struct addrinfo *ai = NULL, *remote; + int res; + + DEBUG("socket_zep_setup(%p, %p)\n", (void *)dev, (void *)params); + assert((params->local_addr != NULL) && (params->local_port != NULL) && + (params->remote_addr != NULL) && (params->remote_port != NULL)); + memset(dev, 0, sizeof(socket_zep_t)); + dev->netdev.netdev.driver = &socket_zep_driver; + /* bind and connect socket */ + if ((res = real_getaddrinfo(params->local_addr, params->local_port, &hints, + &ai)) < 0) { + errx(EXIT_FAILURE, "ZEP: unable to get local address: %s\n", + gai_strerror(res)); + } + for (struct addrinfo *local = ai; local != NULL; local = local->ai_next) { + if ((res = real_socket(local->ai_family, local->ai_socktype, + local->ai_protocol)) < 0) { + continue; + } + if (real_bind(res, local->ai_addr, local->ai_addrlen) == 0) { + break; /* successfully bound */ + } + } + real_freeaddrinfo(ai); + if (res < 0) { + err(EXIT_FAILURE, "ZEP: Unable to bind socket"); + } + dev->sock_fd = res; + ai = NULL; + if ((res = real_getaddrinfo(params->remote_addr, params->remote_port, &hints, + &ai)) < 0) { + errx(EXIT_FAILURE, "ZEP: unable to get remote address: %s\n", + gai_strerror(res)); + } + for (remote = ai; remote != NULL; remote = remote->ai_next) { + if (real_connect(dev->sock_fd, remote->ai_addr, remote->ai_addrlen) == 0) { + break; /* successfully connected */ + } + } + if (remote == NULL) { + err(EXIT_FAILURE, "ZEP: Unable to connect socket"); + } + real_freeaddrinfo(ai); + + /* generate hardware address from local address */ + uint8_t ss_array[sizeof(struct sockaddr_storage)] = { 0 }; + socklen_t ss_len = sizeof(struct sockaddr_storage); + + if (getpeername(dev->sock_fd, (struct sockaddr *)&ss_array, &ss_len) < 0) { + err(EXIT_FAILURE, "ZEP: Unable to retrieve remote address"); + } + assert(ss_len >= IEEE802154_LONG_ADDRESS_LEN); + if (getsockname(dev->sock_fd, (struct sockaddr *)&ss_array, &ss_len) < 0) { + err(EXIT_FAILURE, "ZEP: Unable to retrieve local address"); + } + assert(ss_len >= IEEE802154_LONG_ADDRESS_LEN); + + /* generate hardware address from socket address and port info */ + dev->netdev.long_addr[1] = 'Z'; /* The "OUI" */ + dev->netdev.long_addr[2] = 'E'; + dev->netdev.long_addr[3] = 'P'; + for (unsigned i = 0; i < ss_len; i++) { /* generate NIC from local source */ + unsigned addr_idx = (i % (IEEE802154_LONG_ADDRESS_LEN / 2)) + + (IEEE802154_LONG_ADDRESS_LEN / 2); + dev->netdev.long_addr[addr_idx] ^= ss_array[i]; + } + dev->netdev.short_addr[0] = dev->netdev.long_addr[6]; + dev->netdev.short_addr[1] = dev->netdev.long_addr[7]; + native_async_read_setup(); + native_async_read_add_handler(dev->sock_fd, dev, _socket_isr); +#ifdef MODULE_NETSTATS_L2 + memset(&dev->netdev.netdev.stats, 0, sizeof(netstats_t)); +#endif +} + +void socket_zep_cleanup(socket_zep_t *dev) +{ + assert(dev != NULL); + /* cleanup signal handling */ + native_async_read_cleanup(); + /* close the socket */ + close(dev->sock_fd); + dev->sock_fd = 0; +} + +/** @} */ diff --git a/cpu/native/startup.c b/cpu/native/startup.c index 35997b9d55..2f0b0173ae 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -75,12 +75,21 @@ netdev_tap_params_t netdev_tap_params[NETDEV_TAP_MAX]; #include "candev_linux.h" #endif +#ifdef MODULE_SOCKET_ZEP +#include "socket_zep_params.h" + +socket_zep_params_t socket_zep_params[SOCKET_ZEP_MAX]; +#endif + static const char short_opts[] = ":hi:s:deEoc:" #ifdef MODULE_MTD_NATIVE "m:" #endif #ifdef MODULE_CAN_LINUX "n:" +#endif +#ifdef MODULE_SOCKET_ZEP + "z:" #endif ""; @@ -98,6 +107,9 @@ static const struct option long_opts[] = { #endif #ifdef MODULE_CAN_LINUX { "can", required_argument, NULL, 'n' }, +#endif +#ifdef MODULE_SOCKET_ZEP + { "zep", required_argument, NULL, 'z' }, #endif { NULL, 0, NULL, '\0' }, }; @@ -228,8 +240,15 @@ void usage_exit(int status) real_printf(" ", i + 1); } #endif - real_printf(" [-i ] [-d] [-e|-E] [-o] [-c ]\n"); +#if defined(MODULE_SOCKET_ZEP) && (SOCKET_ZEP_MAX > 0) + real_printf(" -z [[:,]:]\n"); + for (int i = 0; i < SOCKET_ZEP_MAX - 1; i++) { + /* for further interfaces the local address must be different so we omit + * the braces (marking them as optional) to be 100% clear on that */ + real_printf(" -z :,:\n"); + } +#endif real_printf(" help: %s -h\n\n", _progname); @@ -253,7 +272,14 @@ void usage_exit(int status) " to socket\n" " -c , --uart-tty=\n" " specify TTY device for UART. This argument can be used multiple\n" -" times (up to UART_NUMOF)\n"); +" times (up to UART_NUMOF)\n" +#if defined(MODULE_SOCKET_ZEP) && (SOCKET_ZEP_MAX > 0) +" -z [:,]: --zep=[:,]:\n" +" provide a ZEP interface with local address and port (, )\n" +" and remote address and port (default local: [::]:17754).\n" +" Required to be provided SOCKET_ZEP_MAX times\n" +#endif + ); #ifdef MODULE_MTD_NATIVE real_printf( " -m , --mtd=\n" @@ -268,6 +294,65 @@ void usage_exit(int status) real_exit(status); } +#ifdef MODULE_SOCKET_ZEP +static void _parse_ep_str(char *ep_str, char **addr, char **port) +{ + /* read endpoint string in reverse, the last chars are the port and decimal + * numbers, then a colon, then the address (potentially containing colons, + * that's why we read in reverse) */ + for (int i = strlen(ep_str) - 1; (i >= 0) && (*port == NULL); i--) { + if (((ep_str[i] < '0') || (ep_str[i] > '9')) && (ep_str[i] != ':')) { + usage_exit(EXIT_FAILURE); + } + if ((ep_str[i] == ':') && (i >= (int)sizeof("[]"))) { + /* found port delimiter, but we need to make sure it isn't delivered + * like :. Two characters for either hostname or IP address + * seems reasonable especially considering, that we need to + * remove the [] around IPv6 addresses */ + *port = &ep_str[i + 1]; + if ((ep_str[0] == '[') && (ep_str[i - 1] == ']')) { + /* addr is in the format [], strip [] */ + *addr = &ep_str[1]; + ep_str[i - 1] = '\0'; + } + else if ((ep_str[0] == '[') || (ep_str[i - 1] == ']')) { + /* unbalanced brackets */ + usage_exit(EXIT_FAILURE); + } + else { + *addr = ep_str; + } + ep_str[i] = '\0'; + } + } + if (*port == NULL) { + usage_exit(EXIT_FAILURE); + } +} + +static void _zep_params_setup(char *zep_str, int zep) +{ + char *save_ptr, *first_ep, *second_ep; + + if ((first_ep = strtok_r(zep_str, ",", &save_ptr)) == NULL) { + usage_exit(EXIT_FAILURE); + } + second_ep = strtok_r(NULL, ",", &save_ptr); + if (second_ep == NULL) { + socket_zep_params[zep].local_addr = SOCKET_ZEP_LOCAL_ADDR_DEFAULT; + socket_zep_params[zep].local_port = SOCKET_ZEP_PORT_DEFAULT; + _parse_ep_str(first_ep, &socket_zep_params[zep].remote_addr, + &socket_zep_params[zep].remote_port); + } + else { + _parse_ep_str(first_ep, &socket_zep_params[zep].local_addr, + &socket_zep_params[zep].local_port); + _parse_ep_str(second_ep, &socket_zep_params[zep].remote_addr, + &socket_zep_params[zep].remote_port); + } +} +#endif + /** @brief Initialization function pointer type */ typedef void (*init_func_t)(int argc, char **argv, char **envp); #ifdef __APPLE__ @@ -295,6 +380,9 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e _native_id = _native_pid; int c, opt_idx = 0, uart = 0; +#ifdef MODULE_SOCKET_ZEP + unsigned zeps = 0; +#endif bool dmn = false, force_stderr = false; _stdiotype_t stderrtype = _STDIOTYPE_STDIO; _stdiotype_t stdouttype = _STDIOTYPE_STDIO; @@ -360,6 +448,11 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e CAN_MAX_SIZE_INTERFACE_NAME); } break; +#endif +#ifdef MODULE_SOCKET_ZEP + case 'z': + _zep_params_setup(optarg, zeps++); + break; #endif default: usage_exit(EXIT_FAILURE); @@ -374,6 +467,12 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e } } #endif +#ifdef MODULE_SOCKET_ZEP + if (zeps != SOCKET_ZEP_MAX) { + /* not enough ZEPs given */ + usage_exit(EXIT_FAILURE); + } +#endif if (dmn) { filter_daemonize_argv(_native_argv); diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c index c4417153c1..765044d9f1 100644 --- a/cpu/native/syscalls.c +++ b/cpu/native/syscalls.c @@ -62,9 +62,11 @@ void (*real_freeifaddrs)(struct ifaddrs *ifa); void (*real_srandom)(unsigned int seed); int (*real_accept)(int socket, ...); int (*real_bind)(int socket, ...); +int (*real_connect)(int socket, ...); int (*real_printf)(const char *format, ...); int (*real_getaddrinfo)(const char *node, ...); int (*real_getifaddrs)(struct ifaddrs **ifap); +int (*real_gettimeofday)(struct timeval *t, ...); int (*real_getpid)(void); int (*real_chdir)(const char *path); int (*real_close)(int); @@ -447,11 +449,13 @@ void _native_init_syscalls(void) *(void **)(&real_srandom) = dlsym(RTLD_NEXT, "srandom"); *(void **)(&real_accept) = dlsym(RTLD_NEXT, "accept"); *(void **)(&real_bind) = dlsym(RTLD_NEXT, "bind"); + *(void **)(&real_connect) = dlsym(RTLD_NEXT, "connect"); *(void **)(&real_printf) = dlsym(RTLD_NEXT, "printf"); *(void **)(&real_gai_strerror) = dlsym(RTLD_NEXT, "gai_strerror"); *(void **)(&real_getaddrinfo) = dlsym(RTLD_NEXT, "getaddrinfo"); *(void **)(&real_getifaddrs) = dlsym(RTLD_NEXT, "getifaddrs"); *(void **)(&real_getpid) = dlsym(RTLD_NEXT, "getpid"); + *(void **)(&real_gettimeofday) = dlsym(RTLD_NEXT, "gettimeofday"); *(void **)(&real_pipe) = dlsym(RTLD_NEXT, "pipe"); *(void **)(&real_chdir) = dlsym(RTLD_NEXT, "chdir"); *(void **)(&real_close) = dlsym(RTLD_NEXT, "close"); diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index aa3768f04f..76248d0e40 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -215,6 +215,11 @@ void auto_init(void) auto_init_netdev_tap(); #endif +#ifdef MODULE_SOCKET_ZEP + extern void auto_init_socket_zep(void); + auto_init_socket_zep(); +#endif + #ifdef MODULE_NORDIC_SOFTDEVICE_BLE extern void gnrc_nordic_ble_6lowpan_init(void); gnrc_nordic_ble_6lowpan_init(); diff --git a/sys/auto_init/netif/auto_init_socket_zep.c b/sys/auto_init/netif/auto_init_socket_zep.c new file mode 100644 index 0000000000..b80457798c --- /dev/null +++ b/sys/auto_init/netif/auto_init_socket_zep.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @ingroup auto_init_gnrc_netif + * @{ + * + * @file + * @brief Auto initialization for @ref netdev_socket_zep devices + * + * @author Martine Lenders + */ + +#ifdef MODULE_SOCKET_ZEP + +#include "log.h" +#include "socket_zep.h" +#include "socket_zep_params.h" +#include "net/gnrc/netif/ieee802154.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Define stack parameters for the MAC layer thread + */ +#define SOCKET_ZEP_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) +#ifndef SOCKET_ZEP_MAC_PRIO +#define SOCKET_ZEP_MAC_PRIO (GNRC_NETIF_PRIO) +#endif + +/** + * @brief Stacks for the MAC layer threads + */ +static char _socket_zep_stacks[SOCKET_ZEP_MAX][SOCKET_ZEP_MAC_STACKSIZE]; +static socket_zep_t _socket_zeps[SOCKET_ZEP_MAX]; + +void auto_init_socket_zep(void) +{ + for (int i = 0; i < SOCKET_ZEP_MAX; i++) { + LOG_DEBUG("[auto_init_netif: initializing socket ZEP device #%u\n", i); + /* setup netdev device */ + socket_zep_setup(&_socket_zeps[i], &socket_zep_params[i]); + gnrc_netif_ieee802154_create(_socket_zep_stacks[i], + SOCKET_ZEP_MAC_STACKSIZE, + SOCKET_ZEP_MAC_PRIO, "socket_zep", + (netdev_t *)&_socket_zeps[i]); + } +} + +#else +typedef int dont_be_pedantic; +#endif /* MODULE_SOCKET_ZEP */ +/** @} */ diff --git a/sys/include/net/zep.h b/sys/include/net/zep.h new file mode 100644 index 0000000000..80a317a40e --- /dev/null +++ b/sys/include/net/zep.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_zep ZEP header definitions + * @ingroup net + * @{ + * + * @file + * @brief + * + * @author Martine Lenders + */ +#ifndef NET_ZEP_H +#define NET_ZEP_H + +#include + +#include "byteorder.h" +#include "net/ntp_packet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZEP_PORT_DEFAULT (17754) /**< default ZEP port */ + +/** + * @brief Type == Data for ZEPv2 header + */ +#define ZEP_V2_TYPE_DATA (1) + +/** + * @brief Type == Ack for ZEPv2 header + */ +#define ZEP_V2_TYPE_ACK (2) + +/** + * @brief Mask for length field + */ +#define ZEP_LENGTH_MASK (0x7f) + +/** + * @brief ZEP header definition + */ +typedef struct __attribute__((packed)) { + char preamble[2]; /**< Preamble code (must be "EX") */ + uint8_t version; /**< Protocol Version (must be 1 or 2) */ +} zep_hdr_t; + +/** + * @brief ZEPv1 header definition + * @extends zep_hdr_t + */ +typedef struct __attribute__((packed)) { + zep_hdr_t hdr; /**< common header fields */ + uint8_t chan; /**< channel ID */ + network_uint16_t dev; /**< device ID */ + uint8_t lqi_mode; /**< CRC/LQI Mode (0: append LQI to frame, 1: append FCS) */ + uint8_t lqi_val; /**< LQI value */ + uint8_t resv[7]; /**< reserved field, must always be 0 */ + uint8_t length; /**< length of the frame */ +} zep_v1_hdr_t; + +/** + * @brief ZEPv2 header definition (type == Data) + * @extends zep_hdr_t + */ +typedef struct __attribute__((packed)) { + zep_hdr_t hdr; /**< common header fields */ + uint8_t type; /**< type (must be @ref ZEP_V2_TYPE_DATA) */ + uint8_t chan; /**< channel ID */ + network_uint16_t dev; /**< device ID */ + uint8_t lqi_mode; /**< CRC/LQI Mode */ + uint8_t lqi_val; /**< LQI value */ + ntp_timestamp_t time; /**< NTP timestamp */ + network_uint32_t seq; /**< Sequence number */ + uint8_t resv[10]; /**< reserved field, must always be 0 */ + uint8_t length; /**< length of the frame */ +} zep_v2_data_hdr_t; + +/** + * @brief ZEPv2 header definition (type == Ack) + * @extends zep_hdr_t + */ +typedef struct __attribute__((packed)) { + zep_hdr_t hdr; /**< common header fields */ + uint8_t type; /**< type (must be @ref ZEP_V2_TYPE_ACK) */ + network_uint32_t seq; /**< Sequence number */ +} zep_v2_ack_hdr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* NET_ZEP_H */ +/** @} */