mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
native: provide socket-based ZEP device
This commit is contained in:
parent
2b23697ca3
commit
81ef15287a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, ...);
|
||||
|
84
cpu/native/include/socket_zep.h
Normal file
84
cpu/native/include/socket_zep.h
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef SOCKET_ZEP_H
|
||||
#define SOCKET_ZEP_H
|
||||
|
||||
#include <netdb.h>
|
||||
#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 */
|
||||
/** @} */
|
54
cpu/native/include/socket_zep_params.h
Normal file
54
cpu/native/include/socket_zep_params.h
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#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 */
|
||||
/** @} */
|
3
cpu/native/socket_zep/Makefile
Normal file
3
cpu/native/socket_zep/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
||||
INCLUDES = $(NATIVEINCLUDES)
|
443
cpu/native/socket_zep/socket_zep.c
Normal file
443
cpu/native/socket_zep/socket_zep.c
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/** @} */
|
@ -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(" <tap interface %d>", i + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
real_printf(" [-i <id>] [-d] [-e|-E] [-o] [-c <tty>]\n");
|
||||
#if defined(MODULE_SOCKET_ZEP) && (SOCKET_ZEP_MAX > 0)
|
||||
real_printf(" -z [[<laddr>:<lport>,]<raddr>:<rport>]\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 <laddr>:<lport>,<raddr>:<rport>\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
real_printf(" help: %s -h\n\n", _progname);
|
||||
|
||||
@ -253,7 +272,14 @@ void usage_exit(int status)
|
||||
" to socket\n"
|
||||
" -c <tty>, --uart-tty=<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 [<laddr>:<lport>,]<raddr>:<rport> --zep=[<laddr>:<lport>,]<raddr>:<rport>\n"
|
||||
" provide a ZEP interface with local address and port (<laddr>, <lport>)\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>, --mtd=<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 :<port>. 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 [<addr>], 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);
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
60
sys/auto_init/netif/auto_init_socket_zep.c
Normal file
60
sys/auto_init/netif/auto_init_socket_zep.c
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#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 */
|
||||
/** @} */
|
102
sys/include/net/zep.h
Normal file
102
sys/include/net/zep.h
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef NET_ZEP_H
|
||||
#define NET_ZEP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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 */
|
||||
/** @} */
|
Loading…
Reference in New Issue
Block a user