1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/netdev/ieee802154.c
Marian Buschsieweke c3500eb6e0
tree wide: fix typos in comments found by codespell
This will not change generated binaries, only the Doxygen output and
source code will have less typos.
2023-05-02 09:52:06 +02:00

330 lines
10 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"
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));
#if IS_USED(MODULE_IEEE802154_SECURITY)
ieee802154_sec_init(&dev->sec_ctx);
const netopt_enable_t e = NETOPT_ENABLE;
netdev_ieee802154_set(dev, NETOPT_ENCRYPTION, &e, sizeof(e));
#endif
}
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;
(void)max_len; /* only used in assert() */
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;
#if IS_USED(MODULE_IEEE802154_SECURITY)
case NETOPT_ENCRYPTION:
assert(max_len == sizeof(netopt_enable_t));
if (dev->flags & NETDEV_IEEE802154_SECURITY_EN) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */
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;
#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)
#if IS_USED(MODULE_IEEE802154_SECURITY)
-IEEE802154_SEC_MAX_AUX_HDR_LEN
#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */
- 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 variable */
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;
#if IS_USED(MODULE_IEEE802154_SECURITY)
case NETOPT_ENCRYPTION:
assert(len == sizeof(netopt_enable_t));
if ((*(bool *)value)) {
dev->flags |= NETDEV_IEEE802154_SECURITY_EN;
}
else {
dev->flags &= ~NETDEV_IEEE802154_SECURITY_EN;
}
res = sizeof(netopt_enable_t);
break;
case NETOPT_ENCRYPTION_KEY:
assert(len >= IEEE802154_SEC_KEY_LENGTH);
if (memcmp(dev->sec_ctx.cipher.context.context, value, len)) {
/* If the key changes, the frame counter can be reset to 0*/
dev->sec_ctx.frame_counter = 0;
}
memcpy(dev->sec_ctx.cipher.context.context, value,
IEEE802154_SEC_KEY_LENGTH);
res = IEEE802154_SEC_KEY_LENGTH;
break;
#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */
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;
}
/** @} */