2016-08-17 16:48:36 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Intel Corporation.
|
|
|
|
*
|
2017-01-19 02:01:01 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2016-08-17 16:48:36 +02:00
|
|
|
*/
|
|
|
|
|
2017-01-10 14:24:01 +01:00
|
|
|
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL
|
2016-08-17 16:48:36 +02:00
|
|
|
#define SYS_LOG_DOMAIN "net/ieee802154/upipe/"
|
2016-12-17 18:56:56 +01:00
|
|
|
#include <logging/sys_log.h>
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
2016-11-09 16:53:16 +01:00
|
|
|
#include <kernel.h>
|
2016-08-17 16:48:36 +02:00
|
|
|
#include <arch/cpu.h>
|
|
|
|
|
|
|
|
#include <board.h>
|
|
|
|
#include <device.h>
|
|
|
|
#include <init.h>
|
|
|
|
#include <net/net_if.h>
|
2017-04-03 17:14:35 +02:00
|
|
|
#include <net/net_pkt.h>
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
#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;
|
|
|
|
|
2017-04-21 16:27:50 +02:00
|
|
|
static u8_t *upipe_rx(u8_t *buf, size_t *off)
|
2016-08-17 16:48:36 +02:00
|
|
|
{
|
|
|
|
struct upipe_context *upipe = upipe_dev->driver_data;
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_pkt *pkt = NULL;
|
|
|
|
struct net_buf *frag = NULL;
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
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) {
|
2017-04-03 17:14:35 +02:00
|
|
|
pkt = net_pkt_get_reserve_rx(0, K_NO_WAIT);
|
|
|
|
if (!pkt) {
|
2017-04-05 08:37:44 +02:00
|
|
|
SYS_LOG_DBG("No pkt available");
|
2016-08-17 16:48:36 +02:00
|
|
|
goto flush;
|
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
frag = net_pkt_get_frag(pkt, K_NO_WAIT);
|
|
|
|
if (!frag) {
|
2016-08-17 16:48:36 +02:00
|
|
|
SYS_LOG_DBG("No fragment available");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
net_pkt_frag_insert(pkt, frag);
|
2016-08-17 16:48:36 +02:00
|
|
|
|
2017-10-18 16:37:08 +02:00
|
|
|
memcpy(frag->data, upipe->rx_buf, upipe->rx_len);
|
|
|
|
net_buf_add(frag, upipe->rx_len);
|
2016-08-17 16:48:36 +02:00
|
|
|
|
2017-04-03 17:14:35 +02:00
|
|
|
if (ieee802154_radio_handle_ack(upipe->iface, pkt) == NET_OK) {
|
2016-08-17 16:48:36 +02:00
|
|
|
SYS_LOG_DBG("ACK packet handled");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-11-03 15:45:26 +01:00
|
|
|
SYS_LOG_DBG("Caught a packet (%u)", upipe->rx_len);
|
2017-04-03 17:14:35 +02:00
|
|
|
if (net_recv_data(upipe->iface, pkt) < 0) {
|
2016-08-17 16:48:36 +02:00
|
|
|
SYS_LOG_DBG("Packet dropped by NET stack");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto flush;
|
|
|
|
out:
|
2017-04-03 17:14:35 +02:00
|
|
|
net_pkt_unref(pkt);
|
2016-08-17 16:48:36 +02:00
|
|
|
flush:
|
|
|
|
upipe->rx = false;
|
|
|
|
upipe->rx_len = 0;
|
|
|
|
upipe->rx_off = 0;
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
*off = 0;
|
|
|
|
|
2017-10-04 08:54:20 +02:00
|
|
|
return buf;
|
2016-08-17 16:48:36 +02:00
|
|
|
}
|
|
|
|
|
2017-09-04 15:24:36 +02:00
|
|
|
static enum ieee802154_hw_caps upipe_get_capabilities(struct device *dev)
|
|
|
|
{
|
|
|
|
return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ;
|
|
|
|
}
|
|
|
|
|
2016-08-17 16:48:36 +02:00
|
|
|
static int upipe_cca(struct device *dev)
|
|
|
|
{
|
|
|
|
struct upipe_context *upipe = dev->driver_data;
|
|
|
|
|
|
|
|
if (upipe->stopped) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-21 16:27:50 +02:00
|
|
|
static int upipe_set_channel(struct device *dev, u16_t channel)
|
2016-08-17 16:48:36 +02:00
|
|
|
{
|
|
|
|
struct upipe_context *upipe = dev->driver_data;
|
|
|
|
|
|
|
|
if (upipe->stopped) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-21 16:27:50 +02:00
|
|
|
static int upipe_set_txpower(struct device *dev, s16_t dbm)
|
2016-08-17 16:48:36 +02:00
|
|
|
{
|
|
|
|
struct upipe_context *upipe = dev->driver_data;
|
|
|
|
|
|
|
|
if (upipe->stopped) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
net/ieee802154: Modify radio TX function signature
The cause for this change is TCP. Until now, the radio strategy driver
(ALOHA or CSMA) was providing the actual nbuf, and not the buffer
fragment, counting on the fact that the loop was using
net_buf_frag_del() which made so, iteration after iteration, buffer
framgent to be always buf->frags. The problem with this logic is loosing
the fragments that might be still referenced by TCP, in case the whole
buffer did not make it so TCP can retry later and so on.
Instead, TX now takes the nbuf and the actual frag to send. It could
have been working with just a pointer on the data, and the whole length
of the frame. But it has been avoided due to possible future devices,
that will be smarter and run CSMA directly in the hw, thus it will
require to access the whole buffer list through the nbuf.
Change-Id: I8d77b1e13b648c0ec3645cb2d55d1910d00381ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2017-01-26 14:31:30 +01:00
|
|
|
static int upipe_tx(struct device *dev,
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_pkt *pkt,
|
net/ieee802154: Modify radio TX function signature
The cause for this change is TCP. Until now, the radio strategy driver
(ALOHA or CSMA) was providing the actual nbuf, and not the buffer
fragment, counting on the fact that the loop was using
net_buf_frag_del() which made so, iteration after iteration, buffer
framgent to be always buf->frags. The problem with this logic is loosing
the fragments that might be still referenced by TCP, in case the whole
buffer did not make it so TCP can retry later and so on.
Instead, TX now takes the nbuf and the actual frag to send. It could
have been working with just a pointer on the data, and the whole length
of the frame. But it has been avoided due to possible future devices,
that will be smarter and run CSMA directly in the hw, thus it will
require to access the whole buffer list through the nbuf.
Change-Id: I8d77b1e13b648c0ec3645cb2d55d1910d00381ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2017-01-26 14:31:30 +01:00
|
|
|
struct net_buf *frag)
|
2016-08-17 16:48:36 +02:00
|
|
|
{
|
2017-04-21 16:27:50 +02:00
|
|
|
u8_t *pkt_buf = frag->data - net_pkt_ll_reserve(pkt);
|
|
|
|
u8_t len = net_pkt_ll_reserve(pkt) + frag->len;
|
2016-08-17 16:48:36 +02:00
|
|
|
struct upipe_context *upipe = dev->driver_data;
|
2017-04-21 16:27:50 +02:00
|
|
|
u8_t i, data;
|
2016-08-17 16:48:36 +02:00
|
|
|
|
net/ieee802154: Modify radio TX function signature
The cause for this change is TCP. Until now, the radio strategy driver
(ALOHA or CSMA) was providing the actual nbuf, and not the buffer
fragment, counting on the fact that the loop was using
net_buf_frag_del() which made so, iteration after iteration, buffer
framgent to be always buf->frags. The problem with this logic is loosing
the fragments that might be still referenced by TCP, in case the whole
buffer did not make it so TCP can retry later and so on.
Instead, TX now takes the nbuf and the actual frag to send. It could
have been working with just a pointer on the data, and the whole length
of the frame. But it has been avoided due to possible future devices,
that will be smarter and run CSMA directly in the hw, thus it will
require to access the whole buffer list through the nbuf.
Change-Id: I8d77b1e13b648c0ec3645cb2d55d1910d00381ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2017-01-26 14:31:30 +01:00
|
|
|
SYS_LOG_DBG("%p (%u)", frag, len);
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
if (upipe->stopped) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = UART_PIPE_RADIO_15_4_FRAME_TYPE;
|
|
|
|
uart_pipe_send(&data, 1);
|
|
|
|
|
2017-10-18 16:37:08 +02:00
|
|
|
data = len;
|
2016-08-17 16:48:36 +02:00
|
|
|
uart_pipe_send(&data, 1);
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
uart_pipe_send(pkt_buf+i, 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;
|
|
|
|
}
|
|
|
|
|
2017-04-21 16:27:50 +02:00
|
|
|
static inline u8_t *get_mac(struct device *dev)
|
2016-08-17 16:48:36 +02:00
|
|
|
{
|
|
|
|
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()),
|
2017-04-21 16:27:50 +02:00
|
|
|
(u32_t *) ((void *)upipe->mac_addr+4));
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
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;
|
2017-04-21 16:27:50 +02:00
|
|
|
u8_t *mac = get_mac(dev);
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
SYS_LOG_DBG("");
|
|
|
|
|
2017-02-15 12:20:31 +01:00
|
|
|
net_if_set_link_addr(iface, mac, 8, NET_LINK_IEEE802154);
|
2016-08-17 16:48:36 +02:00
|
|
|
|
|
|
|
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,
|
|
|
|
|
2017-09-04 15:24:36 +02:00
|
|
|
.get_capabilities = upipe_get_capabilities,
|
2016-08-17 16:48:36 +02:00
|
|
|
.cca = upipe_cca,
|
|
|
|
.set_channel = upipe_set_channel,
|
|
|
|
.set_txpower = upipe_set_txpower,
|
|
|
|
.tx = upipe_tx,
|
|
|
|
.start = upipe_start,
|
|
|
|
.stop = upipe_stop,
|
|
|
|
};
|
|
|
|
|
2017-02-06 11:49:16 +01:00
|
|
|
NET_DEVICE_INIT(upipe_15_4, CONFIG_IEEE802154_UPIPE_DRV_NAME,
|
2016-08-17 16:48:36 +02:00
|
|
|
upipe_init, &upipe_context_data, NULL,
|
|
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
|
|
|
&upipe_radio_api, IEEE802154_L2,
|
2016-11-16 11:48:40 +01:00
|
|
|
NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125);
|