1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

sys: net: replace dev_eth with netdev2, adapt native tap driver

This commit is contained in:
Kaspar Schleiser 2015-08-21 16:08:43 +02:00
parent 78b4bf6f58
commit ef972735dc
20 changed files with 272 additions and 1055 deletions

View File

@ -1,5 +1,4 @@
ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
USEMODULE += dev_eth_tap
USEMODULE += gnrc_netdev_eth
USEMODULE += gnrc_nomac
USEMODULE += netdev2_tap
USEMODULE += gnrc_netdev2
endif

View File

@ -72,7 +72,7 @@ export LINKFLAGS += -ldl
endif
# set the tap interface for term/valgrind
ifneq (,$(filter dev_eth_tap,$(USEMODULE)))
ifneq (,$(filter netdev2_tap,$(USEMODULE)))
export PORT ?= tap0
else
export PORT =

View File

@ -2,8 +2,8 @@ MODULE = cpu
DIRS += periph
ifneq (,$(filter dev_eth_tap,$(USEMODULE)))
DIRS += dev_eth_tap
ifneq (,$(filter netdev2_tap,$(USEMODULE)))
DIRS += netdev2_tap
endif
include $(RIOTBASE)/Makefile.base

View File

@ -47,6 +47,7 @@
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include "kernel_types.h"
@ -123,6 +124,7 @@ extern long int (*real_random)(void);
extern const char* (*real_gai_strerror)(int errcode);
extern FILE* (*real_fopen)(const char *path, const char *mode);
extern mode_t (*real_umask)(mode_t cmask);
extern ssize_t (*real_writev)(int fildes, const struct iovec *iov, int iovcnt);
#ifdef __MACH__
#else
@ -160,6 +162,7 @@ extern fd_set _native_rfds;
ssize_t _native_read(int fd, void *buf, size_t count);
ssize_t _native_write(int fd, const void *buf, size_t count);
ssize_t _native_writev(int fildes, const struct iovec *iov, int iovcnt);
/**
* register interrupt handler handler for interrupt sig

View File

@ -7,66 +7,67 @@
*/
/**
* @defgroup dev_eth_tap Ethernet driver for TAP interfaces
* @ingroup native_cpu
* @ingroup netdev2
* @brief Low-level ethernet driver for native tap interfaces
* @{
*
* @file
* @brief Definitions for @ref net_dev_eth driver for host system's
* @brief Definitions for @ref netdev2 ethernet driver for host system's
* TAP interfaces
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef DEV_ETH_TAP_H
#define DEV_ETH_TAP_H
#ifndef NETDEV2_TAP_H
#define NETDEV2_TAP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "net/dev_eth.h"
#include "net/netdev2.h"
#include "net/if.h"
#include "net/ethernet/hdr.h"
#ifdef __MACH__
#include "net/if_var.h"
#else
#include "net/if.h"
#endif
/**
* @brief tap interface state
*/
typedef struct dev_eth_tap {
dev_eth_t ethdev; /**< dev_eth internal member */
typedef struct netdev2_tap {
netdev2_t netdev; /**< netdev2 internal member */
char tap_name[IFNAMSIZ]; /**< host dev file name */
int tap_fd; /**< host file descriptor for the TAP */
uint8_t addr[ETHERNET_ADDR_LEN]; /**< The MAC address of the TAP */
uint8_t promiscous; /**< Flag for promiscous mode */
} dev_eth_tap_t;
} netdev2_tap_t;
/**
* @brief global device struct. driver only supports one tap device as of now.
*/
extern dev_eth_tap_t dev_eth_tap;
extern netdev2_tap_t netdev2_tap;
/**
* @brief Setup dev_eth_tap_t structure.
* @brief Setup netdev2_tap_t structure.
*
* @param dev the preallocated dev_eth_tap device handle to setup
* @param dev the preallocated netdev2_tap device handle to setup
* @param name Name of the host system's tap inteface to bind to.
*/
void dev_eth_tap_setup(dev_eth_tap_t *dev, const char *name);
void netdev2_tap_setup(netdev2_tap_t *dev, const char *name);
/**
* @brief Cleanup dev_eth_tap_t structure.
* @brief Cleanup tap resources
*
* @param dev the dev_eth_tap device handle to cleanup
* @param dev the netdev2_tap device handle to cleanup
*/
void dev_eth_tap_cleanup(dev_eth_tap_t *dev);
void netdev2_tap_cleanup(netdev2_tap_t *dev);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* DEV_ETH_TAP_H */
#endif /* NETDEV2_TAP_H */

View File

