1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/netdev_ieee802154/netdev_ieee802154.c
Benjamin Valentin cfc2feca1d ieee802154: return PDU based on PHY mode
IEEE 802.15.4g-2012 specifies a PDU of 2047 for it's PHY modes, so
query the driver for the mode before returning the PDU.

If none of the new modes is used, don't query the driver to not incure
a penalty on existing platforms.
2020-04-29 10:41:37 +02:00

314 lines
9.6 KiB
C

/*
* Copyright (C) 2016 Freie Universität Berlin
*
* 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 drivers_netdev_ieee802154
* @{
*
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include "net/eui64.h"
#include "net/ieee802154.h"
#include "net/netdev.h"
#include "random.h"
#include "net/netdev/ieee802154.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static int _get_iid(netdev_ieee802154_t *dev, eui64_t *value, size_t max_len)
{
(void)max_len;
uint8_t addr[IEEE802154_LONG_ADDRESS_LEN];
uint16_t addr_len;
assert(max_len >= sizeof(eui64_t));
dev->netdev.driver->get(&dev->netdev, NETOPT_SRC_LEN, &addr_len,
sizeof(addr_len));
if (addr_len == IEEE802154_LONG_ADDRESS_LEN) {
dev->netdev.driver->get(&dev->netdev, NETOPT_ADDRESS_LONG, addr,
addr_len);
}
else {
dev->netdev.driver->get(&dev->netdev, NETOPT_ADDRESS, addr,
addr_len);
}
ieee802154_get_iid(value, addr, addr_len);
return sizeof(eui64_t);
}
void netdev_ieee802154_reset(netdev_ieee802154_t *dev)
{
/* Only the least significant byte of the random value is used */
dev->seq = random_uint32();
dev->flags = 0;
/* set default protocol */
#ifdef MODULE_GNRC_SIXLOWPAN
dev->proto = GNRC_NETTYPE_SIXLOWPAN;
#elif MODULE_GNRC
dev->proto = GNRC_NETTYPE_UNDEF;
#endif
/* Initialize PAN ID and call netdev::set to propagate it */
dev->pan = CONFIG_IEEE802154_DEFAULT_PANID;
dev->netdev.driver->set(&dev->netdev, NETOPT_NID, &dev->pan, sizeof(dev->pan));
}
static inline uint16_t _get_ieee802154_pdu(netdev_ieee802154_t *dev)
{
#if defined(MODULE_NETDEV_IEEE802154_MR_OQPSK) || \
defined(MODULE_NETDEV_IEEE802154_MR_OFDM) || \
defined(MODULE_NETDEV_IEEE802154_MR_FSK)
uint8_t type = IEEE802154_PHY_DISABLED;
dev->netdev.driver->get(&dev->netdev, NETOPT_IEEE802154_PHY, &type, sizeof(type));
#else
(void) dev;
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
if (type == IEEE802154_PHY_MR_OQPSK) {
return IEEE802154G_FRAME_LEN_MAX;
}
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
if (type == IEEE802154_PHY_MR_OFDM) {
return IEEE802154G_FRAME_LEN_MAX;
}
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
if (type == IEEE802154_PHY_MR_FSK) {
return IEEE802154G_FRAME_LEN_MAX;
}
#endif
return IEEE802154_FRAME_LEN_MAX;
}
int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value,
size_t max_len)
{
int res = -ENOTSUP;
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len >= sizeof(dev->short_addr));
memcpy(value, dev->short_addr, sizeof(dev->short_addr));
res = sizeof(dev->short_addr);
break;
case NETOPT_ADDRESS_LONG:
assert(max_len >= sizeof(dev->long_addr));
memcpy(value, dev->long_addr, sizeof(dev->long_addr));
res = sizeof(dev->long_addr);
break;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
assert(max_len == sizeof(uint16_t));
if (dev->flags & NETDEV_IEEE802154_SRC_MODE_LONG) {
*((uint16_t *)value) = IEEE802154_LONG_ADDRESS_LEN;
}
else {
*((uint16_t *)value) = IEEE802154_SHORT_ADDRESS_LEN;
}
res = sizeof(uint16_t);
break;
case NETOPT_NID:
assert(max_len == sizeof(dev->pan));
*((uint16_t *)value) = dev->pan;
res = sizeof(dev->pan);
break;
case NETOPT_CHANNEL:
assert(max_len == sizeof(uint16_t));
*((uint16_t *)value) = (uint16_t)dev->chan;
res = sizeof(dev->chan);
break;
case NETOPT_ACK_REQ:
assert(max_len == sizeof(netopt_enable_t));
if (dev->flags & NETDEV_IEEE802154_ACK_REQ) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
case NETOPT_RAWMODE:
assert(max_len == sizeof(netopt_enable_t));
if (dev->flags & NETDEV_IEEE802154_RAW) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
#ifdef MODULE_GNRC
case NETOPT_PROTO:
assert(max_len == sizeof(gnrc_nettype_t));
*((gnrc_nettype_t *)value) = dev->proto;
res = sizeof(gnrc_nettype_t);
break;
#endif
case NETOPT_DEVICE_TYPE:
assert(max_len == sizeof(uint16_t));
*((uint16_t *)value) = NETDEV_TYPE_IEEE802154;
res = sizeof(uint16_t);
break;
case NETOPT_IPV6_IID:
res = _get_iid(dev, value, max_len);
break;
#ifdef MODULE_L2FILTER
case NETOPT_L2FILTER:
assert(max_len >= sizeof(l2filter_t **));
*((l2filter_t **)value) = dev->netdev.filter;
res = sizeof(l2filter_t **);
break;
#endif
case NETOPT_MAX_PDU_SIZE:
assert(max_len >= sizeof(int16_t));
*((uint16_t *)value) = (_get_ieee802154_pdu(dev)
- IEEE802154_MAX_HDR_LEN)
- IEEE802154_FCS_LEN;
res = sizeof(uint16_t);
break;
default:
break;
}
return res;
}
int netdev_ieee802154_set(netdev_ieee802154_t *dev, netopt_t opt, const void *value,
size_t len)
{
int res = -ENOTSUP;
switch (opt) {
case NETOPT_CHANNEL:
{
assert(len == sizeof(uint16_t));
uint16_t chan = *((uint16_t *)value);
/* real validity needs to be checked by device, since sub-GHz and
* 2.4 GHz band radios have different legal values. Here we only
* check that it fits in an 8-bit variabl*/
assert(chan <= UINT8_MAX);
dev->chan = chan;
res = sizeof(uint16_t);
break;
}
case NETOPT_ADDRESS:
assert(len <= sizeof(dev->short_addr));
memset(dev->short_addr, 0, sizeof(dev->short_addr));
memcpy(dev->short_addr, value, len);
res = sizeof(dev->short_addr);
break;
case NETOPT_ADDRESS_LONG:
assert(len <= sizeof(dev->long_addr));
memset(dev->long_addr, 0, sizeof(dev->long_addr));
memcpy(dev->long_addr, value, len);
res = sizeof(dev->long_addr);
break;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
assert(len == sizeof(uint16_t));
res = sizeof(uint16_t);
switch ((*(uint16_t *)value)) {
case IEEE802154_SHORT_ADDRESS_LEN:
dev->flags &= ~NETDEV_IEEE802154_SRC_MODE_LONG;
break;
case IEEE802154_LONG_ADDRESS_LEN:
dev->flags |= NETDEV_IEEE802154_SRC_MODE_LONG;
break;
default:
res = -EAFNOSUPPORT;
break;
}
break;
case NETOPT_NID:
assert(len == sizeof(dev->pan));
dev->pan = *((uint16_t *)value);
res = sizeof(dev->pan);
break;
case NETOPT_ACK_REQ:
if ((*(bool *)value)) {
dev->flags |= NETDEV_IEEE802154_ACK_REQ;
}
else {
dev->flags &= ~NETDEV_IEEE802154_ACK_REQ;
}
res = sizeof(uint16_t);
break;
case NETOPT_RAWMODE:
if ((*(bool *)value)) {
dev->flags |= NETDEV_IEEE802154_RAW;
}
else {
dev->flags &= ~NETDEV_IEEE802154_RAW;
}
res = sizeof(uint16_t);
break;
#ifdef MODULE_GNRC
case NETOPT_PROTO:
assert(len == sizeof(gnrc_nettype_t));
dev->proto = *((gnrc_nettype_t *)value);
res = sizeof(gnrc_nettype_t);
break;
#endif
#ifdef MODULE_L2FILTER
case NETOPT_L2FILTER:
res = l2filter_add(dev->netdev.filter, value, len);
break;
case NETOPT_L2FILTER_RM:
res = l2filter_rm(dev->netdev.filter, value, len);
break;
#endif
default:
break;
}
return res;
}
int netdev_ieee802154_dst_filter(netdev_ieee802154_t *dev, const uint8_t *mhr)
{
uint8_t dst_addr[IEEE802154_LONG_ADDRESS_LEN];
le_uint16_t dst_pan;
uint8_t pan_bcast[] = IEEE802154_PANID_BCAST;
int addr_len = ieee802154_get_dst(mhr, dst_addr, &dst_pan);
/* filter PAN ID */
if ((memcmp(pan_bcast, dst_pan.u8, 2) != 0) &&
(memcmp(&dev->pan, dst_pan.u8, 2) != 0)) {
return 1;
}
/* check destination address */
if (((addr_len == IEEE802154_SHORT_ADDRESS_LEN) &&
(memcmp(dev->short_addr, dst_addr, addr_len) == 0 ||
memcmp(ieee802154_addr_bcast, dst_addr, addr_len) == 0)) ||
((addr_len == IEEE802154_LONG_ADDRESS_LEN) &&
(memcmp(dev->long_addr, dst_addr, addr_len) == 0))) {
return 0;
}
return 1;
}
/** @} */