
230 changed files with 11 additions and 45817 deletions
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* nativenet transceiver interface |
||||
* |
||||
* A configurable transceiver for the native port. |
||||
* |
||||
* At the moment only the tap interface is supported, but more network |
||||
* layers are intended. So the "configurable" part is a lie for now ;-) |
||||
* The effect of calls like nativenet_set_channel depend on the |
||||
* network layer. |
||||
* |
||||
* Copyright (C) 2013, 2014 Ludwig Ortmann <ludwig.ortmann@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 native_net Native network interface |
||||
* @ingroup native_cpu |
||||
* @{ |
||||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef NATIVENET_H |
||||
#define NATIVENET_H |
||||
|
||||
#if defined(__FreeBSD__) |
||||
#include <sys/types.h> |
||||
#endif |
||||
|
||||
#include <net/ethernet.h> |
||||
|
||||
#include "radio/types.h" |
||||
#include "kernel_types.h" |
||||
#include "netdev/base.h" |
||||
|
||||
#ifndef RX_BUF_SIZE |
||||
#define RX_BUF_SIZE (10) |
||||
#endif |
||||
#ifndef TRANSCEIVER_BUFFER_SIZE |
||||
#define TRANSCEIVER_BUFFER_SIZE (10) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Number of registrable netdev_rcv_data_cb_t callbacks per nativenet |
||||
* device |
||||
*/ |
||||
#define NATIVENET_DEV_CB_MAX (128) |
||||
|
||||
/**
|
||||
* @brief Broadcast address |
||||
*/ |
||||
#define NATIVE_BROADCAST_ADDRESS (0) |
||||
|
||||
#ifndef NATIVE_MAX_DATA_LENGTH |
||||
#include "tap.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifdef MODULE_SIXLOWPAN |
||||
#define NATIVE_MAX_DATA_LENGTH (127) |
||||
#else |
||||
#define NATIVE_MAX_DATA_LENGTH (TAP_MAX_DATA) |
||||
#endif |
||||
#else |
||||
#warning be careful not to exceed (TAP_MAX_DATA) with NATIVE_MAX_DATA_LENGTH |
||||
#endif /* NATIVE_MAX_DATA_LENGTH */ |
||||
|
||||
/**
|
||||
* @brief Implementation of netdev_driver_t for nativenet |
||||
*/ |
||||
extern const netdev_driver_t nativenet_driver; |
||||
|
||||
/**
|
||||
* @brief Default @ref netdev API device |
||||
*/ |
||||
extern netdev_t nativenet_default_dev; |
||||
|
||||
/**
|
||||
* Initialize @ref sys_transceiver and @ref nativenet_default_dev |
||||
* |
||||
* @param transceiver_pid the pid of the transceiver thread |
||||
*/ |
||||
void nativenet_init(kernel_pid_t transceiver_pid); |
||||
|
||||
/**
|
||||
* Shutdown transceiver |
||||
*/ |
||||
void nativenet_powerdown(void); |
||||
|
||||
/**
|
||||
* Enable/disable monitor mode |
||||
* |
||||
* @param mode 0 off, 1 on |
||||
*/ |
||||
void nativenet_set_monitor(uint8_t mode); |
||||
|
||||
/**
|
||||
* Send a packet |
||||
* |
||||
* @param packet a radio packet |
||||
* @return -1 if the operation failed, the number of transmitted bytes |
||||
* up to INT8_MAX otherwise |
||||
*/ |
||||
int8_t nativenet_send(radio_packet_t *packet); |
||||
|
||||
/**
|
||||
* Set transceiver address |
||||
* |
||||
* @param address the address |
||||
* @return the address |
||||
*/ |
||||
radio_address_t nativenet_set_address(radio_address_t address); |
||||
|
||||
/**
|
||||
* Get transceiver address |
||||
* |
||||
* @return the address |
||||
*/ |
||||
radio_address_t nativenet_get_address(void); |
||||
|
||||
/**
|
||||
* @brief Sets the IEEE long address of the nativenet transceiver. |
||||
* |
||||
* @param[in] addr The desired address. |
||||
* |
||||
* @return The set address after calling. |
||||
*/ |
||||
uint64_t nativenet_set_address_long(uint64_t addr); |
||||
|
||||
/**
|
||||
* @brief Gets the current IEEE long address of the nativenet |
||||
* transceiver. |
||||
* |
||||
* @return The current IEEE long address. |
||||
*/ |
||||
uint64_t nativenet_get_address_long(void); |
||||
|
||||
/**
|
||||
* Set transceiver channel |
||||
* |
||||
* @param channel the channel |
||||
* @return the channel |
||||
*/ |
||||
int16_t nativenet_set_channel(uint8_t channel); |
||||
|
||||
/**
|
||||
* Get transceiver channel |
||||
* |
||||
* @return the channel |
||||
*/ |
||||
int16_t nativenet_get_channel(void); |
||||
|
||||
/**
|
||||
* Set transceiver pan |
||||
* |
||||
* @param pan the pan |
||||
* @return the pan |
||||
*/ |
||||
uint16_t nativenet_set_pan(uint16_t pan); |
||||
|
||||
/**
|
||||
* Get transceiver pan |
||||
* |
||||
* @return the pan |
||||
*/ |
||||
uint16_t nativenet_get_pan(void); |
||||
|
||||
/**
|
||||
* Enable transceiver rx mode |
||||
*/ |
||||
void nativenet_switch_to_rx(void); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
/** @} */ |
||||
#endif /* NATIVENET_H */ |
@ -1,109 +0,0 @@
|
||||
/**
|
||||
* internal nativenet transceiver interface |
||||
* |
||||
* Copyright (C) 2013 Ludwig Ortmann <ludwig.ortmann@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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @{ |
||||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#ifndef NATIVENET_INTERNAL_H |
||||
#define NATIVENET_INTERNAL_H |
||||
|
||||
#include "tap.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#define NNEV_PWRDWN 0x01 |
||||
#define NNEV_PWRUP 0x02 |
||||
#define NNEV_MONITOR 0x03 |
||||
#define NNEV_GETCHAN 0x04 |
||||
#define NNEV_SETCHAN 0x05 |
||||
#define NNEV_GETADDR 0x06 |
||||
#define NNEV_SETADDR 0x07 |
||||
#define NNEV_GETPAN 0x08 |
||||
#define NNEV_SETPAN 0x09 |
||||
#define NNEV_SEND 0x0a |
||||
#define NNEV_SWTRX 0x0b |
||||
#define NNEV_MAXEV 0x0b |
||||
|
||||
#define _NATIVENET_DEV_MORE(dev) ((_nativenet_netdev_more_t *)dev->more) |
||||
|
||||
struct rx_buffer_s { |
||||
radio_packet_t packet; |
||||
char data[NATIVE_MAX_DATA_LENGTH]; |
||||
}; |
||||
|
||||
extern struct rx_buffer_s _nativenet_rx_buffer[RX_BUF_SIZE]; |
||||
|
||||
/**
|
||||
* @brief Definition of network device data. |
||||
*/ |
||||
typedef struct { |
||||
/**
|
||||
* @brief The channel assigned to this device |
||||
* |
||||
* @note For internal use only, do not change externally! |
||||
* |
||||
* @internal |
||||
*/ |
||||
uint8_t _channel; |
||||
|
||||
/**
|
||||
* @brief The PAN ID assigned to this device |
||||
* |
||||
* @note For internal use only, do not change externally! |
||||
* @internal |
||||
*/ |
||||
uint16_t _pan_id; |
||||
|
||||
/**
|
||||
* @brief The short address assigned to this device |
||||
* |
||||
* @note For internal use only, do not change externally! |
||||
* @internal |
||||
*/ |
||||
radio_address_t _radio_addr; |
||||
|
||||
/**
|
||||
* @brief The long address assigned to this device |
||||
* |
||||
* @note For internal use only, do not change externally! |
||||
* @internal |
||||
*/ |
||||
uint64_t _long_addr; |
||||
|
||||
/**
|
||||
* @brief Flag to determine if device is in promiscuous mode |
||||
* |
||||
* @note For internal use only, do not change externally! |
||||
* @internal |
||||
*/ |
||||
uint8_t _is_monitoring; |
||||
|
||||
/**
|
||||
* @brief Receive data callbacks for this device |
||||
*/ |
||||
netdev_rcv_data_cb_t _callbacks[NATIVENET_DEV_CB_MAX]; |
||||
} _nativenet_netdev_more_t; |
||||
|
||||
/* internal counterpart to nativenet_default_dev */ |
||||
extern _nativenet_netdev_more_t _nativenet_default_dev_more; |
||||
|
||||
void _nativenet_handle_packet(radio_packet_t *packet); |
||||
int8_t send_buf(radio_packet_t *packet); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NATIVENET_INTERNAL_H */ |
@ -1,70 +0,0 @@
|
||||
/**
|
||||
* internal nativenet tap network layer interface |
||||
* |
||||
* Copyright (C) 2013 Ludwig Ortmann <ludwig.ortmann@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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @{ |
||||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
#ifndef _TAP_H |
||||
#define _TAP_H |
||||
|
||||
#include <net/ethernet.h> |
||||
|
||||
#include "board.h" |
||||
#include "radio/types.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* create and/or open tap device "name" |
||||
* |
||||
* if "name" is an empty string, the kernel chooses a name |
||||
* if "name" is an existing device, that device is used |
||||
* otherwise a device named "name" is created |
||||
* |
||||
* On OSX a name has to be provided. |
||||
*/ |
||||
int tap_init(char *name); |
||||
|
||||
/**
|
||||
* Close tap device |
||||
*/ |
||||
void tap_cleanup(void); |
||||
|
||||
extern unsigned char _native_tap_mac[ETHER_ADDR_LEN]; |
||||
|
||||
struct nativenet_header { |
||||
radio_packet_length_t length; |
||||
radio_address_t dst; |
||||
radio_address_t src; |
||||
} __attribute__((packed)); |
||||
#define TAP_MAX_DATA ((ETHERMTU) - 6) /* XXX: this is suboptimal */ |
||||
|
||||
struct nativenet_packet { |
||||
struct nativenet_header nn_header; |
||||
uint8_t data[ETHERMTU - sizeof(struct nativenet_header)]; |
||||
} __attribute__((packed)); |
||||
|
||||
union eth_frame { |
||||
struct { |
||||
struct ether_header header; |
||||
struct nativenet_packet payload; |
||||
} field; |
||||
unsigned char buffer[ETHER_MAX_LEN]; |
||||
} __attribute__((packed)); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _TAP_H */ |
@ -1,5 +0,0 @@
|
||||
MODULE = nativenet
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
||||
|
||||
INCLUDES = $(NATIVEINCLUDES)
|
@ -1,618 +0,0 @@
|
||||
/**
|
||||
* nativenet.h implementation |
||||
* |
||||
* Copyright (C) 2013 Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
* |
||||
* @ingroup native_cpu |
||||
* @ingroup net |
||||
* @{ |
||||
* @file |
||||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <err.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include <arpa/inet.h> |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
#include "transceiver.h" |
||||
#include "msg.h" |
||||
|
||||
#include "native_internal.h" |
||||
#include "tap.h" |
||||
#include "nativenet.h" |
||||
#include "nativenet_internal.h" |
||||
#include "cpu.h" |
||||
|
||||
static _native_callback_t _nativenet_callbacks[255]; |
||||
|
||||
struct rx_buffer_s _nativenet_rx_buffer[RX_BUF_SIZE]; |
||||
static volatile uint8_t rx_buffer_next; |
||||
|
||||
static kernel_pid_t _native_net_tpid = KERNEL_PID_UNDEF; |
||||
|
||||
/************************************************************************/ |
||||
/* nativenet.h **********************************************************/ |
||||
/************************************************************************/ |
||||
|
||||
int _nativenet_init(netdev_t *dev) |
||||
{ |
||||
if ((dev->type != NETDEV_TYPE_BASE) || (dev->more == NULL)) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
_NATIVENET_DEV_MORE(dev)->_channel = 0; |
||||
_NATIVENET_DEV_MORE(dev)->_pan_id = 0; |
||||
_NATIVENET_DEV_MORE(dev)->_is_monitoring = 0; |
||||
memset(_NATIVENET_DEV_MORE(dev)->_callbacks, 0, |
||||
sizeof((_NATIVENET_DEV_MORE(dev)->_callbacks))); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void nativenet_init(kernel_pid_t transceiver_pid) |
||||
{ |
||||
DEBUG("nativenet_init(transceiver_pid=%" PRIkernel_pid ")\n", transceiver_pid); |
||||
rx_buffer_next = 0; |
||||
_nativenet_init((netdev_t *)(&nativenet_default_dev)); |
||||
_native_net_tpid = transceiver_pid; |
||||
} |
||||
|
||||
void nativenet_powerdown(void) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
void nativenet_set_monitor(uint8_t mode) |
||||
{ |
||||
DEBUG("nativenet_set_monitor(mode=%d)\n", mode); |
||||
_nativenet_default_dev_more._is_monitoring = mode; |
||||
} |
||||
|
||||
int16_t nativenet_set_channel(uint8_t channel) |
||||
{ |
||||
_nativenet_default_dev_more._channel = channel; |
||||
return _nativenet_default_dev_more._channel; |
||||
} |
||||
|
||||
int16_t nativenet_get_channel(void) |
||||
{ |
||||
return _nativenet_default_dev_more._channel; |
||||
} |
||||
|
||||
uint16_t nativenet_set_pan(uint16_t pan) |
||||
{ |
||||
_nativenet_default_dev_more._pan_id = pan; |
||||
return _nativenet_default_dev_more._pan_id; |
||||
} |
||||
|
||||
uint16_t nativenet_get_pan(void) |
||||
{ |
||||
return _nativenet_default_dev_more._pan_id; |
||||
} |
||||
|
||||
radio_address_t nativenet_set_address(radio_address_t address) |
||||
{ |
||||
DEBUG("nativenet_set_address(address=%d)\n", address); |
||||
_nativenet_default_dev_more._radio_addr = address; |
||||
return _nativenet_default_dev_more._radio_addr; |
||||
} |
||||
|
||||
radio_address_t nativenet_get_address(void) |
||||
{ |
||||
DEBUG("nativenet_get_address -> address = %d\n", |
||||
_nativenet_default_dev_more._radio_addr); |
||||
return _nativenet_default_dev_more._radio_addr; |
||||
} |
||||
|
||||
uint64_t nativenet_get_address_long(void) |
||||
{ |
||||
DEBUG("nativenet_get_address_long -> address = %" PRIx64 "\n", |
||||
_nativenet_default_dev_more._long_addr); |
||||
return _nativenet_default_dev_more._long_addr; |
||||
} |
||||
|
||||
uint64_t nativenet_set_address_long(uint64_t address) |
||||
{ |
||||
DEBUG("nativenet_set_address_long(address=%" PRIx64 ")\n", address); |
||||
warnx("nativenet_set_address_long: this does not actually change the interfaces address"); |
||||
_nativenet_default_dev_more._long_addr = address; |
||||
return _nativenet_default_dev_more._long_addr; |
||||
} |
||||
|
||||
int8_t nativenet_send(radio_packet_t *packet) |
||||
{ |
||||
packet->src = _nativenet_default_dev_more._radio_addr; |
||||
DEBUG("nativenet_send: Sending packet of length %" PRIu16 " from %" PRIu16 " to %" PRIu16 "\n", |
||||
packet->length, packet->src, packet->dst); |
||||
|
||||
return send_buf(packet); |
||||
} |
||||
|
||||
void nativenet_switch_to_rx(void) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
/************************************************************************/ |
||||
/* nativenet_internal.h *************************************************/ |
||||
/************************************************************************/ |
||||
|
||||
int _nativenet_register_cb(int event, _native_callback_t func) |
||||
{ |
||||
if (event > NNEV_MAXEV) { |
||||
DEBUG("_nativenet_register_cb: event > NNEV_MAXEV\n"); |
||||
return -1; |
||||
} |
||||
|
||||
_nativenet_callbacks[event] = func; |
||||
return 0; |
||||
} |
||||
|
||||
int _nativenet_unregister_cb(int event) |
||||
{ |
||||
if (event > NNEV_MAXEV) { |
||||
DEBUG("_nativenet_unregister_cb: event > NNEV_MAXEV\n"); |
||||
return -1; |
||||
} |
||||
|
||||
_nativenet_callbacks[event] = NULL; |
||||
return 0; |
||||
} |
||||
|
||||
void do_cb(int event) |
||||
{ |
||||
if (event > NNEV_MAXEV) { |
||||
DEBUG("do_cb: event > NNEV_MAXEV\n"); |
||||
return; |
||||
} |
||||
|
||||
if (_nativenet_callbacks[event] != NULL) { |
||||
_nativenet_callbacks[event](); |
||||
} |
||||
} |
||||
|
||||
void _nativenet_handle_packet(radio_packet_t *packet) |
||||
{ |
||||
radio_address_t dst_addr = packet->dst; |
||||
int notified = 0; |
||||
|
||||
/* TODO: find way to demultiplex reception from several taps and map them
|
||||
* to devices. */ |
||||
netdev_t *dev = &nativenet_default_dev; |
||||
|
||||
/* address filter / monitor mode */ |
||||
if (_nativenet_default_dev_more._is_monitoring == 1) { |
||||
DEBUG("_nativenet_handle_packet: monitoring, not filtering address \n"); |
||||
} |
||||
else { |
||||
/* own addr check */ |
||||
if (dst_addr == _nativenet_default_dev_more._radio_addr) { |
||||
DEBUG("_nativenet_handle_packet: accept packet, addressed to us\n"); |
||||
} |
||||
else if (dst_addr == NATIVE_BROADCAST_ADDRESS) { |
||||
DEBUG("_nativenet_handle_packet: accept packet, broadcast\n"); |
||||
} |
||||
else { |
||||
DEBUG("_nativenet_handle_packet: discard packet addressed to someone else\n"); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/* copy packet to rx buffer */ |
||||
DEBUG("\n\t\trx_buffer_next: %i\n\n", rx_buffer_next); |
||||
memcpy(&_nativenet_rx_buffer[rx_buffer_next].data, packet->data, packet->length); |
||||
memcpy(&_nativenet_rx_buffer[rx_buffer_next].packet, packet, sizeof(radio_packet_t)); |
||||
_nativenet_rx_buffer[rx_buffer_next].packet.data = (uint8_t *) |
||||
&_nativenet_rx_buffer[rx_buffer_next].data; |
||||
|
||||
/* notify transceiver thread if any */ |
||||
if (_native_net_tpid != KERNEL_PID_UNDEF) { |
||||
DEBUG("_nativenet_handle_packet: notifying transceiver thread!\n"); |
||||
msg_t m; |
||||
m.type = (uint16_t) RCV_PKT_NATIVE; |
||||
m.content.value = rx_buffer_next; |
||||
msg_send_int(&m, _native_net_tpid); |
||||
notified = 1; |
||||
} |
||||
|
||||
for (int i = 0; i < NATIVENET_DEV_CB_MAX; i++) { |
||||
if (_NATIVENET_DEV_MORE(dev)->_callbacks[i]) { |
||||
_NATIVENET_DEV_MORE(dev)->_callbacks[i]((netdev_t *)dev, |
||||
&(_nativenet_rx_buffer[rx_buffer_next].packet.src), |
||||
sizeof(uint16_t), |
||||
&(_nativenet_rx_buffer[rx_buffer_next].packet.dst), |
||||
sizeof(uint16_t), |
||||
&(_nativenet_rx_buffer[rx_buffer_next].data), |
||||
(size_t)_nativenet_rx_buffer[rx_buffer_next].packet.length); |
||||
notified = 1; |
||||
} |
||||
} |
||||
|
||||
if (!notified) { |
||||
DEBUG("_nativenet_handle_packet: no one to notify =(\n"); |
||||
} |
||||
|
||||
/* shift to next buffer element */ |
||||
if (++rx_buffer_next == RX_BUF_SIZE) { |
||||
rx_buffer_next = 0; |
||||
} |
||||
} |
||||
|
||||
/***************************************************************
|
||||
* netdev_base wrapper |
||||
***************************************************************/ |
||||
|
||||
#ifdef MODULE_NETDEV_BASE |
||||
int _nativenet_send_data(netdev_t *dev, void *dest, size_t dest_len, |
||||
netdev_hlist_t *upper_layer_hdrs, void *data, |
||||
size_t data_len) |
||||
{ |
||||
netdev_hlist_t *ptr = upper_layer_hdrs; |
||||
uint8_t tx_buffer[data_len + netdev_get_hlist_len(upper_layer_hdrs)]; |
||||
size_t tx_ptr = 0; |
||||
radio_packet_t pkt = {0, 0, 0, 0, 0, {0, 0}, sizeof(tx_buffer), tx_buffer}; |
||||
|
||||
if (dev->type != NETDEV_TYPE_BASE) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
if (dest_len > sizeof(uint16_t)) { |
||||
return -EAFNOSUPPORT; |
||||
} |
||||
|
||||
if (sizeof(tx_buffer) > NATIVE_MAX_DATA_LENGTH) { |
||||
return -EMSGSIZE; |
||||
} |
||||
|
||||
if (upper_layer_hdrs) { |
||||
do { |
||||
memcpy(&(tx_buffer[tx_ptr]), ptr->header, ptr->header_len); |
||||
tx_ptr += ptr->header_len; |
||||
netdev_hlist_advance(&ptr); |
||||
} while (ptr != upper_layer_hdrs); |
||||
} |
||||
|
||||
memcpy(&(tx_buffer[tx_ptr]), data, data_len); |
||||
|
||||
if (dest_len == sizeof(uint16_t)) { |
||||
pkt.dst = *((uint16_t *)dest); |
||||
} |
||||
else { |
||||
pkt.dst = (uint16_t)(*((uint8_t *)dest)); |
||||
} |
||||
|
||||
return nativenet_send(&pkt); |
||||
} |
||||
|
||||
int _nativenet_add_rcv_data_cb(netdev_t *dev, netdev_rcv_data_cb_t cb) |
||||
{ |
||||
int i = 0; |
||||
|
||||
if (dev->type != NETDEV_TYPE_BASE) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
for (i = 0; i < NATIVENET_DEV_CB_MAX; i++) { |
||||
if (_NATIVENET_DEV_MORE(dev)->_callbacks[i] == NULL || |
||||
_NATIVENET_DEV_MORE(dev)->_callbacks[i] == cb) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (i >= NATIVENET_DEV_CB_MAX) { |
||||
return -ENOBUFS; |
||||
} |
||||
|
||||
_NATIVENET_DEV_MORE(dev)->_callbacks[i] = cb; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int _nativenet_rem_rcv_data_cb(netdev_t *dev, netdev_rcv_data_cb_t cb) |
||||
{ |
||||
int i = 0; |
||||
|
||||
if (dev->type != NETDEV_TYPE_BASE) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
for (i = 0; i < NATIVENET_DEV_CB_MAX; i++) { |
||||
if (_NATIVENET_DEV_MORE(dev)->_callbacks[i] == cb) { |
||||
_NATIVENET_DEV_MORE(dev)->_callbacks[i] = NULL; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int _nativenet_get_option(netdev_t *dev, netdev_opt_t opt, void *value, |
||||
size_t *value_len) |
||||
{ |
||||
if (dev->type != NETDEV_TYPE_BASE) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
switch (opt) { |
||||
case NETDEV_OPT_CHANNEL: |
||||
if (*value_len == 0) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (*value_len > sizeof(uint8_t)) { |
||||
*value_len = sizeof(uint8_t); |
||||
} |
||||
|
||||
*((uint8_t *)value) = _NATIVENET_DEV_MORE(dev)->_channel; |
||||
break; |
||||
|
||||
case NETDEV_OPT_ADDRESS: |
||||
if (*value_len < sizeof(radio_address_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (*value_len > sizeof(radio_address_t)) { |
||||
*value_len = sizeof(radio_address_t); |
||||
} |
||||
|
||||
*((radio_address_t *)value) = _NATIVENET_DEV_MORE(dev)->_radio_addr; |
||||
break; |
||||
|
||||
case NETDEV_OPT_NID: |
||||
if (*value_len < sizeof(uint16_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (*value_len > sizeof(uint16_t)) { |
||||
*value_len = sizeof(uint16_t); |
||||
} |
||||
|
||||
*((uint16_t *)value) = _NATIVENET_DEV_MORE(dev)->_pan_id; |
||||
break; |
||||
|
||||
case NETDEV_OPT_ADDRESS_LONG: |
||||
if (*value_len < sizeof(uint64_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (*value_len > sizeof(uint64_t)) { |
||||
*value_len = sizeof(uint64_t); |
||||
} |
||||
|
||||
*((uint64_t *)value) = _NATIVENET_DEV_MORE(dev)->_long_addr; |
||||
break; |
||||
|
||||
case NETDEV_OPT_MAX_PACKET_SIZE: |
||||
if (*value_len < sizeof(NATIVE_MAX_DATA_LENGTH)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (*value_len > sizeof(NATIVE_MAX_DATA_LENGTH)) { |
||||
*value_len = sizeof(NATIVE_MAX_DATA_LENGTH); |
||||
} |
||||
|
||||
*((netdev_proto_t *)value) = NATIVE_MAX_DATA_LENGTH; |
||||
break; |
||||
|
||||
case NETDEV_OPT_PROTO: |
||||
if (*value_len < sizeof(netdev_proto_t)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (*value_len > sizeof(netdev_proto_t)) { |
||||
*value_len = sizeof(netdev_proto_t); |
||||
} |
||||
|
||||
*((netdev_proto_t *)value) = NETDEV_PROTO_RADIO; |
||||
break; |
||||
|
||||
default: |
||||
return -ENOTSUP; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int _type_pun_up(void *value_out, size_t desired_len, |
||||
void *value_in, size_t given_len) |
||||
{ |
||||
if (given_len > desired_len) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
/* XXX this is ugly, but bear with me */ |
||||
switch (given_len) { |
||||
case 8: |
||||
switch (desired_len) { |
||||
case 8: |
||||
*((uint64_t *)value_out) = (*((uint64_t *)value_in)); |
||||
return 0; |
||||
|
||||
default: |
||||
return -EINVAL; |
||||
} |
||||
|
||||
case 4: |
||||
switch (desired_len) { |
||||
case 8: |
||||
*((uint64_t *)value_out) = (uint64_t)(*((uint32_t *)value_in)); |
||||
return 0; |
||||
|
||||
case 4: |
||||
*((uint32_t *)value_out) = (*((uint32_t *)value_in)); |
||||
return 0; |
||||
|
||||
default: |
||||
return -EINVAL; |
||||
} |
||||
|
||||
case 2: |
||||
switch (desired_len) { |
||||
case 8: |
||||
*((uint64_t *)value_out) = (uint64_t)(*((uint16_t *)value_in)); |
||||
return 0; |
||||
|
||||
case 4: |
||||
*((uint32_t *)value_out) = (uint32_t)(*((uint16_t *)value_in)); |
||||
return 0; |
||||
|
||||
case 2: |
||||
*((uint16_t *)value_out) = (*((uint16_t *)value_in)); |
||||
return 0; |
||||
|
||||
default: |
||||
return -EINVAL; |
||||
} |
||||
|
||||
case 1: |
||||
switch (desired_len) { |
||||
case 8: |
||||
*((uint64_t *)value_out) = (uint64_t)(*((uint8_t *)value_in)); |
||||
return 0; |
||||
|
||||
case 4: |
||||
*((uint32_t *)value_out) = (uint32_t)(*((uint8_t *)value_in)); |
||||
return 0; |
||||
|
||||
case 2: |
||||
*((uint16_t *)value_out) = (uint16_t)(*((uint8_t *)value_in)); |
||||
return 0; |
||||
|
||||
case 1: |
||||
*((uint8_t *)value_out) = (*((uint8_t *)value_in)); |
||||
return 0; |
||||
|
||||
default: |
||||
return -EINVAL; |
||||
} |
||||
|
||||
default: |
||||
return -EINVAL; |
||||
} |
||||
} |
||||
|
||||
int _nativenet_set_option(netdev_t *dev, netdev_opt_t opt, void *value, |
||||
size_t value_len) |
||||
{ |
||||
uint8_t set_value[sizeof(uint64_t)]; |
||||
int res = 0; |
||||
|
||||
if (dev->type != NETDEV_TYPE_BASE) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
switch (opt) { |
||||
case NETDEV_OPT_CHANNEL: |
||||
if ((res = _type_pun_up(set_value, sizeof(uint8_t), |
||||
value, value_len)) == 0) { |
||||
_NATIVENET_DEV_MORE(dev)->_channel = *((uint8_t *)set_value); |
||||
} |
||||
|
||||
break; |
||||
|
||||
case NETDEV_OPT_ADDRESS: |
||||
if ((res = _type_pun_up(set_value, sizeof(radio_address_t), |
||||
value, value_len)) == 0) { |
||||
_NATIVENET_DEV_MORE(dev)->_radio_addr = *((radio_address_t *)set_value); |
||||
} |
||||
|
||||
break; |
||||
|
||||
case NETDEV_OPT_NID: |
||||
if ((res = _type_pun_up(set_value, sizeof(uint16_t), |
||||
value, value_len)) == 0) { |
||||
_NATIVENET_DEV_MORE(dev)->_pan_id = *((uint16_t *)set_value); |
||||
} |
||||
|
||||
break; |
||||
|
||||
case NETDEV_OPT_PROTO: |
||||
/* TODO: wouldn't this be awesome */ |
||||
return -ENOTSUP; |
||||
|
||||
default: |
||||
return -ENOTSUP; |
||||
} |
||||
|
||||
return res; |
||||
} |
||||
|
||||
int _nativenet_get_state(netdev_t *dev, netdev_state_t *state) |
||||
{ |
||||
if (dev->type != NETDEV_TYPE_BASE) { |
||||
return -ENODEV; |
||||
} |
||||
|
||||
if (_NATIVENET_DEV_MORE(dev)->_is_monitoring) { |
||||
*state = NETDEV_STATE_PROMISCUOUS_MODE; |
||||
} |
||||
else { |
||||
*state = NETDEV_STATE_RX_MODE; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int _nativenet_set_state(netdev_t *dev, netdev_state_t state) |
||||
{ |
||||
if (state != NETDEV_STATE_PROMISCUOUS_MODE && _NATIVENET_DEV_MORE(dev)->_is_monitoring) { |
||||
_NATIVENET_DEV_MORE(dev)->_is_monitoring = 0; |
||||
} |
||||
|
||||
switch (state) { |
||||
case NETDEV_STATE_RX_MODE: |
||||
nativenet_switch_to_rx(); |
||||
break; |
||||
|
||||
case NETDEV_STATE_PROMISCUOUS_MODE: |
||||
_NATIVENET_DEV_MORE(dev)->_is_monitoring = 1; |
||||
break; |
||||
|
||||
default: |
||||
return -ENOTSUP; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void _nativenet_event(netdev_t *dev, uint32_t event_type) |
||||
{ |
||||
(void)dev; |
||||
(void)event_type; |
||||
} |
||||
|
||||
const netdev_driver_t nativenet_driver = { |
||||
_nativenet_init, |
||||
_nativenet_send_data, |
||||
_nativenet_add_rcv_data_cb, |
||||
_nativenet_rem_rcv_data_cb, |
||||
_nativenet_get_option, |
||||
_nativenet_set_option, |
||||
_nativenet_get_state, |
||||
_nativenet_set_state, |
||||
_nativenet_event, |
||||
}; |
||||
|
||||
_nativenet_netdev_more_t _nativenet_default_dev_more; |
||||
netdev_t nativenet_default_dev = {NETDEV_TYPE_BASE, &nativenet_driver, |
||||
&_nativenet_default_dev_more |
||||
}; |
||||
#else |
||||
_nativenet_netdev_more_t _nativenet_default_dev_more; |
||||
netdev_t nativenet_default_dev = {NETDEV_TYPE_BASE, NULL, |
||||
&_nativenet_default_dev_more |
||||
}; |
||||
#endif /* MODULE_NETDEV_BASE */ |
||||
|
||||
/** @} */ |
@ -1,370 +0,0 @@
|
||||
/**
|
||||
* tap.h implementation |
||||
* |
||||
* Copyright (C) 2013 Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
* |
||||
* @ingroup native_cpu |
||||
* @{ |
||||
* @file |
||||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <stdint.h> |
||||
#include <err.h> |
||||
#include <sys/ioctl.h> |
||||
#include <fcntl.h> |
||||
#include <arpa/inet.h> |
||||
#include <inttypes.h> |
||||
#include <errno.h> |
||||
|
||||
#ifdef __MACH__ |
||||
#define _POSIX_C_SOURCE |
||||
#include <net/if.h> |
||||
#undef _POSIX_C_SOURCE |
||||
#include <ifaddrs.h> |
||||
#include <net/if_dl.h> |
||||
|
||||
#elif defined(__FreeBSD__) |
||||
#include <sys/socket.h> |
||||
#include <net/if.h> |
||||
#include <ifaddrs.h> |
||||
#include <net/if_dl.h> |
||||
|
||||
#else |
||||
#include <net/if.h> |
||||
#include <linux/if_tun.h> |
||||
#include <linux/if_ether.h> |
||||
#endif |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
#include "cpu.h" |
||||
#include "cpu_conf.h" |
||||
#include "tap.h" |
||||
#include "nativenet.h" |
||||
#include "nativenet_internal.h" |
||||
#include "native_internal.h" |
||||
|
||||
#include "hwtimer.h" |
||||
#include "timex.h" |
||||
|
||||
#define TAP_BUFFER_LENGTH (ETHER_MAX_LEN) |
||||
int _native_marshall_ethernet(uint8_t *framebuf, radio_packet_t *packet); |
||||
|
||||
int _native_tap_fd = -1; |
||||
unsigned char _native_tap_mac[ETHER_ADDR_LEN]; |
||||
|
||||
#ifdef __MACH__ |
||||
pid_t sigio_child_pid; |
||||
#endif |
||||
|
||||
void _native_handle_tap_input(void) |
||||
{ |
||||
int nread; |
||||
union eth_frame frame; |
||||
radio_packet_t p; |
||||
|
||||
DEBUG("_native_handle_tap_input\n"); |
||||
|
||||
/* TODO: check whether this is an input or an output event
|
||||
TODO: refactor this into general io-signal multiplexer */ |
||||
|
||||
nread = real_read(_native_tap_fd, &frame, sizeof(union eth_frame)); |
||||
DEBUG("_native_handle_tap_input - read %d bytes\n", nread); |
||||
|
||||
if (nread > 0) { |
||||
if (ntohs(frame.field.header.ether_type) == NATIVE_ETH_PROTO) { |
||||
nread = nread - ETHER_HDR_LEN; |
||||
|
||||
if ((nread - 1) <= 0) { |
||||
DEBUG("_native_handle_tap_input: no payload\n"); |
||||
} |
||||
else { |
||||
unsigned long t = hwtimer_now(); |
||||
p.processing = 0; |
||||
p.src = ntohs(frame.field.payload.nn_header.src); |
||||
p.dst = ntohs(frame.field.payload.nn_header.dst); |
||||
p.rssi = 0; |
||||
p.lqi = 0; |
||||
p.toa.seconds = HWTIMER_TICKS_TO_US(t) / 1000000; |
||||
p.toa.microseconds = HWTIMER_TICKS_TO_US(t) % 1000000; |
||||
/* XXX: check overflow */ |
||||
p.length = ntohs(frame.field.payload.nn_header.length); |
||||
p.data = frame.field.payload.data; |
||||
|
||||
if (p.length > (nread - sizeof(struct nativenet_header))) { |
||||
warnx("_native_handle_tap_input: packet with malicious length field received, discarding"); |
||||
} |
||||
else { |
||||
DEBUG("_native_handle_tap_input: received packet of length %" PRIu16 " for %" PRIu16 " from %" |
||||
PRIu16 "\n", p.length, p.dst, p.src); |
||||
_nativenet_handle_packet(&p); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
DEBUG("ignoring non-native frame\n"); |
||||
} |
||||
|
||||
/* work around lost signals */ |
||||
fd_set rfds; |
||||
struct timeval t; |
||||
memset(&t, 0, sizeof(t)); |
||||
FD_ZERO(&rfds); |
||||
FD_SET(_native_tap_fd, &rfds); |
||||
|
||||
_native_in_syscall++; // no switching here
|
||||
|
||||
if (real_select(_native_tap_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++; |
||||
DEBUG("_native_handle_tap_input: sigpend++\n"); |
||||
} |
||||
else { |
||||
DEBUG("_native_handle_tap_input: no more pending tap data\n"); |
||||
#ifdef __MACH__ |
||||
kill(sigio_child_pid, SIGCONT); |
||||
#endif |
||||
} |
||||
|
||||
_native_in_syscall--; |
||||
} |
||||
else if (nread == -1) { |
||||
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { |
||||
//warn("read");
|
||||
} |
||||
else { |
||||
err(EXIT_FAILURE, "_native_handle_tap_input: read"); |
||||
} |
||||
} |
||||
else if (nread == 0) { |
||||
DEBUG("_native_handle_tap_input: ignoring null-event\n"); |
||||