@ -49,9 +49,9 @@
#include "cpu.h"
#include "cpu_conf.h"
#ifdef MODULE_DEV_ETH_TAP
#include "dev_eth_tap.h"
extern dev_eth_tap_t dev_eth_tap;
#ifdef MODULE_NETDEV2_TAP
#include "netdev2_tap.h"
extern netdev2_tap_t netdev2_tap;
#endif
#include "native_internal.h"
@ -75,8 +75,8 @@ int reboot_arch(int mode)
/* TODO: close stdio fds */
#endif
#ifdef MODULE_DEV_ETH_TAP
dev_eth_tap_cleanup(&dev_eth_tap);
#ifdef MODULE_NETDEV2_TAP
netdev2_tap_cleanup(&netdev2_tap);
#endif
if (real_execve(_native_argv[0], _native_argv, NULL) == -1) {

View File

@ -1,5 +1,3 @@
MODULE = dev_eth_tap
include $(RIOTBASE)/Makefile.base
INCLUDES = $(NATIVEINCLUDES)

View File

@ -10,12 +10,13 @@
*/
/*
* @ingroup net_dev_eth
* @ingroup netdev2
* @{
* @brief Low-level ethernet driver for tap interfaces
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @}
*/
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@ -47,55 +48,157 @@
#include "native_internal.h"
#include "net/dev_eth.h"
#include "dev_eth_tap.h"
#include "net/eui64.h"
#include "net/netdev2.h"
#include "net/ethernet.h"
#include "net/ethernet/hdr.h"
#include "netdev2_tap.h"
#include "net/netopt.h"
#include "net/eui64.h"
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
/* support one tap interface for now */
dev_eth_tap_t dev_eth_tap;
netdev2_tap_t netdev2_tap;
#ifdef __MACH__
pid_t _sigio_child_pid;
static void _sigio_child(dev_eth_tap_t *dev);
static void _sigio_child(netdev2_tap_t *dev);
#endif
/* dev_eth interface */
static int _init(dev_eth_t *ethdev);
static void _cleanup(dev_eth_t *ethdev);
static int _send(dev_eth_t *ethdev, char* buf, int n);
static int _recv(dev_eth_t *ethdev, char* buf, int n);
/* netdev2 interface */
static int _init(netdev2_t *netdev);
static int _send(netdev2_t *netdev, const struct iovec *vector, int n);
static int _recv(netdev2_t *netdev, char* buf, int n);
static inline void _get_mac_addr(dev_eth_t *ethdev, uint8_t *dst) {
dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;
static inline void _get_mac_addr(netdev2_t *netdev, uint8_t *dst)
{
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
memcpy(dst, dev->addr, ETHERNET_ADDR_LEN);
}
static inline int _get_promiscous(dev_eth_t *ethdev) {
dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;
static inline void _set_mac_addr(netdev2_t *netdev, uint8_t *src)
{
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
memcpy(dev->addr, src, ETHERNET_ADDR_LEN);
}
static inline int _get_promiscous(netdev2_t *netdev)
{
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
return dev->promiscous;
}
static inline int _set_promiscous(dev_eth_t *ethdev, int value) {
dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;
static inline int _set_promiscous(netdev2_t *netdev, int value)
{
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
dev->promiscous = value;
return value;
}
static inline void _isr(dev_eth_t *ethdev) {
dev_eth_rx_handler(ethdev);
static inline int _get_iid(netdev2_t *netdev, eui64_t *value, size_t max_len)
{
if (max_len < sizeof(eui64_t)) {
return -EOVERFLOW;
}
uint8_t addr[ETHERNET_ADDR_LEN];
_get_mac_addr(netdev, addr);
ethernet_get_iid(value, addr);
return sizeof(eui64_t);
}
static inline void _isr(netdev2_t *netdev)
{
if (netdev->event_callback) {
netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE, (void*)NETDEV2_TYPE_ETHERNET);
}
#if DEVELHELP
else {
puts("netdev2_tap: _isr(): no event_callback set.");
}
#endif
}
static eth_driver_t eth_driver_tap = {
.init = _init,
.cleanup = _cleanup,
int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len)
{
if (dev != (netdev2_t *)&netdev2_tap) {
return -ENODEV;
}
int res = 0;
switch (opt) {
case NETOPT_DEVICE_TYPE:
{
uint16_t *tgt = (uint16_t *)value;
*tgt = NETDEV2_TYPE_ETHERNET;
res = 2;
break;
}
case NETOPT_ADDRESS:
if (max_len < ETHERNET_ADDR_LEN) {
res = -EINVAL;
}
else {
_get_mac_addr(dev, (uint8_t*)value);
res = ETHERNET_ADDR_LEN;
}
break;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
assert(max_len == 2);
uint16_t *tgt = (uint16_t*)value;
*tgt=6;
res = sizeof(uint16_t);
break;
case NETOPT_PROMISCUOUSMODE:
*((bool*)value) = (bool)_get_promiscous(dev);
res = sizeof(bool);
break;
case NETOPT_IPV6_IID:
return _get_iid(dev, value, max_len);
default:
res = -ENOTSUP;
break;
}
return res;
}
int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len)
{
(void)value_len;
if (dev != (netdev2_t *)&netdev2_tap) {
return -ENODEV;
}
int res = 0;
switch (opt) {
case NETOPT_ADDRESS:
assert(value_len==ETHERNET_ADDR_LEN);
_set_mac_addr(dev, (uint8_t*)value);
break;
case NETOPT_PROMISCUOUSMODE:
_set_promiscous(dev, ((bool *)value)[0]);
break;
default:
return -ENOTSUP;
}
return res;
}
static netdev2_driver_t netdev2_driver_tap = {
.send = _send,
.recv = _recv,
.get_mac_addr = _get_mac_addr,
.get_promiscous = _get_promiscous,
.set_promiscous = _set_promiscous,
.init = _init,
.isr = _isr,
.get = _get,
.set = _set,
};
/* driver implementation */
@ -111,18 +214,25 @@ static inline bool _is_addr_multicast(uint8_t *addr)
return (addr[0] & 0x01);
}
static int _recv(dev_eth_t *dev_eth, char *buf, int len) {
dev_eth_tap_t *dev = (dev_eth_tap_t*)dev_eth;
static int _recv(netdev2_t *netdev2, char *buf, int len)
{
netdev2_tap_t *dev = (netdev2_tap_t*)netdev2;
if (!buf) {
/* no way of figuring out packet size without racey buffering,
* so we return the maximum possible size */
return 576;
}
int nread = real_read(dev->tap_fd, buf, len);
DEBUG("gnrc_tapnet: read %d bytes\n", nread);
DEBUG("netdev2_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("gnrc_eth_dev: received for %02x:%02x:%02x:%02x:%02x:%02x\n"
DEBUG("netdev2_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]);
@ -146,7 +256,7 @@ static int _recv(dev_eth_t *dev_eth, char *buf, int len) {
extern ssize_t (*real_write)(int fd, const void * buf, size_t count);
real_write(_sig_pipefd[1], &sig, sizeof(int));
_native_sigpend++;
DEBUG("dev_eth_tap: sigpend++\n");
DEBUG("netdev2_tap: sigpend++\n");
}
else {
#ifdef __MACH__
@ -162,7 +272,7 @@ static int _recv(dev_eth_t *dev_eth, char *buf, int len) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
}
else {
err(EXIT_FAILURE, "dev_eth_tap: read");
err(EXIT_FAILURE, "netdev2_tap: read");
}
}
else if (nread == 0) {
@ -175,30 +285,33 @@ static int _recv(dev_eth_t *dev_eth, char *buf, int len) {
return -1;
}
static int _send(dev_eth_t *ethdev, char* buf, int n) {
dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;
return _native_write(dev->tap_fd, buf, n);
static int _send(netdev2_t *netdev, const struct iovec *vector, int n)
{
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
return _native_writev(dev->tap_fd, vector, n);
}
void dev_eth_tap_setup(dev_eth_tap_t *dev, const char *name) {
dev->ethdev.driver = &eth_driver_tap;
void netdev2_tap_setup(netdev2_tap_t *dev, const char *name) {
dev->netdev.driver = &netdev2_driver_tap;
strncpy(dev->tap_name, name, IFNAMSIZ);
}
void dev_eth_tap_cleanup(dev_eth_tap_t *dev) {
if (!dev) {
return;
}
dev_eth_cleanup((dev_eth_t *) dev);
}
static void _tap_isr(void) {
dev_eth_isr(((dev_eth_t *) &dev_eth_tap));
netdev2_t *netdev = (netdev2_t *)&netdev2_tap;
if (netdev->event_callback) {
netdev->event_callback(netdev, NETDEV2_EVENT_ISR, netdev->isr_arg);
}
else {
puts("netdev2_tap: _isr: no event callback.");
}
}
static int _init(dev_eth_t *ethdev)
static int _init(netdev2_t *netdev)
{
dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);
netdev2_tap_t *dev = (netdev2_tap_t*)netdev;
/* check device parametrs */
if (dev == NULL) {
@ -284,10 +397,8 @@ static int _init(dev_eth_t *ethdev)
return 0;
}
static void _cleanup(dev_eth_t *ethdev)
void netdev2_tap_cleanup(netdev2_tap_t *dev)
{
dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;
/* Do we have a device */
if (!dev) {
return;
@ -304,7 +415,7 @@ static void _cleanup(dev_eth_t *ethdev)
}
#ifdef __MACH__
static void _sigio_child(dev_eth_tap_t *dev)
static void _sigio_child(netdev2_tap_t *dev)
{
pid_t parent = _native_pid;
if ((_sigio_child_pid = real_fork()) == -1) {

View File

@ -46,9 +46,9 @@ unsigned _native_rng_seed = 0;
int _native_rng_mode = 0;
const char *_native_unix_socket_path = NULL;
#ifdef MODULE_DEV_ETH_TAP
#include "dev_eth_tap.h"
extern dev_eth_tap_t dev_eth_tap;
#ifdef MODULE_NETDEV2_TAP
#include "netdev2_tap.h"
extern netdev2_tap_t netdev2_tap;
#endif
/**
@ -196,7 +196,7 @@ void usage_exit(void)
{
real_printf("usage: %s", _progname);
#if defined(MODULE_DEV_ETH_TAP)
#if defined(MODULE_NETDEV2_TAP)
real_printf(" <tap interface>");
#endif
@ -256,7 +256,7 @@ __attribute__((constructor)) static void startup(int argc, char **argv)
int replay = 0;
#endif
#if defined(MODULE_DEV_ETH_TAP)
#if defined(MODULE_NETDEV2_TAP)
if (
(argc < 2)
|| (
@ -367,8 +367,8 @@ __attribute__((constructor)) static void startup(int argc, char **argv)
native_cpu_init();
native_interrupt_init();
#ifdef MODULE_DEV_ETH_TAP
dev_eth_tap_setup(&dev_eth_tap, argv[1]);
#ifdef MODULE_NETDEV2_TAP
netdev2_tap_setup(&netdev2_tap, argv[1]);
#endif
board_init();

View File

@ -91,6 +91,7 @@ long int (*real_random)(void);
const char* (*real_gai_strerror)(int errcode);
FILE* (*real_fopen)(const char *path, const char *mode);
mode_t (*real_umask)(mode_t cmask);
ssize_t (*real_writev)(int fildes, const struct iovec *iov, int iovcnt);
#ifdef __MACH__
#else
@ -209,6 +210,17 @@ ssize_t _native_write(int fd, const void *buf, size_t count)
return r;
}
ssize_t _native_writev(int fd, const struct iovec *iov, int iovcnt)
{
ssize_t r;
_native_syscall_enter();
r = real_writev(fd, iov, iovcnt);
_native_syscall_leave();
return r;
}
#if defined(__FreeBSD__)
#undef putchar
#endif
@ -424,6 +436,7 @@ void _native_init_syscalls(void)
*(void **)(&real_ferror) = dlsym(RTLD_NEXT, "ferror");
*(void **)(&real_clearerr) = dlsym(RTLD_NEXT, "clearerr");
*(void **)(&real_umask) = dlsym(RTLD_NEXT, "umask");
*(void **)(&real_writev) = dlsym(RTLD_NEXT, "writev");
#ifdef __MACH__
#else
*(void **)(&real_clock_gettime) = dlsym(RTLD_NEXT, "clock_gettime");

View File

@ -4,8 +4,4 @@ ifneq (,$(filter auto_init_gnrc_netif,$(USEMODULE)))
DIRS += netif
endif
ifneq (,$(filter dev_eth_autoinit,$(USEMODULE)))
DIRS += $(RIOTBASE)/sys/auto_init/dev_eth
endif
include $(RIOTBASE)/Makefile.base

View File

@ -84,9 +84,8 @@
#include "net/gnrc/udp.h"
#endif
#ifdef MODULE_DEV_ETH_AUTOINIT
#include "net/dev_eth.h"
#include "dev_eth_autoinit.h"
#ifdef MODULE_FIB
#include "net/fib.h"
#endif
#define ENABLE_DEBUG (0)
@ -182,9 +181,9 @@ void auto_init(void)
auto_init_kw2xrf();
#endif
#ifdef MODULE_GNRC_NETDEV_ETH
extern void auto_init_gnrc_netdev_eth(void);
auto_init_gnrc_netdev_eth();
#ifdef MODULE_NETDEV2_TAP
extern void auto_init_netdev2_tap(void);
auto_init_netdev2_tap();
#endif
#endif /* MODULE_AUTO_INIT_GNRC_NETIF */

View File

@ -1,3 +0,0 @@
MODULE = dev_eth_autoinit
include $(RIOTBASE)/Makefile.base

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.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.
*/
#include "net/dev_eth.h"
#include "dev_eth_autoinit.h"
#ifdef MODULE_DEV_ETH_TAP
#include "dev_eth_tap.h"
#endif
#ifdef MODULE_ENCX24J600
#include "encx24j600.h"
encx24j600_t dev_eth_encx24j600;
#endif
dev_eth_t * const dev_eth_devices[] = {
#ifdef MODULE_DEV_ETH_TAP
[DEV_ETH_TAP] = (dev_eth_t*)&dev_eth_tap,
#endif
#ifdef MODULE_ENCX24J600
[DEV_ETH_ENCX24J600] = (dev_eth_t*)&dev_eth_encx24j600,
#endif
};
void dev_eth_autoinit(void)
{
#ifdef MODULE_ENCX24J600
/* TODO: use sensible defines */
encx24j600_setup(&dev_eth_encx24j600, SPI_0, GPIO_1, GPIO_2);
#endif
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.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 auto_init_gnrc_netif
* @{
*
* @file
* @brief Auto initialization for netdev Ethernet network interfaces
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
*/
#ifdef MODULE_GNRC_NETDEV_ETH
#include "board.h"
#include "net/gnrc/nomac.h"
#include "net/gnrc.h"
#include "net/gnrc/netdev_eth.h"
#include "net/dev_eth.h"
#include "dev_eth_tap.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Define stack parameters for the MAC layer thread
* @{
*/
#define NETDEV_ETH_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#define NETDEV_ETH_MAC_PRIO (THREAD_PRIORITY_MAIN - 4)
static char _nomac_stack[NETDEV_ETH_MAC_STACKSIZE];
void auto_init_gnrc_netdev_eth(void)
{
DEBUG("Initializing NETDEV_ETH device\n");
int res = gnrc_netdev_eth_init(&gnrc_netdev_eth, (dev_eth_t*)&dev_eth_tap);
if (res < 0) {
DEBUG("Error initializing NETDEV_ETH device!");
}
else {
gnrc_nomac_init(_nomac_stack, NETDEV_ETH_MAC_STACKSIZE, NETDEV_ETH_MAC_PRIO,
"tapnet", (gnrc_netdev_t *)&gnrc_netdev_eth);
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_GNRC_NETDEV_ETH */
/** @} */

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.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 auto_init_ng_netif
* @{
*
* @file
* @brief Auto initialization for ethernet devices
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifdef MODULE_NETDEV2_TAP
#define ENABLE_DEBUG (1)
#include "debug.h"
#include "netdev2_tap.h"
#include "net/gnrc/gnrc_netdev2_eth.h"
extern netdev2_tap_t netdev2_tap;
/**
* @brief Define stack parameters for the MAC layer thread
* @{
*/
#define TAP_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE)
#define TAP_MAC_PRIO (THREAD_PRIORITY_MAIN - 3)
/**
* @brief Stacks for the MAC layer threads
*/
static char _netdev2_eth_stack[TAP_MAC_STACKSIZE + DEBUG_EXTRA_STACKSIZE];
static gnrc_netdev2_t _gnrc_netdev2_tap;
void auto_init_netdev2_tap(void)
{
gnrc_netdev2_eth_init(&_gnrc_netdev2_tap, (netdev2_t*)&netdev2_tap);
gnrc_netdev2_init(_netdev2_eth_stack, TAP_MAC_STACKSIZE,
TAP_MAC_PRIO, "gnrc_netdev2_tap", &_gnrc_netdev2_tap);
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_NETDEV2_TAP */
/** @} */

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.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 sys_net_dev_eth dev_eth auto setup
* @ingroup net_ethernet
* @file
* @brief Automatically setup available ethernet devices
* @{
*
* @brief header for dev_eth automatic initialization
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef DEV_ETH_AUTOINIT_H
#define DEV_ETH_AUTOINIT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief enum for available ethernet devices
*/
enum {
#ifdef MODULE_DEV_ETH_TAP
DEV_ETH_TAP,
#endif
#ifdef MODULE_ENCX24J600
DEV_ETH_ENCX24J600,
#endif
/* must be last: */
NUM_DEV_ETH
};
/**
* @brief Array of const pointers to available ethernet devices
*/
extern dev_eth_t *const dev_eth_devices[];
/**
* @brief Automatically sets up available dev_eth ethernet devices
*
* ... by calling the respective *_setup() functions if available.
*/
void dev_eth_autoinit(void);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* DEV_ETH_AUTOINIT_H */

View File

@ -1,216 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* Ell-i open source co-operative
*
* 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_dev_eth Low-Level Driver Interface
* @ingroup net_ethernet
* @brief Low-level ethernet driver interface
*
* This interface is supposed to be a low-level interface for ethernet drivers.
* In order to be universally usable, it leaves out many implementation details
* to the implementation of an actual network stack using this interface.
*
* In order to write a driver for this interface, you have to
*
* 1. create a (possibly const) eth_driver_t structure for your device type,
* implement it's functions
*
* 2. create a dev_eth_t structure, used as device state and handle, for each device
*
* In order to use this interface, you have to
*
* 1. implement dev_eth_isr, dev_eth_rx_handler and dev_eth_linkstate_handler
* 2. run a loop that get's notified by dev_eth_isr
*
* A devices send function should always be able to send a frame (and make sure of proper locking).
*
* Receive packet flow:
*
* 1. Ethernet driver receives packet, executes driver's internal ISR.
* 2. driver's internal ISR should do minimal acknowledging and house keeping and then
* call dev_eth_isr
* 3. dev_eth_isr should notify a user of this API (e.g., the network stack's L2 thread)
* 4. That thread executes the driver's user-space isr (dev->driver->isr)
* 5. user space ISR handles less timing critical stuff, eventually calling
* dev_eth_linkstate_handler and / or dev_eth_rx_handler
*
* Check out the dev_eth test application as example.
*
* @{
*
* @file
* @brief Definitions low-level ethernet driver interface
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef DEV_ETH_H
#define DEV_ETH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "ethernet/hdr.h"
/**
* @brief Structure to hold driver state
*
* Supposed to be extended by driver implementations.
* The extended structure should contain all variable driver state.
*/
typedef struct dev_eth {
const struct eth_driver *driver; /**< ptr to that driver's interface.
driver->init() expects this to be present,
so set this before using the device. */
} dev_eth_t;
/**
* @brief Structure to hold driver interface -> function mapping
*
* The send/receive functions expect/return a full ethernet
* frame (dst mac, src mac, ethertype, payload, no checksum).
*/
typedef struct eth_driver {
/**
* @brief Send ethernet frame
*
* Expects a full ethernet frame (dst mac, src mac, ethertype, payload,
* no checksum).
*
* @param buf buffer to read from
* @param len nr of bytes to send
*
* @return nr of bytes sent, or <=0 on error
*/
int (*send)(dev_eth_t *dev, char* buf, int len);
/**
* @brief Get a received ethernet frame
*
* Supposed to be called from dev_eth_rx_handler().
*
* Make sure buf can hold the maximum expected ethernet frame size.
*
* @param buf buffer to write to
* @param len maximum nr. of bytes to read
*
* @return nr of bytes read or <=0 on error
*/
int (*recv)(dev_eth_t *dev, char* buf, int len);
/**
* @brief get the device's MAC address
*
* @param buf location to write to. Make sure this is can take least 6 bytes
*/
void (*get_mac_addr)(dev_eth_t *dev, uint8_t *buf);
/**
* @brief get the device's promiscous status
*
* Default is not promiscous.
* Promiscous means, receive all ethernet frames.
* Not promiscous means only receive broadcast, multicast or frames with
* the device's MAC address as dst address.
*
* @return 1 for promiscous, 0 for not promiscous
*/
int (*get_promiscous)(dev_eth_t *dev);
/**
* @brief set the devices promiscous mode
*
* @param value 1 for promiscous, 0 for not promiscous
* @return the new value (device might not support wanted mode)
*/
int (*set_promiscous)(dev_eth_t *dev, int value);
/**
* @brief the driver's initialization function
*
* @return <=0 on error, >0 on success
*/
int (*init)(dev_eth_t *dev);
/**
* @brief the driver's cleanup function (optional)
*/
void (*cleanup)(dev_eth_t *dev);
/**
* @brief a driver's user-space ISR handler
*
* This function will be called from a network stack's loop when being notified
* by dev_eth_isr.
*
* It is supposed to call dev_eth_rx_handler for each available received packed,
* and dev_eth_linkstate_handler whenever a link state change event occurs.
*
* See receive packet flow description for details.
*/
void (*isr)(dev_eth_t *dev);
} eth_driver_t;
/**
* @brief Initialize a device given by dev (convenience function)
*
* The device given as parameter *must* be previously setup by the
* drivers *_setup() function.
*
*/
static inline int dev_eth_init(dev_eth_t *dev) {
return dev->driver->init(dev);
}
/**
* @brief Cleanup a device given by dev (convenience function)
*
* This function is to be called on reboot if the init function is not
* idempotent.
*
*/
static inline void dev_eth_cleanup(dev_eth_t *dev) {
if (dev->driver->cleanup) {
dev->driver->cleanup(dev);
}
}
/**
* @brief global dev_eth interrupt handling function.
*
* This function should be called from your device's ISR from whithin ISR context.
* It is supposed to wake up a waiting user-space event loop.
*/
extern void dev_eth_isr(dev_eth_t *dev);
/**
* @brief dev_eth event callback for packets that were received.
*
* This function should be called from whithin your driver's isr()
* (as defined in eth_driver_t), once for every packet that was received.
*
* It needs to call dev->driver->recv() in order to get received packet
* from the driver.
*/
extern void dev_eth_rx_handler(dev_eth_t *dev);
/**
* @brief dev_eth ethernet link state handler
*
* This function should be called from whithin your driver's isr()
* (as defined in eth_driver_t) for every layer 2 link state change.
*
* @param dev device that triggered the event
* @param newstate 1 for "link established", 0 for "link down"
*/
extern void dev_eth_linkstate_handler(dev_eth_t *dev, int newstate);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* DEV_ETH_H */

View File

@ -1,3 +0,0 @@
MODULE = gnrc_netdev_eth
include $(RIOTBASE)/Makefile.base

View File

@ -1,581 +0,0 @@
/*
* Copyright (C) 2015 Ludwig Ortmann <ludwig.ortmann@fu-berlin.de>,
* Martine Lenders <mlenders@inf.fu-berlin.de>
* Kaspar Schleiser <kaspar@schleiser.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 sys_net_link_layer
* @{
*
* @file
*
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de>
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "byteorder.h"
#include "net/eui64.h"
#include "net/ethernet.h"
#include "net/ethertype.h"
#include "net/ipv6/hdr.h"
#include "net/gnrc/netdev.h"
#include "net/gnrc/netif/hdr.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/netdev_eth.h"
#include "net/dev_eth.h"
#include "od.h"
#include "thread.h"
#include "utlist.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
gnrc_netdev_eth_t gnrc_netdev_eth;
static uint8_t send_buffer[ETHERNET_MAX_LEN];
static uint8_t recv_buffer[ETHERNET_MAX_LEN];
#define _ISR_EVENT_RX (1U)
/* driver function definitions */
static int _send_data(gnrc_netdev_t *netdev, gnrc_pktsnip_t *pkt);
static int _add_event_callback(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb);
static int _rem_event_callback(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb);
static int _get(gnrc_netdev_t *dev, netopt_t opt, void *value, size_t max_len);
static int _set(gnrc_netdev_t *dev, netopt_t opt, void *value, size_t value_len);
static void _isr_event(gnrc_netdev_t *dev, uint32_t event_type);
/* netdev driver struct */
const gnrc_netdev_driver_t gnrc_netdev_eth_driver = {
_send_data,
_add_event_callback,
_rem_event_callback,
_get,
_set,
_isr_event,
};
/* These functions are not used */
#if !(defined(__FreeBSD__) || defined(__MACH__))
/* internal function definitions */
static inline bool _is_addr_broadcast(uint8_t *addr)
{
return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) &&
(addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
}
static inline bool _is_addr_multicast(uint8_t *addr)
{
/* source: http://ieee802.org/secmail/pdfocSP2xXA6d.pdf */
return (addr[0] & 0x01);
}
#endif /* !(defined(__FreeBSD__) || defined(__MACH__)) */
/* build Ethernet packet from pkt */
static int _marshall_ethernet(gnrc_netdev_eth_t *dev, uint8_t *buffer, gnrc_pktsnip_t *pkt);
/* build ISR handler for ISR events */
void _trigger_isr_event(void);
static int _send_data(gnrc_netdev_t *netdev, gnrc_pktsnip_t *pkt)
{
int nsent, to_send;
gnrc_netdev_eth_t *dev = (gnrc_netdev_eth_t *)netdev;
DEBUG("gnrc_netdev_eth: send data ");
if (pkt == NULL) {
return -EFAULT;
}
if ((dev == NULL) || (netdev->driver != &gnrc_netdev_eth_driver)) {
DEBUG("[wrong device descriptor]\n");
gnrc_pktbuf_release(pkt);
return -ENODEV;
}
DEBUG("\n");
to_send = _marshall_ethernet(dev, send_buffer, pkt);
gnrc_pktbuf_release(pkt);
if (to_send < 0) {
errno = -to_send;
DEBUG("marshall\n");
return to_send;
}
DEBUG("gnrc_netdev_eth: send %d bytes\n", to_send);
#if defined(MODULE_OD) && ENABLE_DEBUG
od_hex_dump(send_buffer, to_send, OD_WIDTH_DEFAULT);
#endif
dev_eth_t *ethdev = dev->ethdev;
if ((nsent = ethdev->driver->send(ethdev, (char*)send_buffer, to_send)) < 0) {
DEBUG("write\n");
return -EIO;
}
return nsent;
}
static int _add_event_callback(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
{
DEBUG("gnrc_netdev_eth: add event callback");
if ((dev == NULL) || (dev->driver != &gnrc_netdev_eth_driver)) {
DEBUG(" [wrong device descriptor]\n");
return -ENODEV;
}
if (dev->event_cb != NULL) {
DEBUG(" [no space left]\n");
return -ENOBUFS;
}
DEBUG("\n");
dev->event_cb = cb;
return 0;
}
static int _rem_event_callback(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
{
DEBUG("gnrc_netdev_eth: remove event callback");
if ((dev == NULL) || (dev->driver != &gnrc_netdev_eth_driver)) {
DEBUG(" [wrong device descriptor]\n");
return -ENODEV;
}
if (dev->event_cb != cb) {
DEBUG(" [not found]\n");
return -ENOENT;
}
DEBUG("\n");
dev->event_cb = NULL;
return 0;
}
/* individual option getters to be called by _get() */
static inline int _get_addr(gnrc_netdev_eth_t *netdev, uint8_t *value, size_t max_len)
{
if (max_len < ETHERNET_ADDR_LEN) {
/* value buffer not big enough */
return -EOVERFLOW;
}
dev_eth_t *dev = netdev->ethdev;
dev->driver->get_mac_addr(dev, value);
return ETHERNET_ADDR_LEN;
}
static inline int _get_addr_len(uint16_t *value, size_t max_len)
{
if (max_len != sizeof(uint16_t)) {
/* value buffer not big enough */
return -EOVERFLOW;
}
*value = ETHERNET_ADDR_LEN;
return sizeof(uint16_t);
}
static inline int _get_iid(gnrc_netdev_eth_t *netdev, eui64_t *value, size_t max_len)
{
if (max_len < sizeof(eui64_t)) {
/* value buffer not big enough */
return -EOVERFLOW;
}
dev_eth_t *dev = netdev->ethdev;
uint8_t addr[ETHERNET_ADDR_LEN];
dev->driver->get_mac_addr(dev, addr);
ethernet_get_iid(value, addr);
return sizeof(eui64_t);
}
static inline int _get_max_pkt_sz(uint16_t *value, size_t max_len)
{
if (max_len != sizeof(uint16_t)) {
/* value buffer not big enough */
return -EOVERFLOW;
}
*value = ETHERNET_DATA_LEN;
return sizeof(uint16_t);
}
static inline int _get_promiscousmode(gnrc_netdev_eth_t *netdev, netopt_enable_t *value,
size_t max_len)
{
if (max_len != sizeof(netopt_enable_t)) {
/* value buffer not big enough */
return -EOVERFLOW;
}
dev_eth_t *dev = netdev->ethdev;
*value = (netopt_enable_t)dev->driver->get_promiscous(dev);
return sizeof(netopt_enable_t);
}
static int _get(gnrc_netdev_t *dev, netopt_t opt, void *value, size_t max_len)
{
DEBUG("gnrc_netdev_eth: get ");
if ((dev == NULL) || (dev->driver != &gnrc_netdev_eth_driver)) {
DEBUG("[wrong device descriptor]\n");
return -ENODEV;
}
switch (opt) {
case NETOPT_ADDRESS:
DEBUG("address\n");
return _get_addr((gnrc_netdev_eth_t *)dev, value, max_len);
case NETOPT_ADDR_LEN:
DEBUG("address length\n");
return _get_addr_len(value, max_len);
case NETOPT_IPV6_IID:
DEBUG("IPv6 IID\n");
return _get_iid((gnrc_netdev_eth_t *)dev, value, max_len);
case NETOPT_MAX_PACKET_SIZE:
DEBUG("maximum packet size\n");
return _get_max_pkt_sz(value, max_len);
case NETOPT_PROMISCUOUSMODE:
DEBUG("promiscous mode\n");
return _get_promiscousmode((gnrc_netdev_eth_t *)dev, value, max_len);
case NETOPT_IS_WIRED:
DEBUG("is wired\n");
return 1;
default:
DEBUG("[not supported: %d]\n", opt);
return -ENOTSUP;
}
}
/* individual option getters to be called by _get() */
static inline int _set_promiscousmode(gnrc_netdev_eth_t *netdev, netopt_enable_t *value,
size_t value_len)
{
if (value_len != sizeof(netopt_enable_t)) {
/* value buffer not big enough */
return -EOVERFLOW;
}
dev_eth_t *dev = netdev->ethdev;
dev->driver->set_promiscous(dev, (uint8_t)*value);
return sizeof(netopt_enable_t);
}
static int _set(gnrc_netdev_t *dev, netopt_t opt, void *value, size_t value_len)
{
DEBUG("gnrc_netdev_eth: set ");
if ((dev == NULL) || (dev->driver != &gnrc_netdev_eth_driver)) {
DEBUG("[wrong device descriptor]\n");
return -ENODEV;
}
switch (opt) {
case NETOPT_PROMISCUOUSMODE:
DEBUG("promiscous mode\n");
return _set_promiscousmode((gnrc_netdev_eth_t *)dev, value, value_len);
default:
DEBUG("[not supported: %d]\n", opt);
return -ENOTSUP;
}
}
/* individual event handlers called by _isr_event() */
static void _rx_event(gnrc_netdev_eth_t *dev);
static void _isr_event(gnrc_netdev_t *dev, uint32_t event_type)
{
DEBUG("gnrc_netdev_eth: ISR event ");
if ((dev == NULL) || (dev->driver != &gnrc_netdev_eth_driver)) {
return;
}
gnrc_netdev_eth_t *netdev = (gnrc_netdev_eth_t*)dev;
switch (event_type) {
case _ISR_EVENT_RX:
DEBUG("[ISR]\n");
#ifdef NETDEV_ETH_DELAY_SEND
DEBUG("netdev_eth: delaying send...\n");
volatile int i = NETDEV_ETH_DELAY_SEND;
while(i--);
DEBUG("netdev_eth: delay done.\n");
#endif
dev_eth_t *ethdev = netdev->ethdev;
ethdev->driver->isr(ethdev);
break;
default:
DEBUG("[unknown event_type]\n");
break;
}
}
static inline void _addr_set_broadcast(uint8_t *dst)
{
memset(dst, 0xff, ETHERNET_ADDR_LEN);
}
static inline void _addr_set_multicast(uint8_t *dst, gnrc_pktsnip_t *payload)
{
switch (payload->type) {
#ifdef MODULE_GNRC_IPV6
case GNRC_NETTYPE_IPV6:
dst[0] = 0x33;
dst[1] = 0x33;
if (payload->data != NULL) {
ipv6_hdr_t *hdr = payload->data;
uint16_t *prefix = (uint16_t *)(&dst[2]);
prefix[0] = hdr->dst.u16[6].u16;
prefix[1] = hdr->dst.u16[7].u16;
}
break;
#endif
default:
_addr_set_broadcast(dst);
break;
}
}
static int _marshall_ethernet(gnrc_netdev_eth_t *dev, uint8_t *buffer, gnrc_pktsnip_t *pkt)
{
int data_len = 0;
ethernet_hdr_t *hdr = (ethernet_hdr_t *)buffer;
gnrc_netif_hdr_t *netif_hdr;
gnrc_pktsnip_t *payload;
if (pkt == NULL) {
DEBUG("gnrc_netdev_eth: pkt was NULL");
return -EINVAL;
}
payload = pkt->next;
if (pkt->type != GNRC_NETTYPE_NETIF) {
DEBUG("gnrc_netdev_eth: First header was not generic netif header\n");
return -EBADMSG;
}
if (payload) {
hdr->type = byteorder_htons(gnrc_nettype_to_ethertype(payload->type));
}
else {
hdr->type = byteorder_htons(ETHERTYPE_UNKNOWN);
}
netif_hdr = pkt->data;
/* set ethernet header */
if (netif_hdr->src_l2addr_len == ETHERNET_ADDR_LEN) {
memcpy(hdr->dst, gnrc_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
}
else {
dev_eth_t *ethdev = dev->ethdev;
ethdev->driver->get_mac_addr(ethdev, hdr->src);
}
if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) {
_addr_set_broadcast(hdr->dst);
}
else if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST) {
if (payload == NULL) {
DEBUG("gnrc_netdev_eth: empty multicast packets over Ethernet are "\
"not yet supported\n");
return -ENOTSUP;
}
_addr_set_multicast(hdr->dst, payload);
}
else if (netif_hdr->dst_l2addr_len == ETHERNET_ADDR_LEN) {
memcpy(hdr->dst, gnrc_netif_hdr_get_dst_addr(netif_hdr),
ETHERNET_ADDR_LEN);
}
else {
DEBUG("gnrc_netdev_eth: destination address had unexpected format\n");
return -EBADMSG;
}
DEBUG("gnrc_netdev_eth: send to %02x:%02x:%02x:%02x:%02x:%02x\n",
hdr->dst[0], hdr->dst[1], hdr->dst[2],
hdr->dst[3], hdr->dst[4], hdr->dst[5]);
data_len += sizeof(ethernet_hdr_t);
while (payload != NULL) {
if ((data_len + payload->size) > ETHERNET_MAX_LEN) {
DEBUG("gnrc_netdev_eth: Packet too big for ethernet frame\n");
return -ENOBUFS;
}
memcpy(send_buffer + data_len, payload->data, payload->size);
data_len += payload->size;
payload = payload->next;
}
/* Pad to minimum payload size.
* Linux does this on its own, but it doesn't hurt to do it here.
* As of now only tuntaposx needs this. */
if (data_len < (ETHERNET_MIN_LEN)) {
DEBUG("gnrc_netdev_eth: padding data! (%d -> ", data_len);
memset(send_buffer + data_len, 0, ETHERNET_MIN_LEN - data_len);
data_len = ETHERNET_MIN_LEN;
DEBUG("%d)\n", data_len);
}
return data_len;
}
void dev_eth_isr(dev_eth_t* dev)
{
(void)dev;
msg_t msg;
DEBUG("gnrc_netdev_eth: Trigger ISR event\n");
/* TODO: check whether this is an input or an output event
TODO: refactor this into general io-signal multiplexer */
msg.type = GNRC_NETDEV_MSG_TYPE_EVENT;
msg.content.value = _ISR_EVENT_RX;
if (msg_send(&msg, gnrc_netdev_eth.mac_pid) <= 0) {
puts("dev_eth_isr: possibly lost interrupt.");
}
}
void dev_eth_rx_handler(dev_eth_t* dev) {
(void)dev;
_rx_event(&gnrc_netdev_eth);
}
void dev_eth_linkstate_handler(dev_eth_t *dev, int newstate)
{
DEBUG("gnrc_dev_eth: dev=0x%08x link %s\n", (unsigned)dev, newstate ? "UP" : "DOWN");
(void)dev; (void)newstate;
}
static void _rx_event(gnrc_netdev_eth_t *netdev)
{
dev_eth_t *dev = netdev->ethdev;
int nread = dev->driver->recv(dev, (char*)recv_buffer, ETHERNET_MAX_LEN);
DEBUG("gnrc_netdev_eth: read %d bytes\n", nread);
if (nread > 0) {
ethernet_hdr_t *hdr = (ethernet_hdr_t *)recv_buffer;
gnrc_pktsnip_t *netif_hdr, *pkt;
gnrc_nettype_t receive_type = GNRC_NETTYPE_UNDEF;
size_t data_len = (nread - sizeof(ethernet_hdr_t));
/* TODO: implement multicast groups? */
netif_hdr = gnrc_pktbuf_add(NULL, NULL,
sizeof(gnrc_netif_hdr_t) + (2 * ETHERNET_ADDR_LEN),
GNRC_NETTYPE_NETIF);
if (netif_hdr == NULL) {
DEBUG("gnrc_netdev_eth: no space left in packet buffer\n");
return;
}
gnrc_netif_hdr_init(netif_hdr->data, ETHERNET_ADDR_LEN, ETHERNET_ADDR_LEN);
gnrc_netif_hdr_set_src_addr(netif_hdr->data, hdr->src, ETHERNET_ADDR_LEN);
gnrc_netif_hdr_set_dst_addr(netif_hdr->data, hdr->dst, ETHERNET_ADDR_LEN);
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = thread_getpid();
receive_type = gnrc_nettype_from_ethertype(byteorder_ntohs(hdr->type));
DEBUG("gnrc_netdev_eth: received packet from %02x:%02x:%02x:%02x:%02x:%02x "
"of length %zu\n",
hdr->src[0], hdr->src[1], hdr->src[2], hdr->src[3], hdr->src[4],
hdr->src[5], data_len);
#if defined(MODULE_OD) && ENABLE_DEBUG
od_hex_dump(hdr, nread, OD_WIDTH_DEFAULT);
#endif
/* Mark netif header and payload for next layer */
if ((pkt = gnrc_pktbuf_add(netif_hdr, recv_buffer + sizeof(ethernet_hdr_t),
data_len, receive_type)) == NULL) {
gnrc_pktbuf_release(netif_hdr);
DEBUG("gnrc_netdev_eth: no space left in packet buffer\n");
return;
}
if (netdev->event_cb != NULL) {
netdev->event_cb(NETDEV_EVENT_RX_COMPLETE, pkt);
}
else {
gnrc_pktbuf_release(pkt); /* netif_hdr is released automatically too */
}
}
else {
DEBUG("gnrc_netdev_eth: spurious _rx_event: %d\n", nread);
}
}
int gnrc_netdev_eth_init(gnrc_netdev_eth_t *netdev, dev_eth_t *ethdev)
{
if ((netdev == NULL) || (ethdev == NULL) || (netdev != &gnrc_netdev_eth)) {
return -ENODEV;
}
/* initialize low-level driver */
dev_eth_init(ethdev);
/* initialize device descriptor */
netdev->driver = (gnrc_netdev_driver_t *)(&gnrc_netdev_eth_driver);
netdev->ethdev = ethdev;
DEBUG("gnrc_netdev_eth: initialized.\n");
return 0;
}
/**
* @}
*/