2015-08-21 16:06:57 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
|
|
|
* 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 net
|
|
|
|
* @file
|
2017-02-15 13:07:34 +01:00
|
|
|
* @brief Glue for netdev devices to netapi
|
2015-08-21 16:06:57 +02:00
|
|
|
*
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "msg.h"
|
|
|
|
#include "thread.h"
|
|
|
|
|
|
|
|
#include "net/gnrc.h"
|
|
|
|
#include "net/gnrc/nettype.h"
|
2017-02-15 13:07:34 +01:00
|
|
|
#include "net/netdev.h"
|
2015-08-21 16:06:57 +02:00
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
#include "net/gnrc/netdev.h"
|
2015-08-21 16:06:57 +02:00
|
|
|
#include "net/ethernet/hdr.h"
|
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
#if defined(MODULE_OD) && ENABLE_DEBUG
|
|
|
|
#include "od.h"
|
|
|
|
#endif
|
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
#define NETDEV_NETAPI_MSG_QUEUE_SIZE 8
|
2015-08-21 16:06:57 +02:00
|
|
|
|
|
|
|
static void _pass_on_packet(gnrc_pktsnip_t *pkt);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Function called by the device driver on device events
|
|
|
|
*
|
|
|
|
* @param[in] event type of event
|
|
|
|
*/
|
2017-02-15 13:07:34 +01:00
|
|
|
static void _event_cb(netdev_t *dev, netdev_event_t event)
|
2015-08-21 16:06:57 +02:00
|
|
|
{
|
2017-02-15 13:07:34 +01:00
|
|
|
gnrc_netdev_t *gnrc_netdev = (gnrc_netdev_t*) dev->context;
|
2015-08-21 16:06:57 +02:00
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
if (event == NETDEV_EVENT_ISR) {
|
2015-08-21 16:06:57 +02:00
|
|
|
msg_t msg;
|
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
msg.type = NETDEV_MSG_TYPE_EVENT;
|
|
|
|
msg.content.ptr = gnrc_netdev;
|
2015-08-21 16:06:57 +02:00
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
if (msg_send(&msg, gnrc_netdev->pid) <= 0) {
|
|
|
|
puts("gnrc_netdev: possibly lost interrupt.");
|
2015-08-21 16:06:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: event triggered -> %i\n", event);
|
2015-08-21 16:06:57 +02:00
|
|
|
switch(event) {
|
2017-02-15 13:07:34 +01:00
|
|
|
case NETDEV_EVENT_RX_COMPLETE:
|
2015-08-21 16:06:57 +02:00
|
|
|
{
|
2017-02-15 13:07:34 +01:00
|
|
|
gnrc_pktsnip_t *pkt = gnrc_netdev->recv(gnrc_netdev);
|
2015-08-21 16:06:57 +02:00
|
|
|
|
|
|
|
if (pkt) {
|
|
|
|
_pass_on_packet(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2016-02-11 23:06:07 +01:00
|
|
|
#ifdef MODULE_NETSTATS_L2
|
2017-02-15 13:07:34 +01:00
|
|
|
case NETDEV_EVENT_TX_MEDIUM_BUSY:
|
2016-02-11 23:06:07 +01:00
|
|
|
dev->stats.tx_failed++;
|
|
|
|
break;
|
2017-02-15 13:07:34 +01:00
|
|
|
case NETDEV_EVENT_TX_COMPLETE:
|
2016-02-11 23:06:07 +01:00
|
|
|
dev->stats.tx_success++;
|
|
|
|
break;
|
|
|
|
#endif
|
2015-08-21 16:06:57 +02:00
|
|
|
default:
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: warning: unhandled event %u.\n", event);
|
2015-08-21 16:06:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _pass_on_packet(gnrc_pktsnip_t *pkt)
|
|
|
|
{
|
|
|
|
/* throw away packet if no one is interested */
|
2015-09-29 16:58:08 +02:00
|
|
|
if (!gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: unable to forward packet of type %i\n", pkt->type);
|
2015-08-21 16:06:57 +02:00
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-02-15 13:07:34 +01:00
|
|
|
* @brief Startup code and event loop of the gnrc_netdev layer
|
2015-08-21 16:06:57 +02:00
|
|
|
*
|
|
|
|
* @param[in] args expects a pointer to the underlying netdev device
|
|
|
|
*
|
|
|
|
* @return never returns
|
|
|
|
*/
|
2017-02-15 13:07:34 +01:00
|
|
|
static void *_gnrc_netdev_thread(void *args)
|
2015-08-21 16:06:57 +02:00
|
|
|
{
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: starting thread\n");
|
2015-08-21 16:06:57 +02:00
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
gnrc_netdev_t *gnrc_netdev = (gnrc_netdev_t*) args;
|
|
|
|
netdev_t *dev = gnrc_netdev->dev;
|
2015-08-21 16:06:57 +02:00
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
gnrc_netdev->pid = thread_getpid();
|
2015-08-21 16:06:57 +02:00
|
|
|
|
|
|
|
gnrc_netapi_opt_t *opt;
|
|
|
|
int res;
|
2017-02-15 13:07:34 +01:00
|
|
|
msg_t msg, reply, msg_queue[NETDEV_NETAPI_MSG_QUEUE_SIZE];
|
2015-08-21 16:06:57 +02:00
|
|
|
|
|
|
|
/* setup the MAC layers message queue */
|
2017-02-15 13:07:34 +01:00
|
|
|
msg_init_queue(msg_queue, NETDEV_NETAPI_MSG_QUEUE_SIZE);
|
2015-08-21 16:06:57 +02:00
|
|
|
|
|
|
|
/* register the event callback with the device driver */
|
|
|
|
dev->event_callback = _event_cb;
|
2017-02-15 13:07:34 +01:00
|
|
|
dev->context = (void*) gnrc_netdev;
|
2015-08-21 16:06:57 +02:00
|
|
|
|
|
|
|
/* register the device to the network stack*/
|
|
|
|
gnrc_netif_add(thread_getpid());
|
|
|
|
|
|
|
|
/* initialize low-level driver */
|
|
|
|
dev->driver->init(dev);
|
|
|
|
|
|
|
|
/* start the event loop */
|
|
|
|
while (1) {
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: waiting for incoming messages\n");
|
2015-08-21 16:06:57 +02:00
|
|
|
msg_receive(&msg);
|
|
|
|
/* dispatch NETDEV and NETAPI messages */
|
|
|
|
switch (msg.type) {
|
2017-02-15 13:07:34 +01:00
|
|
|
case NETDEV_MSG_TYPE_EVENT:
|
|
|
|
DEBUG("gnrc_netdev: GNRC_NETDEV_MSG_TYPE_EVENT received\n");
|
2015-08-21 16:06:57 +02:00
|
|
|
dev->driver->isr(dev);
|
|
|
|
break;
|
|
|
|
case GNRC_NETAPI_MSG_TYPE_SND:
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: GNRC_NETAPI_MSG_TYPE_SND received\n");
|
2016-06-02 20:40:15 +02:00
|
|
|
gnrc_pktsnip_t *pkt = msg.content.ptr;
|
2017-02-15 13:07:34 +01:00
|
|
|
gnrc_netdev->send(gnrc_netdev, pkt);
|
2015-08-21 16:06:57 +02:00
|
|
|
break;
|
|
|
|
case GNRC_NETAPI_MSG_TYPE_SET:
|
|
|
|
/* read incoming options */
|
2016-06-02 20:40:15 +02:00
|
|
|
opt = msg.content.ptr;
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: GNRC_NETAPI_MSG_TYPE_SET received. opt=%s\n",
|
2015-08-21 16:06:57 +02:00
|
|
|
netopt2str(opt->opt));
|
|
|
|
/* set option for device driver */
|
|
|
|
res = dev->driver->set(dev, opt->opt, opt->data, opt->data_len);
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: response of netdev->set: %i\n", res);
|
2015-08-21 16:06:57 +02:00
|
|
|
/* send reply to calling thread */
|
|
|
|
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
|
|
|
|
reply.content.value = (uint32_t)res;
|
|
|
|
msg_reply(&msg, &reply);
|
|
|
|
break;
|
|
|
|
case GNRC_NETAPI_MSG_TYPE_GET:
|
|
|
|
/* read incoming options */
|
2016-06-02 20:40:15 +02:00
|
|
|
opt = msg.content.ptr;
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: GNRC_NETAPI_MSG_TYPE_GET received. opt=%s\n",
|
2015-08-21 16:06:57 +02:00
|
|
|
netopt2str(opt->opt));
|
|
|
|
/* get option from device driver */
|
|
|
|
res = dev->driver->get(dev, opt->opt, opt->data, opt->data_len);
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: response of netdev->get: %i\n", res);
|
2015-08-21 16:06:57 +02:00
|
|
|
/* send reply to calling thread */
|
|
|
|
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
|
|
|
|
reply.content.value = (uint32_t)res;
|
|
|
|
msg_reply(&msg, &reply);
|
|
|
|
break;
|
|
|
|
default:
|
2017-02-15 13:07:34 +01:00
|
|
|
DEBUG("gnrc_netdev: Unknown command %" PRIu16 "\n", msg.type);
|
2015-08-21 16:06:57 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* never reached */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
kernel_pid_t gnrc_netdev_init(char *stack, int stacksize, char priority,
|
|
|
|
const char *name, gnrc_netdev_t *gnrc_netdev)
|
2015-08-21 16:06:57 +02:00
|
|
|
{
|
|
|
|
kernel_pid_t res;
|
|
|
|
|
|
|
|
/* check if given netdev device is defined and the driver is set */
|
2017-02-15 13:07:34 +01:00
|
|
|
if (gnrc_netdev == NULL || gnrc_netdev->dev == NULL) {
|
2015-08-21 16:06:57 +02:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2017-02-15 13:07:34 +01:00
|
|
|
/* create new gnrc_netdev thread */
|
2015-12-02 12:00:19 +01:00
|
|
|
res = thread_create(stack, stacksize, priority, THREAD_CREATE_STACKTEST,
|
2017-02-15 13:07:34 +01:00
|
|
|
_gnrc_netdev_thread, (void *)gnrc_netdev, name);
|
2015-08-21 16:06:57 +02:00
|
|
|
if (res <= 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|