|
|
|
@ -10,7 +10,7 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* @ingroup netdev2
|
|
|
|
|
* @ingroup netdev
|
|
|
|
|
* @{
|
|
|
|
|
* @brief Low-level ethernet driver for tap interfaces
|
|
|
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
|
|
|
@ -49,60 +49,60 @@
|
|
|
|
|
#include "async_read.h"
|
|
|
|
|
|
|
|
|
|
#include "net/eui64.h"
|
|
|
|
|
#include "net/netdev2.h"
|
|
|
|
|
#include "net/netdev2/eth.h"
|
|
|
|
|
#include "net/netdev.h"
|
|
|
|
|
#include "net/netdev/eth.h"
|
|
|
|
|
#include "net/ethernet.h"
|
|
|
|
|
#include "net/ethernet/hdr.h"
|
|
|
|
|
#include "netdev2_tap.h"
|
|
|
|
|
#include "netdev_tap.h"
|
|
|
|
|
#include "net/netopt.h"
|
|
|
|
|
#include "net/eui64.h"
|
|
|
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
|
|
/* netdev2 interface */
|
|
|
|
|
static int _init(netdev2_t *netdev);
|
|
|
|
|
static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned n);
|
|
|
|
|
static int _recv(netdev2_t *netdev, void *buf, size_t n, void *info);
|
|
|
|
|
/* netdev interface */
|
|
|
|
|
static int _init(netdev_t *netdev);
|
|
|
|
|
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 inline void _get_mac_addr(netdev2_t *netdev, uint8_t *dst)
|
|
|
|
|
static inline void _get_mac_addr(netdev_t *netdev, uint8_t *dst)
|
|
|
|
|
{
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
memcpy(dst, dev->addr, ETHERNET_ADDR_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void _set_mac_addr(netdev2_t *netdev, uint8_t *src)
|
|
|
|
|
static inline void _set_mac_addr(netdev_t *netdev, uint8_t *src)
|
|
|
|
|
{
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
memcpy(dev->addr, src, ETHERNET_ADDR_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int _get_promiscous(netdev2_t *netdev)
|
|
|
|
|
static inline int _get_promiscous(netdev_t *netdev)
|
|
|
|
|
{
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
return dev->promiscous;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int _set_promiscous(netdev2_t *netdev, int value)
|
|
|
|
|
static inline int _set_promiscous(netdev_t *netdev, int value)
|
|
|
|
|
{
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
dev->promiscous = value;
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void _isr(netdev2_t *netdev)
|
|
|
|
|
static inline void _isr(netdev_t *netdev)
|
|
|
|
|
{
|
|
|
|
|
if (netdev->event_callback) {
|
|
|
|
|
netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE);
|
|
|
|
|
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
|
|
|
|
|
}
|
|
|
|
|
#if DEVELHELP
|
|
|
|
|
else {
|
|
|
|
|
puts("netdev2_tap: _isr(): no event_callback set.");
|
|
|
|
|
puts("netdev_tap: _isr(): no event_callback set.");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len)
|
|
|
|
|
static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len)
|
|
|
|
|
{
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
@ -121,14 +121,14 @@ static int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len)
|
|
|
|
|
res = sizeof(bool);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
res = netdev2_eth_get(dev, opt, value, max_len);
|
|
|
|
|
res = netdev_eth_get(dev, opt, value, max_len);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len)
|
|
|
|
|
static int _set(netdev_t *dev, netopt_t opt, void *value, size_t value_len)
|
|
|
|
|
{
|
|
|
|
|
(void)value_len;
|
|
|
|
|
int res = 0;
|
|
|
|
@ -148,7 +148,7 @@ static int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len)
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static netdev2_driver_t netdev2_driver_tap = {
|
|
|
|
|
static netdev_driver_t netdev_driver_tap = {
|
|
|
|
|
.send = _send,
|
|
|
|
|
.recv = _recv,
|
|
|
|
|
.init = _init,
|
|
|
|
@ -170,7 +170,7 @@ static inline bool _is_addr_multicast(uint8_t *addr)
|
|
|
|
|
return (addr[0] & 0x01);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _continue_reading(netdev2_tap_t *dev)
|
|
|
|
|
static void _continue_reading(netdev_tap_t *dev)
|
|
|
|
|
{
|
|
|
|
|
/* work around lost signals */
|
|
|
|
|
fd_set rfds;
|
|
|
|
@ -187,25 +187,25 @@ static void _continue_reading(netdev2_tap_t *dev)
|
|
|
|
|
extern ssize_t (*real_write)(int fd, const void * buf, size_t count);
|
|
|
|
|
real_write(_sig_pipefd[1], &sig, sizeof(int));
|
|
|
|
|
_native_sigpend++;
|
|
|
|
|
DEBUG("netdev2_tap: sigpend++\n");
|
|
|
|
|
DEBUG("netdev_tap: sigpend++\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
DEBUG("netdev2_tap: native_async_read_continue\n");
|
|
|
|
|
DEBUG("netdev_tap: native_async_read_continue\n");
|
|
|
|
|
native_async_read_continue(dev->tap_fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_native_in_syscall--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int _recv(netdev2_t *netdev2, void *buf, size_t len, void *info)
|
|
|
|
|
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
|
|
|
|
{
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev2;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
(void)info;
|
|
|
|
|
|
|
|
|
|
if (!buf) {
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
/* no memory available in pktbuf, discarding the frame */
|
|
|
|
|
DEBUG("netdev2_tap: discarding the frame\n");
|
|
|
|
|
DEBUG("netdev_tap: discarding the frame\n");
|
|
|
|
|
|
|
|
|
|
/* repeating `real_read` for small size on tap device results in
|
|
|
|
|
* freeze for some reason. Using a large buffer for now. */
|
|
|
|
@ -228,14 +228,14 @@ static int _recv(netdev2_t *netdev2, void *buf, size_t len, void *info)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nread = real_read(dev->tap_fd, buf, len);
|
|
|
|
|
DEBUG("netdev2_tap: read %d bytes\n", nread);
|
|
|
|
|
DEBUG("netdev_tap: read %d bytes\n", nread);
|
|
|
|
|
|
|
|
|
|
if (nread > 0) {
|
|
|
|
|
ethernet_hdr_t *hdr = (ethernet_hdr_t *)buf;
|
|
|
|
|
if (!(dev->promiscous) && !_is_addr_multicast(hdr->dst) &&
|
|
|
|
|
!_is_addr_broadcast(hdr->dst) &&
|
|
|
|
|
(memcmp(hdr->dst, dev->addr, ETHERNET_ADDR_LEN) != 0)) {
|
|
|
|
|
DEBUG("netdev2_tap: received for %02x:%02x:%02x:%02x:%02x:%02x\n"
|
|
|
|
|
DEBUG("netdev_tap: received for %02x:%02x:%02x:%02x:%02x:%02x\n"
|
|
|
|
|
"That's not me => Dropped\n",
|
|
|
|
|
hdr->dst[0], hdr->dst[1], hdr->dst[2],
|
|
|
|
|
hdr->dst[3], hdr->dst[4], hdr->dst[5]);
|
|
|
|
@ -248,8 +248,8 @@ static int _recv(netdev2_t *netdev2, void *buf, size_t len, void *info)
|
|
|
|
|
_continue_reading(dev);
|
|
|
|
|
|
|
|
|
|
#ifdef MODULE_NETSTATS_L2
|
|
|
|
|
netdev2->stats.rx_count++;
|
|
|
|
|
netdev2->stats.rx_bytes += nread;
|
|
|
|
|
netdev->stats.rx_count++;
|
|
|
|
|
netdev->stats.rx_bytes += nread;
|
|
|
|
|
#endif
|
|
|
|
|
return nread;
|
|
|
|
|
}
|
|
|
|
@ -257,7 +257,7 @@ static int _recv(netdev2_t *netdev2, void *buf, size_t len, void *info)
|
|
|
|
|
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
err(EXIT_FAILURE, "netdev2_tap: read");
|
|
|
|
|
err(EXIT_FAILURE, "netdev_tap: read");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (nread == 0) {
|
|
|
|
@ -270,9 +270,9 @@ static int _recv(netdev2_t *netdev2, void *buf, size_t len, void *info)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned n)
|
|
|
|
|
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n)
|
|
|
|
|
{
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
int res = _native_writev(dev->tap_fd, vector, n);
|
|
|
|
|
#ifdef MODULE_NETSTATS_L2
|
|
|
|
|
size_t bytes = 0;
|
|
|
|
@ -283,34 +283,34 @@ static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned n)
|
|
|
|
|
netdev->stats.tx_bytes += bytes;
|
|
|
|
|
#endif
|
|
|
|
|
if (netdev->event_callback) {
|
|
|
|
|
netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE);
|
|
|
|
|
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void netdev2_tap_setup(netdev2_tap_t *dev, const netdev2_tap_params_t *params) {
|
|
|
|
|
dev->netdev.driver = &netdev2_driver_tap;
|
|
|
|
|
void netdev_tap_setup(netdev_tap_t *dev, const netdev_tap_params_t *params) {
|
|
|
|
|
dev->netdev.driver = &netdev_driver_tap;
|
|
|
|
|
strncpy(dev->tap_name, *(params->tap_name), IFNAMSIZ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _tap_isr(int fd, void *arg) {
|
|
|
|
|
(void) fd;
|
|
|
|
|
|
|
|
|
|
netdev2_t *netdev = (netdev2_t *)arg;
|
|
|
|
|
netdev_t *netdev = (netdev_t *)arg;
|
|
|
|
|
|
|
|
|
|
if (netdev->event_callback) {
|
|
|
|
|
netdev->event_callback(netdev, NETDEV2_EVENT_ISR);
|
|
|
|
|
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
puts("netdev2_tap: _isr: no event callback.");
|
|
|
|
|
puts("netdev_tap: _isr: no event callback.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int _init(netdev2_t *netdev)
|
|
|
|
|
static int _init(netdev_t *netdev)
|
|
|
|
|
{
|
|
|
|
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
|
|
|
|
|
|
|
|
|
|
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
|
|
|
|
|
netdev_tap_t *dev = (netdev_tap_t*)netdev;
|
|
|
|
|
|
|
|
|
|
/* check device parametrs */
|
|
|
|
|
if (dev == NULL) {
|