zephyr/drivers/ieee802154/ieee802154_uart_pipe.c
Jukka Rissanen d32503f57e net: nbuf: Split one global DATA pool to RX and TX DATA pools
If we receive lot of packets, it might happen that we exhaust
all the DATA buffers in the system. This would prevent from
us sending anything to the network.
Change this by splitting the DATA buffer pool into RX and TX
parts. This way RX flooding cannot consume all DATA buffers
that needs to be sent.

Change-Id: I8e8934c6d5fdd47b579ffa6268721b5eb3d64b6d
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
2017-03-09 20:33:43 +02:00

290 lines
5.4 KiB
C

/*
* Copyright (c) 2016 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL
#define SYS_LOG_DOMAIN "net/ieee802154/upipe/"
#include <logging/sys_log.h>
#include <errno.h>
#include <kernel.h>
#include <arch/cpu.h>
#include <board.h>
#include <device.h>
#include <init.h>
#include <net/net_if.h>
#include <net/nbuf.h>
#include <console/uart_pipe.h>
#include <net/ieee802154_radio.h>
#include "ieee802154_uart_pipe.h"
/** Singleton device used in uart pipe callback */
static struct device *upipe_dev;
static uint8_t *upipe_rx(uint8_t *buf, size_t *off)
{
struct upipe_context *upipe = upipe_dev->driver_data;
struct net_buf *pkt_buf = NULL;
struct net_buf *nbuf = NULL;
if (!upipe_dev) {
goto done;
}
if (!upipe->rx && *buf == UART_PIPE_RADIO_15_4_FRAME_TYPE) {
upipe->rx = true;
goto done;
}
if (!upipe->rx_len) {
if (*buf > 127) {
goto flush;
}
upipe->rx_len = *buf;
goto done;
}
upipe->rx_buf[upipe->rx_off++] = *buf;
if (upipe->rx_len == upipe->rx_off) {
nbuf = net_nbuf_get_reserve_rx(0, K_NO_WAIT);
if (!nbuf) {
SYS_LOG_DBG("No buf available");
goto flush;
}
pkt_buf = net_nbuf_get_reserve_rx_data(0, K_NO_WAIT);
if (!pkt_buf) {
SYS_LOG_DBG("No fragment available");
goto out;
}
net_buf_frag_insert(nbuf, pkt_buf);
memcpy(pkt_buf->data, upipe->rx_buf, upipe->rx_len - 2);
net_buf_add(pkt_buf, upipe->rx_len - 2);
if (ieee802154_radio_handle_ack(upipe->iface, nbuf) == NET_OK) {
SYS_LOG_DBG("ACK packet handled");
goto out;
}
SYS_LOG_DBG("Caught a packet (%u)", upipe->rx_len);
if (net_recv_data(upipe->iface, nbuf) < 0) {
SYS_LOG_DBG("Packet dropped by NET stack");
goto out;
}
goto flush;
out:
net_nbuf_unref(nbuf);
flush:
upipe->rx = false;
upipe->rx_len = 0;
upipe->rx_off = 0;
}
done:
*off = 0;
return buf;
}
static int upipe_cca(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_channel(struct device *dev, uint16_t channel)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_pan_id(struct device *dev, uint16_t pan_id)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_short_addr(struct device *dev, uint16_t short_addr)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_ieee_addr(struct device *dev, const uint8_t *ieee_addr)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_set_txpower(struct device *dev, int16_t dbm)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EIO;
}
return 0;
}
static int upipe_tx(struct device *dev,
struct net_buf *buf,
struct net_buf *frag)
{
uint8_t *pkt_buf = frag->data - net_nbuf_ll_reserve(buf);
uint8_t len = net_nbuf_ll_reserve(buf) + frag->len;
struct upipe_context *upipe = dev->driver_data;
uint8_t i, data;
SYS_LOG_DBG("%p (%u)", frag, len);
if (upipe->stopped) {
return -EIO;
}
data = UART_PIPE_RADIO_15_4_FRAME_TYPE;
uart_pipe_send(&data, 1);
data = len + 2;
uart_pipe_send(&data, 1);
for (i = 0; i < len; i++) {
uart_pipe_send(pkt_buf+i, 1);
}
/* The 2 dummy bytes representing FCS */
data = 0xFF;
uart_pipe_send(&data, 1);
uart_pipe_send(&data, 1);
return 0;
}
static int upipe_start(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
if (!upipe->stopped) {
return -EALREADY;
}
upipe->stopped = false;
return 0;
}
static int upipe_stop(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
if (upipe->stopped) {
return -EALREADY;
}
upipe->stopped = true;
return 0;
}
static int upipe_init(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
memset(upipe, 0, sizeof(struct upipe_context));
uart_pipe_register(upipe->uart_pipe_buf, 1, upipe_rx);
upipe_stop(dev);
return 0;
}
static inline uint8_t *get_mac(struct device *dev)
{
struct upipe_context *upipe = dev->driver_data;
upipe->mac_addr[0] = 0x00;
upipe->mac_addr[1] = 0x10;
upipe->mac_addr[2] = 0x20;
upipe->mac_addr[3] = 0x30;
UNALIGNED_PUT(sys_cpu_to_be32(sys_rand32_get()),
(uint32_t *) ((void *)upipe->mac_addr+4));
return upipe->mac_addr;
}
static void upipe_iface_init(struct net_if *iface)
{
struct device *dev = net_if_get_device(iface);
struct upipe_context *upipe = dev->driver_data;
uint8_t *mac = get_mac(dev);
SYS_LOG_DBG("");
net_if_set_link_addr(iface, mac, 8, NET_LINK_IEEE802154);
upipe_dev = dev;
upipe->iface = iface;
ieee802154_init(iface);
}
static struct upipe_context upipe_context_data;
static struct ieee802154_radio_api upipe_radio_api = {
.iface_api.init = upipe_iface_init,
.iface_api.send = ieee802154_radio_send,
.cca = upipe_cca,
.set_channel = upipe_set_channel,
.set_pan_id = upipe_set_pan_id,
.set_short_addr = upipe_set_short_addr,
.set_ieee_addr = upipe_set_ieee_addr,
.set_txpower = upipe_set_txpower,
.tx = upipe_tx,
.start = upipe_start,
.stop = upipe_stop,
};
NET_DEVICE_INIT(upipe_15_4, CONFIG_IEEE802154_UPIPE_DRV_NAME,
upipe_init, &upipe_context_data, NULL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&upipe_radio_api, IEEE802154_L2,
NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125);