mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cfc2feca1d
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.
314 lines
9.6 KiB
C
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;
|
|
}
|
|
|
|
/** @} */
|