mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-03 04:24:06 +00:00
Add mcxw ieee802154 driver Fix compliance errors for added files. Update function names to snake_case style. Signed-off-by: Andrei Menzopol <andrei.menzopol@nxp.com>
357 lines
7.4 KiB
C
357 lines
7.4 KiB
C
/* ieee802154_mcxw_utils.c - NXP MCXW 802.15.4 driver utils*/
|
|
|
|
/*
|
|
* Copyright 2025 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/arch/cpu.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include "ieee802154_mcxw_utils.h"
|
|
|
|
/* TODO IEEE 802.15.4 MAC Multipurpose frame format */
|
|
/* TODO add function checks */
|
|
|
|
enum offset_fcf_fields {
|
|
OffsetFrameType = 0x00,
|
|
OffsetSecurityEnabled = 0x03,
|
|
OffsetFramePending = 0x04,
|
|
OffsetAR = 0x05,
|
|
OffsetPanIdCompression = 0x06,
|
|
OffsetSeqNumberSuppression = 0x08,
|
|
OffsetIEPresent = 0x09,
|
|
OffsetDstAddrMode = 0x0A,
|
|
OffsetFrameVersion = 0x0C,
|
|
OffsetSrcAddrMode = 0x0E,
|
|
};
|
|
|
|
enum mask_fcf_fields {
|
|
MaskFrameType = (0x7 << OffsetFrameType),
|
|
MaskSecurityEnabled = (0x01 << OffsetSecurityEnabled),
|
|
MaskFramePending = (0x01 << OffsetFramePending),
|
|
MaskAR = (0x01 << OffsetAR),
|
|
MaskPanIdCompression = (0x01 << OffsetPanIdCompression),
|
|
MaskSeqNumberSuppression = (0x01 << OffsetSeqNumberSuppression),
|
|
MaskIEPresent = (0x01 << OffsetIEPresent),
|
|
MaskDstAddrMode = (0x03 << OffsetDstAddrMode),
|
|
MaskFrameVersion = (0x03 << OffsetFrameVersion),
|
|
MaskSrcAddrMode = (0x03 << OffsetSrcAddrMode),
|
|
};
|
|
|
|
enum modes_dst_addr {
|
|
ModeDstAddrNone = 0x00,
|
|
ModeDstAddrShort = (0x02 << OffsetDstAddrMode),
|
|
ModeDstAddrExt = (0x03 << OffsetDstAddrMode),
|
|
};
|
|
|
|
enum version_frame {
|
|
VersionIeee2003 = 0x00,
|
|
VersionIeee2006 = 0x01,
|
|
VersionIeee2015 = 0x02,
|
|
};
|
|
|
|
enum modes_src_addr {
|
|
ModeSrcAddrNone = 0x00,
|
|
ModeSrcAddrShort = (0x02 << OffsetSrcAddrMode),
|
|
ModeSrcAddrExt = (0x03 << OffsetSrcAddrMode),
|
|
};
|
|
|
|
enum offset_scf_fields {
|
|
OffsetSecurityLevel = 0x00,
|
|
OffsetKeyIdMode = 0x03,
|
|
OffsetFrameCntSuppression = 0x05,
|
|
OffsetASNinNonce = 0x06,
|
|
};
|
|
|
|
enum mask_scf_fields {
|
|
MaskSecurityLevel = (0x07 << OffsetSecurityLevel),
|
|
MaskKeyIdMode = (0x03 << OffsetKeyIdMode),
|
|
MaskFrameCntSuppression = (0x1 << OffsetFrameCntSuppression),
|
|
MaskASNinNonce = (0x01 << OffsetASNinNonce),
|
|
};
|
|
|
|
static uint16_t get_frame_control_field(uint8_t *pdu, uint16_t length)
|
|
{
|
|
if ((pdu == NULL) || (length < 3)) {
|
|
return 0x00;
|
|
}
|
|
|
|
return (uint16_t)(pdu[0] | (pdu[1] << 8));
|
|
}
|
|
|
|
static bool is_security_enabled(uint16_t fcf)
|
|
{
|
|
if (fcf) {
|
|
return (bool)(fcf & MaskSecurityEnabled);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool is_ie_present(uint16_t fcf)
|
|
{
|
|
if (fcf) {
|
|
return (bool)(fcf & MaskIEPresent);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static uint8_t get_frame_version(uint16_t fcf)
|
|
{
|
|
if (fcf) {
|
|
return (uint8_t)((fcf & MaskFrameVersion) >> OffsetFrameVersion);
|
|
}
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
static bool is_frame_version_2015_fcf(uint16_t fcf)
|
|
{
|
|
if (fcf) {
|
|
return get_frame_version(fcf) == VersionIeee2015;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool is_frame_version_2015(uint8_t *pdu, uint16_t length)
|
|
{
|
|
uint16_t fcf = get_frame_control_field(pdu, length);
|
|
|
|
if (fcf) {
|
|
return get_frame_version(fcf) == VersionIeee2015;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool is_sequence_number_suppression(uint16_t fcf)
|
|
{
|
|
if (fcf) {
|
|
return (bool)(fcf & MaskSeqNumberSuppression);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool is_dst_panid_present(uint16_t fcf)
|
|
{
|
|
bool present;
|
|
|
|
if (!fcf) {
|
|
return false;
|
|
}
|
|
|
|
if (is_frame_version_2015_fcf(fcf)) {
|
|
switch (fcf & (MaskDstAddrMode | MaskSrcAddrMode | MaskPanIdCompression)) {
|
|
case (ModeDstAddrNone | ModeSrcAddrNone):
|
|
case (ModeDstAddrShort | ModeSrcAddrNone | MaskPanIdCompression):
|
|
case (ModeDstAddrExt | ModeSrcAddrNone | MaskPanIdCompression):
|
|
case (ModeDstAddrNone | ModeSrcAddrShort):
|
|
case (ModeDstAddrNone | ModeSrcAddrExt):
|
|
case (ModeDstAddrNone | ModeSrcAddrShort | MaskPanIdCompression):
|
|
case (ModeDstAddrNone | ModeSrcAddrExt | MaskPanIdCompression):
|
|
case (ModeDstAddrExt | ModeSrcAddrExt | MaskPanIdCompression):
|
|
present = false;
|
|
break;
|
|
default:
|
|
present = true;
|
|
}
|
|
} else {
|
|
present = (bool)(fcf & MaskDstAddrMode);
|
|
}
|
|
|
|
return present;
|
|
}
|
|
|
|
static bool is_src_panid_present(uint16_t fcf)
|
|
{
|
|
bool present;
|
|
|
|
if (!fcf) {
|
|
return false;
|
|
}
|
|
|
|
if (is_frame_version_2015_fcf(fcf)) {
|
|
switch (fcf & (MaskDstAddrMode | MaskSrcAddrMode | MaskPanIdCompression)) {
|
|
case (ModeDstAddrNone | ModeSrcAddrShort):
|
|
case (ModeDstAddrNone | ModeSrcAddrExt):
|
|
case (ModeDstAddrShort | ModeSrcAddrShort):
|
|
case (ModeDstAddrShort | ModeSrcAddrExt):
|
|
case (ModeDstAddrExt | ModeSrcAddrShort):
|
|
present = true;
|
|
break;
|
|
default:
|
|
present = false;
|
|
}
|
|
|
|
} else {
|
|
present = ((fcf & MaskSrcAddrMode) != 0) && ((fcf & MaskPanIdCompression) == 0);
|
|
}
|
|
|
|
return present;
|
|
}
|
|
|
|
static uint8_t calculate_addr_field_size(uint16_t fcf)
|
|
{
|
|
uint8_t size = 2;
|
|
|
|
if (!fcf) {
|
|
return 0;
|
|
}
|
|
|
|
if (!is_sequence_number_suppression(fcf)) {
|
|
size += 1;
|
|
}
|
|
|
|
if (is_dst_panid_present(fcf)) {
|
|
size += 2;
|
|
}
|
|
|
|
/* destination addressing mode */
|
|
switch (fcf & MaskDstAddrMode) {
|
|
case ModeDstAddrShort:
|
|
size += 2;
|
|
break;
|
|
case ModeDstAddrExt:
|
|
size += 8;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (is_src_panid_present(fcf)) {
|
|
size += 2;
|
|
}
|
|
|
|
/* source addressing mode */
|
|
switch (fcf & MaskSrcAddrMode) {
|
|
case ModeSrcAddrShort:
|
|
size += 2;
|
|
break;
|
|
case ModeSrcAddrExt:
|
|
size += 8;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
static uint8_t get_keyid_mode(uint8_t *pdu, uint16_t length)
|
|
{
|
|
uint16_t fcf = get_frame_control_field(pdu, length);
|
|
uint8_t ash_start;
|
|
|
|
if (is_security_enabled(fcf)) {
|
|
ash_start = calculate_addr_field_size(fcf);
|
|
return (uint8_t)((pdu[ash_start] & MaskKeyIdMode) >> OffsetKeyIdMode);
|
|
}
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
bool is_keyid_mode_1(uint8_t *pdu, uint16_t length)
|
|
{
|
|
uint8_t key_mode = get_keyid_mode(pdu, length);
|
|
|
|
if (key_mode == 0x01) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void set_frame_counter(uint8_t *pdu, uint16_t length, uint32_t fc)
|
|
{
|
|
uint16_t fcf = get_frame_control_field(pdu, length);
|
|
|
|
if (is_security_enabled(fcf)) {
|
|
uint8_t ash_start = calculate_addr_field_size(fcf);
|
|
uint8_t scf = pdu[ash_start];
|
|
|
|
/* check that Frame Counter Suppression is not set */
|
|
if (!(scf & MaskFrameCntSuppression)) {
|
|
sys_put_le32(fc, &pdu[ash_start + 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint8_t get_asn_size(uint8_t *pdu, uint16_t length)
|
|
{
|
|
uint16_t fcf = get_frame_control_field(pdu, length);
|
|
|
|
if (is_security_enabled(fcf)) {
|
|
uint8_t ash_start = calculate_addr_field_size(fcf);
|
|
uint8_t scf = pdu[ash_start];
|
|
uint8_t size = 1;
|
|
|
|
/* Frame Counter Suppression is not set */
|
|
if (!(scf & MaskFrameCntSuppression)) {
|
|
size += 4;
|
|
}
|
|
|
|
uint8_t key_mode = get_keyid_mode(pdu, length);
|
|
|
|
switch (key_mode) {
|
|
case 0x01:
|
|
size += 1;
|
|
break;
|
|
case 0x02:
|
|
size += 5;
|
|
case 0x03:
|
|
size += 9;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t *get_csl_ie_content_start(uint8_t *pdu, uint16_t length)
|
|
{
|
|
uint16_t fcf = get_frame_control_field(pdu, length);
|
|
|
|
if (is_ie_present(fcf)) {
|
|
uint8_t ie_start_idx = calculate_addr_field_size(fcf) + get_asn_size(pdu, length);
|
|
uint8_t *cur_ie = &pdu[ie_start_idx];
|
|
|
|
uint8_t ie_header = (uint16_t)(cur_ie[0] | (cur_ie[1] << 8));
|
|
uint8_t ie_length = ie_header & 0x7F;
|
|
uint8_t ie_el_id = ie_header & 0x7F80;
|
|
|
|
while ((ie_el_id != 0x7e) && (ie_el_id != 0x7f)) {
|
|
if (ie_el_id == 0x1a) {
|
|
return (cur_ie + 2);
|
|
}
|
|
cur_ie += (2 + ie_length);
|
|
ie_header = (uint16_t)(cur_ie[0] | (cur_ie[1] << 8));
|
|
ie_length = ie_header & 0x7F;
|
|
ie_el_id = ie_header & 0x7F80;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void set_csl_ie(uint8_t *pdu, uint16_t length, uint16_t period, uint16_t phase)
|
|
{
|
|
uint8_t *csl_ie_content = get_csl_ie_content_start(pdu, length);
|
|
|
|
if (csl_ie_content) {
|
|
sys_put_le16(phase, csl_ie_content);
|
|
sys_put_le16(period, csl_ie_content + 2);
|
|
}
|
|
}
|