mirror of
https://github.com/espressif/openthread.git
synced 2026-08-17 07:59:51 +00:00
[mac] multipurpose wake-up frame support (#10728)
1. Add OT_WAKEUP_COORDINATOR and OT_WAKEUP_END_DEVICE build options. 2. Add support for parsing and constructing 802.15.4 Multipurpose frames. 3. Add support for parsing and constructing wake-up frames.
This commit is contained in:
@@ -85,6 +85,7 @@
|
||||
* @defgroup config-time-sync Time Sync Service
|
||||
* @defgroup config-tmf Thread Management Framework Service
|
||||
* @defgroup config-trel TREL
|
||||
* @defgroup config-wakeup Wake-up
|
||||
*
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -256,6 +256,8 @@ ot_option(OT_TX_QUEUE_STATS OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE "tx que
|
||||
ot_option(OT_UDP_FORWARD OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE "UDP forward")
|
||||
ot_option(OT_UPTIME OPENTHREAD_CONFIG_UPTIME_ENABLE "uptime")
|
||||
ot_option(OT_VERHOEFF_CHECKSUM OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE "verhoeff checksum")
|
||||
ot_option(OT_WAKEUP_COORDINATOR OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE "wake-up coordinator")
|
||||
ot_option(OT_WAKEUP_END_DEVICE OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE "wake-up end device")
|
||||
|
||||
option(OT_DOC "build OpenThread documentation")
|
||||
message(STATUS "- - - - - - - - - - - - - - - - ")
|
||||
|
||||
@@ -131,6 +131,8 @@ build_simulation()
|
||||
options+=("-DOT_LINK_METRICS_INITIATOR=ON")
|
||||
options+=("-DOT_LINK_METRICS_SUBJECT=ON")
|
||||
options+=("-DOT_LINK_METRICS_MANAGER=ON")
|
||||
options+=("-DOT_WAKEUP_COORDINATOR=ON")
|
||||
options+=("-DOT_WAKEUP_END_DEVICE=ON")
|
||||
fi
|
||||
|
||||
if [[ ${OT_NODE_TYPE} == cli* ]]; then
|
||||
|
||||
@@ -842,6 +842,7 @@ source_set("libopenthread_core_config") {
|
||||
"config/time_sync.h",
|
||||
"config/tmf.h",
|
||||
"config/trel.h",
|
||||
"config/wakeup.h",
|
||||
"openthread-core-config.h",
|
||||
]
|
||||
public_configs = [
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
*/
|
||||
|
||||
#include "config/time_sync.h"
|
||||
#include "config/wakeup.h"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT
|
||||
@@ -435,6 +436,17 @@
|
||||
#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
*
|
||||
* Define to 1 to enable support for IEEE 802.15.4 MAC Multipurpose frame format.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
#define OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME \
|
||||
(OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_CSL_AUTO_SYNC_ENABLE
|
||||
*
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes compile-time configurations for the Wake-up Coordinator and Wake-up End Device roles.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_WAKEUP_H_
|
||||
#define CONFIG_WAKEUP_H_
|
||||
|
||||
/**
|
||||
* @addtogroup config-wakeup
|
||||
*
|
||||
* @brief
|
||||
* This module includes configuration variables for the Wake-up Coordinator and Wake-up End Device roles.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
*
|
||||
* Define to 1 to enable the Wake-up Coordinator role that is capable of establishing
|
||||
* a link with one or more Wake-up End Devices by sending a sequence of wake-up frames.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
#define OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
*
|
||||
* Define to 1 to enable the Wake-up End Device role that periodically listens for wake-up
|
||||
* frames to establish a link with a Wake-up Coordinator device.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
#define OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#endif // CONFIG_WAKEUP_H_
|
||||
+271
-95
@@ -39,6 +39,7 @@
|
||||
#include "common/debug.hpp"
|
||||
#include "common/frame_builder.hpp"
|
||||
#include "common/log.hpp"
|
||||
#include "common/num_utils.hpp"
|
||||
#include "radio/trel_link.hpp"
|
||||
#if !OPENTHREAD_RADIO || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
|
||||
#include "crypto/aes_ccm.hpp"
|
||||
@@ -193,13 +194,13 @@ void Frame::InitMacHeader(Type aType,
|
||||
|
||||
if (aSuppressSequence)
|
||||
{
|
||||
fcf |= kFcfSequenceSupression;
|
||||
fcf |= kFcfSequenceSuppression;
|
||||
}
|
||||
|
||||
builder.Init(mPsdu, GetMtu());
|
||||
IgnoreError(builder.AppendLittleEndianUint16(fcf));
|
||||
|
||||
if (!IsSequenceSuppressed(fcf))
|
||||
if (IsSequencePresent(fcf))
|
||||
{
|
||||
IgnoreError(builder.AppendUint8(0)); // Seq number
|
||||
}
|
||||
@@ -238,9 +239,20 @@ void Frame::InitMacHeader(Type aType,
|
||||
mLength += GetFcsSize();
|
||||
}
|
||||
|
||||
uint16_t Frame::GetFrameControlField(void) const { return LittleEndian::ReadUint16(mPsdu); }
|
||||
|
||||
void Frame::SetFrameControlField(uint16_t aFcf) { LittleEndian::WriteUint16(aFcf, mPsdu); }
|
||||
void Frame::SetFrameControlField(uint16_t aFcf)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
if (IsShortFcf(aFcf))
|
||||
{
|
||||
OT_ASSERT((aFcf >> 8) == 0);
|
||||
mPsdu[0] = static_cast<uint8_t>(aFcf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LittleEndian::WriteUint16(aFcf, mPsdu);
|
||||
}
|
||||
}
|
||||
|
||||
Error Frame::ValidatePsdu(void) const
|
||||
{
|
||||
@@ -254,53 +266,115 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
bool Frame::IsWakeupFrame(void) const
|
||||
{
|
||||
const uint16_t fcf = GetFrameControlField();
|
||||
bool result = false;
|
||||
uint8_t keyIdMode;
|
||||
uint8_t firstIeIndex;
|
||||
Address srcAddress;
|
||||
|
||||
// Wake-up frame is a Multipurpose frame without Ack Request...
|
||||
VerifyOrExit((fcf & kFcfFrameTypeMask) == kTypeMultipurpose);
|
||||
VerifyOrExit((fcf & kMpFcfAckRequest) == 0);
|
||||
|
||||
// ... with extended source address...
|
||||
SuccessOrExit(GetSrcAddr(srcAddress));
|
||||
VerifyOrExit(srcAddress.IsExtended());
|
||||
|
||||
// ... secured with Key Id Mode 2...
|
||||
SuccessOrExit(GetKeyIdMode(keyIdMode));
|
||||
VerifyOrExit(keyIdMode == kKeyIdMode2);
|
||||
|
||||
// ... that has Rendezvous Time IE and Connection IE...
|
||||
VerifyOrExit(GetRendezvousTimeIe() != nullptr);
|
||||
VerifyOrExit(GetConnectionIe() != nullptr);
|
||||
|
||||
// ... but no other IEs nor payload.
|
||||
firstIeIndex = FindHeaderIeIndex();
|
||||
VerifyOrExit(mPsdu + firstIeIndex + sizeof(HeaderIe) + RendezvousTimeIe::kIeContentSize + sizeof(HeaderIe) +
|
||||
ConnectionIe::kIeContentSize ==
|
||||
GetFooter());
|
||||
|
||||
result = true;
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
void Frame::SetAckRequest(bool aAckRequest)
|
||||
{
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint16_t mask = Select<kFcfAckRequest, kMpFcfAckRequest>(fcf);
|
||||
|
||||
if (aAckRequest)
|
||||
{
|
||||
mPsdu[0] |= kFcfAckRequest;
|
||||
fcf |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPsdu[0] &= ~kFcfAckRequest;
|
||||
fcf &= ~mask;
|
||||
}
|
||||
|
||||
SetFrameControlField(fcf);
|
||||
}
|
||||
|
||||
void Frame::SetFramePending(bool aFramePending)
|
||||
{
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint16_t mask = Select<kFcfFramePending, kMpFcfFramePending>(fcf);
|
||||
|
||||
if (aFramePending)
|
||||
{
|
||||
mPsdu[0] |= kFcfFramePending;
|
||||
fcf |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPsdu[0] &= ~kFcfFramePending;
|
||||
fcf &= ~mask;
|
||||
}
|
||||
|
||||
SetFrameControlField(fcf);
|
||||
}
|
||||
|
||||
void Frame::SetIePresent(bool aIePresent)
|
||||
{
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint16_t mask = Select<kFcfIePresent, kMpFcfIePresent>(fcf);
|
||||
|
||||
if (aIePresent)
|
||||
{
|
||||
fcf |= kFcfIePresent;
|
||||
fcf |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
fcf &= ~kFcfIePresent;
|
||||
fcf &= ~mask;
|
||||
}
|
||||
|
||||
SetFrameControlField(fcf);
|
||||
}
|
||||
|
||||
uint8_t Frame::SkipSequenceIndex(void) const
|
||||
{
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint8_t index = GetFcfSize(fcf);
|
||||
|
||||
if (IsSequencePresent(fcf))
|
||||
{
|
||||
index += kDsnSize;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t Frame::FindDstPanIdIndex(void) const
|
||||
{
|
||||
uint8_t index;
|
||||
|
||||
VerifyOrExit(IsDstPanIdPresent(), index = kInvalidIndex);
|
||||
|
||||
index = kFcfSize + GetSeqNumSize();
|
||||
index = SkipSequenceIndex();
|
||||
|
||||
exit:
|
||||
return index;
|
||||
@@ -308,9 +382,16 @@ exit:
|
||||
|
||||
bool Frame::IsDstPanIdPresent(uint16_t aFcf)
|
||||
{
|
||||
bool present = true;
|
||||
bool present;
|
||||
|
||||
if (IsVersion2015(aFcf))
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
if (IsMultipurpose(aFcf))
|
||||
{
|
||||
present = (aFcf & kMpFcfPanidPresent) != 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (IsVersion2015(aFcf))
|
||||
{
|
||||
// Original table at `InitMacHeader()`
|
||||
//
|
||||
@@ -348,6 +429,7 @@ bool Frame::IsDstPanIdPresent(uint16_t aFcf)
|
||||
present = false;
|
||||
break;
|
||||
default:
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -382,19 +464,18 @@ void Frame::SetDstPanId(PanId aPanId)
|
||||
uint8_t Frame::GetSequence(void) const
|
||||
{
|
||||
OT_ASSERT(IsSequencePresent());
|
||||
return GetPsdu()[kSequenceIndex];
|
||||
|
||||
return GetPsdu()[GetFcfSize(GetFrameControlField())];
|
||||
}
|
||||
|
||||
void Frame::SetSequence(uint8_t aSequence)
|
||||
{
|
||||
OT_ASSERT(IsSequencePresent());
|
||||
GetPsdu()[kSequenceIndex] = aSequence;
|
||||
|
||||
GetPsdu()[GetFcfSize(GetFrameControlField())] = aSequence;
|
||||
}
|
||||
|
||||
uint8_t Frame::FindDstAddrIndex(void) const
|
||||
{
|
||||
return kFcfSize + GetSeqNumSize() + (IsDstPanIdPresent() ? sizeof(PanId) : 0);
|
||||
}
|
||||
uint8_t Frame::FindDstAddrIndex(void) const { return SkipSequenceIndex() + (IsDstPanIdPresent() ? sizeof(PanId) : 0); }
|
||||
|
||||
Error Frame::GetDstAddr(Address &aAddress) const
|
||||
{
|
||||
@@ -403,13 +484,13 @@ Error Frame::GetDstAddr(Address &aAddress) const
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
|
||||
|
||||
switch (GetFrameControlField() & kFcfDstAddrMask)
|
||||
switch (GetFcfDstAddr(GetFrameControlField()))
|
||||
{
|
||||
case kFcfDstAddrShort:
|
||||
case kFcfAddrShort:
|
||||
aAddress.SetShort(LittleEndian::ReadUint16(&mPsdu[index]));
|
||||
break;
|
||||
|
||||
case kFcfDstAddrExt:
|
||||
case kFcfAddrExt:
|
||||
aAddress.SetExtended(&mPsdu[index], ExtAddress::kReverseByteOrder);
|
||||
break;
|
||||
|
||||
@@ -424,7 +505,7 @@ exit:
|
||||
|
||||
void Frame::SetDstAddr(ShortAddress aShortAddress)
|
||||
{
|
||||
OT_ASSERT((GetFrameControlField() & kFcfDstAddrMask) == kFcfDstAddrShort);
|
||||
OT_ASSERT(GetFcfDstAddr(GetFrameControlField()) == kFcfAddrShort);
|
||||
LittleEndian::WriteUint16(aShortAddress, &mPsdu[FindDstAddrIndex()]);
|
||||
}
|
||||
|
||||
@@ -432,7 +513,7 @@ void Frame::SetDstAddr(const ExtAddress &aExtAddress)
|
||||
{
|
||||
uint8_t index = FindDstAddrIndex();
|
||||
|
||||
OT_ASSERT((GetFrameControlField() & kFcfDstAddrMask) == kFcfDstAddrExt);
|
||||
OT_ASSERT(GetFcfDstAddr(GetFrameControlField()) == kFcfAddrExt);
|
||||
OT_ASSERT(index != kInvalidIndex);
|
||||
|
||||
aExtAddress.CopyTo(&mPsdu[index], ExtAddress::kReverseByteOrder);
|
||||
@@ -458,25 +539,25 @@ void Frame::SetDstAddr(const Address &aAddress)
|
||||
|
||||
uint8_t Frame::FindSrcPanIdIndex(void) const
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint8_t index;
|
||||
|
||||
VerifyOrExit(IsSrcPanIdPresent(), index = kInvalidIndex);
|
||||
VerifyOrExit(IsSrcPanIdPresent(fcf), index = kInvalidIndex);
|
||||
|
||||
index += kFcfSize + GetSeqNumSize();
|
||||
index = SkipSequenceIndex();
|
||||
|
||||
if (IsDstPanIdPresent(fcf))
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
switch (fcf & kFcfDstAddrMask)
|
||||
switch (GetFcfDstAddr(fcf))
|
||||
{
|
||||
case kFcfDstAddrShort:
|
||||
case kFcfAddrShort:
|
||||
index += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfDstAddrExt:
|
||||
case kFcfAddrExt:
|
||||
index += sizeof(ExtAddress);
|
||||
break;
|
||||
}
|
||||
@@ -487,40 +568,52 @@ exit:
|
||||
|
||||
bool Frame::IsSrcPanIdPresent(uint16_t aFcf)
|
||||
{
|
||||
bool present = IsSrcAddrPresent(aFcf) && ((aFcf & kFcfPanidCompression) == 0);
|
||||
bool present;
|
||||
|
||||
// Special case for a IEEE 802.15.4-2015 frame: When both
|
||||
// addresses are extended, then the source PAN iD is not present
|
||||
// independent of PAN ID Compression. In this case, if the PAN ID
|
||||
// compression is set, it indicates that no PAN ID is in the
|
||||
// frame, while if the PAN ID Compression is zero, it indicates
|
||||
// the presence of the destination PAN ID in the frame.
|
||||
//
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
// | No | Dest Addr | Src Addr | PAN ID Comp || Src PAN ID |
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
// | 1 | Not Present | Not Present | 0 || Not Present |
|
||||
// | 2 | Not Present | Not Present | 1 || Not Present |
|
||||
// | 3 | Present | Not Present | 0 || Not Present |
|
||||
// | 4 | Present | Not Present | 1 || Not Present |
|
||||
// | 5 | Not Present | Present | 0 || Present |
|
||||
// | 6 | Not Present | Present | 1 || Not Present |
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
// | 7 | Extended | Extended | 0 || Not Present |
|
||||
// | 8 | Extended | Extended | 1 || Not Present |
|
||||
// |----+--------------+--------------+--------------++--------------+
|
||||
// | 9 | Short | Short | 0 || Present |
|
||||
// | 10 | Short | Extended | 0 || Present |
|
||||
// | 11 | Extended | Short | 0 || Present |
|
||||
// | 12 | Short | Extended | 1 || Not Present |
|
||||
// | 13 | Extended | Short | 1 || Not Present |
|
||||
// | 14 | Short | Short | 1 || Not Present |
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
|
||||
if (IsVersion2015(aFcf) && ((aFcf & (kFcfDstAddrMask | kFcfSrcAddrMask)) == (kFcfDstAddrExt | kFcfSrcAddrExt)))
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
if (IsMultipurpose(aFcf))
|
||||
{
|
||||
// Sources PAN ID is implicitly equal to Destination PAN ID in Multipurpose frames
|
||||
present = false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (IsVersion2015(aFcf) && ((aFcf & (kFcfDstAddrMask | kFcfSrcAddrMask)) == (kFcfDstAddrExt | kFcfSrcAddrExt)))
|
||||
{
|
||||
// Special case for a IEEE 802.15.4-2015 frame: When both
|
||||
// addresses are extended, then the source PAN iD is not present
|
||||
// independent of PAN ID Compression. In this case, if the PAN ID
|
||||
// compression is set, it indicates that no PAN ID is in the
|
||||
// frame, while if the PAN ID Compression is zero, it indicates
|
||||
// the presence of the destination PAN ID in the frame.
|
||||
//
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
// | No | Dest Addr | Src Addr | PAN ID Comp || Src PAN ID |
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
// | 1 | Not Present | Not Present | 0 || Not Present |
|
||||
// | 2 | Not Present | Not Present | 1 || Not Present |
|
||||
// | 3 | Present | Not Present | 0 || Not Present |
|
||||
// | 4 | Present | Not Present | 1 || Not Present |
|
||||
// | 5 | Not Present | Present | 0 || Present |
|
||||
// | 6 | Not Present | Present | 1 || Not Present |
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
// | 7 | Extended | Extended | 0 || Not Present |
|
||||
// | 8 | Extended | Extended | 1 || Not Present |
|
||||
// |----+--------------+--------------+--------------++--------------+
|
||||
// | 9 | Short | Short | 0 || Present |
|
||||
// | 10 | Short | Extended | 0 || Present |
|
||||
// | 11 | Extended | Short | 0 || Present |
|
||||
// | 12 | Short | Extended | 1 || Not Present |
|
||||
// | 13 | Extended | Short | 1 || Not Present |
|
||||
// | 14 | Short | Short | 1 || Not Present |
|
||||
// +----+--------------+--------------+--------------++--------------+
|
||||
|
||||
present = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
present = IsSrcAddrPresent(aFcf) && ((aFcf & kFcfPanidCompression) == 0);
|
||||
}
|
||||
|
||||
return present;
|
||||
}
|
||||
@@ -551,23 +644,21 @@ exit:
|
||||
|
||||
uint8_t Frame::FindSrcAddrIndex(void) const
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
|
||||
index += kFcfSize + GetSeqNumSize();
|
||||
uint8_t index = SkipSequenceIndex();
|
||||
|
||||
if (IsDstPanIdPresent(fcf))
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
switch (fcf & kFcfDstAddrMask)
|
||||
switch (GetFcfDstAddr(fcf))
|
||||
{
|
||||
case kFcfDstAddrShort:
|
||||
case kFcfAddrShort:
|
||||
index += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfDstAddrExt:
|
||||
case kFcfAddrExt:
|
||||
index += sizeof(ExtAddress);
|
||||
break;
|
||||
}
|
||||
@@ -588,17 +679,17 @@ Error Frame::GetSrcAddr(Address &aAddress) const
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
|
||||
|
||||
switch (fcf & kFcfSrcAddrMask)
|
||||
switch (GetFcfSrcAddr(fcf))
|
||||
{
|
||||
case kFcfSrcAddrShort:
|
||||
case kFcfAddrShort:
|
||||
aAddress.SetShort(LittleEndian::ReadUint16(&mPsdu[index]));
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrExt:
|
||||
case kFcfAddrExt:
|
||||
aAddress.SetExtended(&mPsdu[index], ExtAddress::kReverseByteOrder);
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrNone:
|
||||
case kFcfAddrNone:
|
||||
aAddress.SetNone();
|
||||
break;
|
||||
|
||||
@@ -616,7 +707,7 @@ void Frame::SetSrcAddr(ShortAddress aShortAddress)
|
||||
{
|
||||
uint8_t index = FindSrcAddrIndex();
|
||||
|
||||
OT_ASSERT((GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrShort);
|
||||
OT_ASSERT(GetFcfSrcAddr(GetFrameControlField()) == kFcfAddrShort);
|
||||
OT_ASSERT(index != kInvalidIndex);
|
||||
|
||||
LittleEndian::WriteUint16(aShortAddress, &mPsdu[index]);
|
||||
@@ -626,7 +717,7 @@ void Frame::SetSrcAddr(const ExtAddress &aExtAddress)
|
||||
{
|
||||
uint8_t index = FindSrcAddrIndex();
|
||||
|
||||
OT_ASSERT((GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrExt);
|
||||
OT_ASSERT(GetFcfSrcAddr(GetFrameControlField()) == kFcfAddrExt);
|
||||
OT_ASSERT(index != kInvalidIndex);
|
||||
|
||||
aExtAddress.CopyTo(&mPsdu[index], ExtAddress::kReverseByteOrder);
|
||||
@@ -964,8 +1055,6 @@ uint8_t Frame::SkipAddrFieldIndex(void) const
|
||||
|
||||
VerifyOrExit(kFcfSize + GetFcsSize() <= mLength, index = kInvalidIndex);
|
||||
|
||||
VerifyOrExit(!IsSequencePresent() || kFcfSize + kDsnSize + GetFcsSize() <= mLength, index = kInvalidIndex);
|
||||
|
||||
index = CalculateAddrFieldSize(GetFrameControlField());
|
||||
|
||||
exit:
|
||||
@@ -974,7 +1063,7 @@ exit:
|
||||
|
||||
uint8_t Frame::CalculateAddrFieldSize(uint16_t aFcf)
|
||||
{
|
||||
uint8_t size = kFcfSize + GetSeqNumSize(aFcf);
|
||||
uint8_t size = GetFcfSize(aFcf) + (IsSequencePresent(aFcf) ? kDsnSize : 0);
|
||||
|
||||
// This static method calculates the size (number of bytes) of
|
||||
// Address header field for a given Frame Control `aFcf` value.
|
||||
@@ -988,16 +1077,16 @@ uint8_t Frame::CalculateAddrFieldSize(uint16_t aFcf)
|
||||
size += sizeof(PanId);
|
||||
}
|
||||
|
||||
switch (aFcf & kFcfDstAddrMask)
|
||||
switch (GetFcfDstAddr(aFcf))
|
||||
{
|
||||
case kFcfDstAddrNone:
|
||||
case kFcfAddrNone:
|
||||
break;
|
||||
|
||||
case kFcfDstAddrShort:
|
||||
case kFcfAddrShort:
|
||||
size += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfDstAddrExt:
|
||||
case kFcfAddrExt:
|
||||
size += sizeof(ExtAddress);
|
||||
break;
|
||||
|
||||
@@ -1010,16 +1099,16 @@ uint8_t Frame::CalculateAddrFieldSize(uint16_t aFcf)
|
||||
size += sizeof(PanId);
|
||||
}
|
||||
|
||||
switch (aFcf & kFcfSrcAddrMask)
|
||||
switch (GetFcfSrcAddr(aFcf))
|
||||
{
|
||||
case kFcfSrcAddrNone:
|
||||
case kFcfAddrNone:
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrShort:
|
||||
case kFcfAddrShort:
|
||||
size += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrExt:
|
||||
case kFcfAddrExt:
|
||||
size += sizeof(ExtAddress);
|
||||
break;
|
||||
|
||||
@@ -1151,6 +1240,16 @@ template <> void Frame::InitIeContentAt<TimeIe>(uint8_t &aIndex)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
template <> void Frame::InitIeContentAt<RendezvousTimeIe>(uint8_t &aIndex) { aIndex += sizeof(RendezvousTimeIe); }
|
||||
|
||||
template <> void Frame::InitIeContentAt<ConnectionIe>(uint8_t &aIndex)
|
||||
{
|
||||
reinterpret_cast<ConnectionIe *>(mPsdu + aIndex)->Init();
|
||||
aIndex += sizeof(ConnectionIe);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
template <> void Frame::InitIeContentAt<CslIe>(uint8_t &aIndex) { aIndex += sizeof(CslIe); }
|
||||
#endif
|
||||
@@ -1186,7 +1285,8 @@ exit:
|
||||
return header;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE || \
|
||||
OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const
|
||||
{
|
||||
uint8_t index = FindHeaderIeIndex();
|
||||
@@ -1218,7 +1318,8 @@ const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const
|
||||
exit:
|
||||
return header;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE ||
|
||||
// OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
|
||||
|
||||
@@ -1342,6 +1443,10 @@ uint8_t Frame::GetFcsSize(void) const { return Trel::Link::kFcsSize; }
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
template Error Frame::AppendHeaderIeAt<TimeIe>(uint8_t &aIndex);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
template Error Frame::AppendHeaderIeAt<RendezvousTimeIe>(uint8_t &aIndex);
|
||||
template Error Frame::AppendHeaderIeAt<ConnectionIe>(uint8_t &aIndex);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
template Error Frame::AppendHeaderIeAt<CslIe>(uint8_t &aIndex);
|
||||
#endif
|
||||
@@ -1433,7 +1538,7 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
|
||||
}
|
||||
LittleEndian::WriteUint16(fcf, mPsdu);
|
||||
|
||||
mPsdu[kSequenceIndex] = aFrame.GetSequence();
|
||||
mPsdu[kFcfSize] = aFrame.GetSequence();
|
||||
|
||||
mLength = kImmAckLength;
|
||||
}
|
||||
@@ -1518,6 +1623,62 @@ exit:
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
Error TxFrame::GenerateWakeupFrame(PanId aPanId, const Address &aDest, const Address &aSource)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint16_t fcf = kTypeMultipurpose | kMpFcfLongFrame | kMpFcfPanidPresent | kMpFcfSecurityEnabled |
|
||||
kMpFcfSequenceSuppression | kMpFcfIePresent;
|
||||
uint8_t index = 0;
|
||||
|
||||
switch (aDest.GetType())
|
||||
{
|
||||
case Address::Type::kTypeShort:
|
||||
fcf |= kMpFcfDstAddrShort;
|
||||
break;
|
||||
case Address::Type::kTypeExtended:
|
||||
fcf |= kMpFcfDstAddrExt;
|
||||
break;
|
||||
default:
|
||||
ExitNow(error = kErrorInvalidArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (aSource.GetType())
|
||||
{
|
||||
case Address::Type::kTypeShort:
|
||||
fcf |= kMpFcfSrcAddrShort;
|
||||
break;
|
||||
case Address::Type::kTypeExtended:
|
||||
fcf |= kMpFcfSrcAddrExt;
|
||||
break;
|
||||
default:
|
||||
ExitNow(error = kErrorInvalidArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
mLength = CalculateAddrFieldSize(fcf);
|
||||
|
||||
OT_ASSERT(mLength != kInvalidSize);
|
||||
|
||||
SetFrameControlField(fcf);
|
||||
SetDstPanId(aPanId);
|
||||
SetDstAddr(aDest);
|
||||
SetSrcAddr(aSource);
|
||||
|
||||
mPsdu[mLength] = kKeyIdMode2 | kSecurityEncMic32;
|
||||
mLength += CalculateSecurityHeaderSize(kKeyIdMode2 | kSecurityEncMic32);
|
||||
mLength += CalculateMicSize(kKeyIdMode2 | kSecurityEncMic32);
|
||||
mLength += GetFcsSize();
|
||||
|
||||
SuccessOrExit(error = AppendHeaderIeAt<RendezvousTimeIe>(index));
|
||||
SuccessOrExit(error = AppendHeaderIeAt<ConnectionIe>(index));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
Error RxFrame::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey)
|
||||
{
|
||||
#if OPENTHREAD_RADIO
|
||||
@@ -1575,16 +1736,20 @@ Frame::InfoString Frame::ToInfoString(void) const
|
||||
InfoString string;
|
||||
uint8_t commandId, type;
|
||||
Address src, dst;
|
||||
uint32_t frameCounter;
|
||||
bool sequencePresent;
|
||||
|
||||
if (IsSequencePresent())
|
||||
string.Append("len:%d", mLength);
|
||||
|
||||
sequencePresent = IsSequencePresent();
|
||||
|
||||
if (sequencePresent)
|
||||
{
|
||||
string.Append("len:%d, seqnum:%d, type:", mLength, GetSequence());
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Append("len:%d, type:", mLength);
|
||||
string.Append(", seqnum:%d", GetSequence());
|
||||
}
|
||||
|
||||
string.Append(", type:");
|
||||
|
||||
type = GetType();
|
||||
|
||||
switch (type)
|
||||
@@ -1624,6 +1789,12 @@ Frame::InfoString Frame::ToInfoString(void) const
|
||||
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
case kTypeMultipurpose:
|
||||
string.Append("MP");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
string.Append("%d", type);
|
||||
break;
|
||||
@@ -1635,6 +1806,11 @@ Frame::InfoString Frame::ToInfoString(void) const
|
||||
string.Append(", src:%s, dst:%s, sec:%s, ackreq:%s", src.ToString().AsCString(), dst.ToString().AsCString(),
|
||||
ToYesNo(GetSecurityEnabled()), ToYesNo(GetAckRequest()));
|
||||
|
||||
if (!sequencePresent && GetFrameCounter(frameCounter) == kErrorNone)
|
||||
{
|
||||
string.Append(", fc:%lu", ToUlong(frameCounter));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
string.Append(", radio:%s", RadioTypeToString(GetRadioType()));
|
||||
#endif
|
||||
|
||||
+195
-47
@@ -69,10 +69,11 @@ public:
|
||||
*/
|
||||
enum Type : uint16_t
|
||||
{
|
||||
kTypeBeacon = 0, ///< Beacon Frame Type.
|
||||
kTypeData = 1, ///< Data Frame Type.
|
||||
kTypeAck = 2, ///< Ack Frame Type.
|
||||
kTypeMacCmd = 3, ///< MAC Command Frame Type.
|
||||
kTypeBeacon = 0, ///< Beacon Frame Type.
|
||||
kTypeData = 1, ///< Data Frame Type.
|
||||
kTypeAck = 2, ///< Ack Frame Type.
|
||||
kTypeMacCmd = 3, ///< MAC Command Frame Type.
|
||||
kTypeMultipurpose = 5, ///< Multipurpose Frame Type.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -215,6 +216,59 @@ public:
|
||||
*/
|
||||
bool IsAck(void) const { return GetType() == kTypeAck; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
/**
|
||||
* This method returns whether the frame is an IEEE 802.15.4 Wake-up frame.
|
||||
*
|
||||
* @retval TRUE If this is a Wake-up frame.
|
||||
* @retval FALSE If this is not a Wake-up frame.
|
||||
*
|
||||
*/
|
||||
bool IsWakeupFrame(void) const;
|
||||
|
||||
/**
|
||||
* This method returns the Rendezvous Time IE of a wake-up frame.
|
||||
*
|
||||
* @returns Pointer to the Rendezvous Time IE.
|
||||
*
|
||||
*/
|
||||
RendezvousTimeIe *GetRendezvousTimeIe(void) { return AsNonConst(AsConst(this)->GetRendezvousTimeIe()); }
|
||||
|
||||
/**
|
||||
* This method returns the Rendezvous Time IE of a wake-up frame.
|
||||
*
|
||||
* @returns Const pointer to the Rendezvous Time IE.
|
||||
*
|
||||
*/
|
||||
const RendezvousTimeIe *GetRendezvousTimeIe(void) const
|
||||
{
|
||||
const uint8_t *ie = GetHeaderIe(RendezvousTimeIe::kHeaderIeId);
|
||||
|
||||
return (ie != nullptr) ? reinterpret_cast<const RendezvousTimeIe *>(ie + sizeof(HeaderIe)) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the Connection IE of a wake-up frame.
|
||||
*
|
||||
* @returns Pointer to the Connection IE.
|
||||
*
|
||||
*/
|
||||
ConnectionIe *GetConnectionIe(void) { return AsNonConst(AsConst(this)->GetConnectionIe()); }
|
||||
|
||||
/**
|
||||
* This method returns the Connection IE of a wake-up frame.
|
||||
*
|
||||
* @returns Const pointer to the Connection IE.
|
||||
*
|
||||
*/
|
||||
const ConnectionIe *GetConnectionIe(void) const
|
||||
{
|
||||
const uint8_t *ie = GetThreadIe(ConnectionIe::kThreadIeSubtype);
|
||||
|
||||
return (ie != nullptr) ? reinterpret_cast<const ConnectionIe *>(ie + sizeof(HeaderIe)) : nullptr;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
/**
|
||||
* Returns the IEEE 802.15.4 Frame Version.
|
||||
*
|
||||
@@ -238,7 +292,7 @@ public:
|
||||
* @retval FALSE If security is not enabled.
|
||||
*
|
||||
*/
|
||||
bool GetSecurityEnabled(void) const { return (GetPsdu()[0] & kFcfSecurityEnabled) != 0; }
|
||||
bool GetSecurityEnabled(void) const { return IsSecurityEnabled(GetFrameControlField()); }
|
||||
|
||||
/**
|
||||
* Indicates whether or not the Frame Pending bit is set.
|
||||
@@ -247,11 +301,13 @@ public:
|
||||
* @retval FALSE If the Frame Pending bit is not set.
|
||||
*
|
||||
*/
|
||||
bool GetFramePending(void) const { return (GetPsdu()[0] & kFcfFramePending) != 0; }
|
||||
bool GetFramePending(void) const { return IsFramePending(GetFrameControlField()); }
|
||||
|
||||
/**
|
||||
* Sets the Frame Pending bit.
|
||||
*
|
||||
* @note This method must not be called on a Multipurpose frame with short Frame Control field.
|
||||
*
|
||||
* @param[in] aFramePending The Frame Pending bit.
|
||||
*
|
||||
*/
|
||||
@@ -264,11 +320,13 @@ public:
|
||||
* @retval FALSE If the Ack Request bit is not set.
|
||||
*
|
||||
*/
|
||||
bool GetAckRequest(void) const { return (GetPsdu()[0] & kFcfAckRequest) != 0; }
|
||||
bool GetAckRequest(void) const { return IsAckRequest(GetFrameControlField()); }
|
||||
|
||||
/**
|
||||
* Sets the Ack Request bit.
|
||||
*
|
||||
* @note This method must not be called on a Multipurpose frame with short Frame Control field.
|
||||
*
|
||||
* @param[in] aAckRequest The Ack Request bit.
|
||||
*
|
||||
*/
|
||||
@@ -277,6 +335,8 @@ public:
|
||||
/**
|
||||
* Indicates whether or not the PanId Compression bit is set.
|
||||
*
|
||||
* @note This method must not be called on a Multipurpose frame, which lacks this flag.
|
||||
*
|
||||
* @retval TRUE If the PanId Compression bit is set.
|
||||
* @retval FALSE If the PanId Compression bit is not set.
|
||||
*
|
||||
@@ -290,11 +350,13 @@ public:
|
||||
* @retval FALSE If no IE present.
|
||||
*
|
||||
*/
|
||||
bool IsIePresent(void) const { return (GetFrameControlField() & kFcfIePresent) != 0; }
|
||||
bool IsIePresent(void) const { return IsIePresent(GetFrameControlField()); }
|
||||
|
||||
/**
|
||||
* Sets the IE Present bit.
|
||||
*
|
||||
* @note This method must not be called on a Multipurpose frame with short Frame Control field.
|
||||
*
|
||||
* @param[in] aIePresent The IE Present bit.
|
||||
*
|
||||
*/
|
||||
@@ -322,16 +384,7 @@ public:
|
||||
* @returns TRUE if the Sequence Number is present, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
uint8_t IsSequencePresent(void) const { return !IsSequenceSuppressed(GetFrameControlField()); }
|
||||
|
||||
/**
|
||||
* Get the size of the sequence number.
|
||||
*
|
||||
* @retval 0 The size of sequence number is 0, indicating it's not present.
|
||||
* @retval 1 The size of sequence number is 1, indicating it's present.
|
||||
*
|
||||
*/
|
||||
uint8_t GetSeqNumSize(void) const { return GetSeqNumSize(GetFrameControlField()); }
|
||||
uint8_t IsSequencePresent(void) const { return IsSequencePresent(GetFrameControlField()); }
|
||||
|
||||
/**
|
||||
* Indicates whether or not the Destination PAN ID is present.
|
||||
@@ -919,30 +972,71 @@ public:
|
||||
* @returns The Frame Control field.
|
||||
*
|
||||
*/
|
||||
uint16_t GetFrameControlField(void) const;
|
||||
uint16_t GetFrameControlField(void) const
|
||||
{
|
||||
uint16_t fcf = mPsdu[0];
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
if (!IsShortFcf(fcf))
|
||||
#endif
|
||||
{
|
||||
fcf |= (mPsdu[1] << 8);
|
||||
}
|
||||
|
||||
return fcf;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t kShortFcfSize = sizeof(uint8_t);
|
||||
static constexpr uint8_t kSecurityControlSize = sizeof(uint8_t);
|
||||
static constexpr uint8_t kFrameCounterSize = sizeof(uint32_t);
|
||||
static constexpr uint8_t kCommandIdSize = sizeof(uint8_t);
|
||||
static constexpr uint8_t kKeyIndexSize = sizeof(uint8_t);
|
||||
|
||||
static constexpr uint16_t kFcfFrameTypeMask = 7 << 0;
|
||||
static constexpr uint16_t kFcfSecurityEnabled = 1 << 3;
|
||||
static constexpr uint16_t kFcfFramePending = 1 << 4;
|
||||
static constexpr uint16_t kFcfAckRequest = 1 << 5;
|
||||
static constexpr uint16_t kFcfPanidCompression = 1 << 6;
|
||||
static constexpr uint16_t kFcfSequenceSupression = 1 << 8;
|
||||
static constexpr uint16_t kFcfIePresent = 1 << 9;
|
||||
static constexpr uint16_t kFcfDstAddrNone = 0 << 10;
|
||||
static constexpr uint16_t kFcfDstAddrShort = 2 << 10;
|
||||
static constexpr uint16_t kFcfDstAddrExt = 3 << 10;
|
||||
static constexpr uint16_t kFcfDstAddrMask = 3 << 10;
|
||||
static constexpr uint16_t kFcfFrameVersionMask = 3 << 12;
|
||||
static constexpr uint16_t kFcfSrcAddrNone = 0 << 14;
|
||||
static constexpr uint16_t kFcfSrcAddrShort = 2 << 14;
|
||||
static constexpr uint16_t kFcfSrcAddrExt = 3 << 14;
|
||||
static constexpr uint16_t kFcfSrcAddrMask = 3 << 14;
|
||||
static constexpr uint16_t kFcfFrameTypeMask = 7 << 0;
|
||||
|
||||
static constexpr uint16_t kFcfAddrNone = 0;
|
||||
static constexpr uint16_t kFcfAddrShort = 2;
|
||||
static constexpr uint16_t kFcfAddrExt = 3;
|
||||
static constexpr uint16_t kFcfAddrMask = 3;
|
||||
|
||||
// Frame Control field format for general MAC frame
|
||||
static constexpr uint16_t kFcfSecurityEnabled = 1 << 3;
|
||||
static constexpr uint16_t kFcfFramePending = 1 << 4;
|
||||
static constexpr uint16_t kFcfAckRequest = 1 << 5;
|
||||
static constexpr uint16_t kFcfPanidCompression = 1 << 6;
|
||||
static constexpr uint16_t kFcfSequenceSuppression = 1 << 8;
|
||||
static constexpr uint16_t kFcfIePresent = 1 << 9;
|
||||
static constexpr uint16_t kFcfDstAddrShift = 10;
|
||||
static constexpr uint16_t kFcfDstAddrNone = kFcfAddrNone << kFcfDstAddrShift;
|
||||
static constexpr uint16_t kFcfDstAddrShort = kFcfAddrShort << kFcfDstAddrShift;
|
||||
static constexpr uint16_t kFcfDstAddrExt = kFcfAddrExt << kFcfDstAddrShift;
|
||||
static constexpr uint16_t kFcfDstAddrMask = kFcfAddrMask << kFcfDstAddrShift;
|
||||
static constexpr uint16_t kFcfFrameVersionMask = 3 << 12;
|
||||
static constexpr uint16_t kFcfSrcAddrShift = 14;
|
||||
static constexpr uint16_t kFcfSrcAddrNone = kFcfAddrNone << kFcfSrcAddrShift;
|
||||
static constexpr uint16_t kFcfSrcAddrShort = kFcfAddrShort << kFcfSrcAddrShift;
|
||||
static constexpr uint16_t kFcfSrcAddrExt = kFcfAddrExt << kFcfSrcAddrShift;
|
||||
static constexpr uint16_t kFcfSrcAddrMask = kFcfAddrMask << kFcfSrcAddrShift;
|
||||
|
||||
// Frame Control field format for MAC Multipurpose frame
|
||||
static constexpr uint16_t kMpFcfLongFrame = 1 << 3;
|
||||
static constexpr uint16_t kMpFcfDstAddrShift = 4;
|
||||
static constexpr uint16_t kMpFcfDstAddrNone = kFcfAddrNone << kMpFcfDstAddrShift;
|
||||
static constexpr uint16_t kMpFcfDstAddrShort = kFcfAddrShort << kMpFcfDstAddrShift;
|
||||
static constexpr uint16_t kMpFcfDstAddrExt = kFcfAddrExt << kMpFcfDstAddrShift;
|
||||
static constexpr uint16_t kMpFcfDstAddrMask = kFcfAddrMask << kMpFcfDstAddrShift;
|
||||
static constexpr uint16_t kMpFcfSrcAddrShift = 6;
|
||||
static constexpr uint16_t kMpFcfSrcAddrNone = kFcfAddrNone << kMpFcfSrcAddrShift;
|
||||
static constexpr uint16_t kMpFcfSrcAddrShort = kFcfAddrShort << kMpFcfSrcAddrShift;
|
||||
static constexpr uint16_t kMpFcfSrcAddrExt = kFcfAddrExt << kMpFcfSrcAddrShift;
|
||||
static constexpr uint16_t kMpFcfSrcAddrMask = kFcfAddrMask << kMpFcfSrcAddrShift;
|
||||
static constexpr uint16_t kMpFcfPanidPresent = 1 << 8;
|
||||
static constexpr uint16_t kMpFcfSecurityEnabled = 1 << 9;
|
||||
static constexpr uint16_t kMpFcfSequenceSuppression = 1 << 10;
|
||||
static constexpr uint16_t kMpFcfFramePending = 1 << 11;
|
||||
static constexpr uint16_t kMpFcfAckRequest = 1 << 14;
|
||||
static constexpr uint16_t kMpFcfIePresent = 1 << 15;
|
||||
|
||||
static constexpr uint8_t kSecLevelMask = 7 << 0;
|
||||
static constexpr uint8_t kKeyIdModeMask = 3 << 3;
|
||||
@@ -958,12 +1052,12 @@ protected:
|
||||
static constexpr uint8_t kKeySourceSizeMode2 = 4;
|
||||
static constexpr uint8_t kKeySourceSizeMode3 = 8;
|
||||
|
||||
static constexpr uint8_t kInvalidIndex = 0xff;
|
||||
static constexpr uint8_t kInvalidSize = kInvalidIndex;
|
||||
static constexpr uint8_t kMaxPsduSize = kInvalidSize - 1;
|
||||
static constexpr uint8_t kSequenceIndex = kFcfSize;
|
||||
static constexpr uint8_t kInvalidIndex = 0xff;
|
||||
static constexpr uint8_t kInvalidSize = kInvalidIndex;
|
||||
static constexpr uint8_t kMaxPsduSize = kInvalidSize - 1;
|
||||
|
||||
void SetFrameControlField(uint16_t aFcf);
|
||||
uint8_t SkipSequenceIndex(void) const;
|
||||
uint8_t FindDstPanIdIndex(void) const;
|
||||
uint8_t FindDstAddrIndex(void) const;
|
||||
uint8_t FindSrcPanIdIndex(void) const;
|
||||
@@ -981,16 +1075,55 @@ protected:
|
||||
|
||||
static uint8_t GetKeySourceLength(uint8_t aKeyIdMode);
|
||||
|
||||
static bool IsDstAddrPresent(uint16_t aFcf) { return (aFcf & kFcfDstAddrMask) != kFcfDstAddrNone; }
|
||||
static bool IsDstPanIdPresent(uint16_t aFcf);
|
||||
static bool IsSequenceSuppressed(uint16_t aFcf)
|
||||
{
|
||||
return (aFcf & (kFcfSequenceSupression | kFcfFrameVersionMask)) == (kFcfSequenceSupression | kVersion2015);
|
||||
}
|
||||
static uint8_t GetSeqNumSize(uint16_t aFcf) { return !IsSequenceSuppressed(aFcf) ? kDsnSize : 0; }
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
static uint8_t GetFcfSize(uint16_t aFcf) { return IsShortFcf(aFcf) ? kShortFcfSize : kFcfSize; }
|
||||
#else
|
||||
// clang-format off
|
||||
static uint8_t GetFcfSize(uint16_t /* aFcf */) { return kFcfSize; }
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
static bool IsSrcAddrPresent(uint16_t aFcf) { return (aFcf & kFcfSrcAddrMask) != kFcfSrcAddrNone; }
|
||||
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
|
||||
template <uint16_t kValue, uint16_t kMpValue> static uint16_t Select(uint16_t aFcf)
|
||||
{
|
||||
return IsMultipurpose(aFcf) ? kMpValue : kValue;
|
||||
}
|
||||
#else
|
||||
template <uint16_t kValue, uint16_t kMpValue> static uint16_t Select(uint16_t /* aFcf */) { return kValue; }
|
||||
#endif
|
||||
|
||||
template <uint16_t kValue, uint16_t kMpValue> static uint16_t MaskFcf(uint16_t aFcf)
|
||||
{
|
||||
return aFcf & Select<kValue, kMpValue>(aFcf);
|
||||
}
|
||||
|
||||
static uint16_t GetFcfDstAddr(uint16_t aFcf)
|
||||
{
|
||||
return MaskFcf<kFcfDstAddrMask, kMpFcfDstAddrMask>(aFcf) >> Select<kFcfDstAddrShift, kMpFcfDstAddrShift>(aFcf);
|
||||
}
|
||||
|
||||
static uint16_t GetFcfSrcAddr(uint16_t aFcf)
|
||||
{
|
||||
return MaskFcf<kFcfSrcAddrMask, kMpFcfSrcAddrMask>(aFcf) >> Select<kFcfSrcAddrShift, kMpFcfSrcAddrShift>(aFcf);
|
||||
}
|
||||
|
||||
static bool IsMultipurpose(uint16_t aFcf) { return (aFcf & kFcfFrameTypeMask) == kTypeMultipurpose; }
|
||||
static bool IsShortFcf(uint16_t aFcf)
|
||||
{
|
||||
return (aFcf & (kFcfFrameTypeMask | kMpFcfLongFrame)) == (kTypeMultipurpose | 0);
|
||||
}
|
||||
static bool IsSequencePresent(uint16_t aFcf)
|
||||
{
|
||||
return !MaskFcf<kFcfSequenceSuppression, kMpFcfSequenceSuppression>(aFcf);
|
||||
}
|
||||
static bool IsDstAddrPresent(uint16_t aFcf) { return MaskFcf<kFcfDstAddrMask, kMpFcfDstAddrMask>(aFcf); }
|
||||
static bool IsDstPanIdPresent(uint16_t aFcf);
|
||||
static bool IsSrcAddrPresent(uint16_t aFcf) { return MaskFcf<kFcfSrcAddrMask, kMpFcfSrcAddrMask>(aFcf); }
|
||||
static bool IsSrcPanIdPresent(uint16_t aFcf);
|
||||
static bool IsSecurityEnabled(uint16_t aFcf) { return MaskFcf<kFcfSecurityEnabled, kMpFcfSecurityEnabled>(aFcf); }
|
||||
static bool IsFramePending(uint16_t aFcf) { return MaskFcf<kFcfFramePending, kMpFcfFramePending>(aFcf); }
|
||||
static bool IsIePresent(uint16_t aFcf) { return MaskFcf<kFcfIePresent, kMpFcfIePresent>(aFcf); }
|
||||
static bool IsAckRequest(uint16_t aFcf) { return MaskFcf<kFcfAckRequest, kMpFcfAckRequest>(aFcf); }
|
||||
static bool IsVersion2015(uint16_t aFcf) { return (aFcf & kFcfFrameVersionMask) == kVersion2015; }
|
||||
|
||||
static uint8_t CalculateAddrFieldSize(uint16_t aFcf);
|
||||
@@ -1375,6 +1508,21 @@ public:
|
||||
*/
|
||||
Error GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength);
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
/**
|
||||
* Generate IEE 802.15.4 Wake-up frame.
|
||||
*
|
||||
* @param[in] aPanId A destination PAN identifier
|
||||
* @param[in] aDest A destination address (short or extended)
|
||||
* @param[in] aSource A source address (short or extended)
|
||||
*
|
||||
* @retval kErrorNone Successfully generated Wake-up frame.
|
||||
* @retval kErrorInvalidArgs @p aDest or @p aSource have incorrect type.
|
||||
*
|
||||
*/
|
||||
Error GenerateWakeupFrame(PanId aPanId, const Address &aDest, const Address &aSource);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
/**
|
||||
* Set TX delay field for the frame.
|
||||
|
||||
@@ -193,8 +193,6 @@ public:
|
||||
static constexpr uint8_t kIeContentSize = 0;
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || \
|
||||
OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
/**
|
||||
* Implements vendor specific Header IE generation and parsing.
|
||||
*
|
||||
@@ -307,7 +305,6 @@ private:
|
||||
} OT_TOOL_PACKED_END;
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
class ThreadIe
|
||||
{
|
||||
public:
|
||||
@@ -316,10 +313,118 @@ public:
|
||||
static constexpr uint32_t kVendorOuiThreadCompanyId = 0xeab89b;
|
||||
static constexpr uint8_t kEnhAckProbingIe = 0x00;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE ||
|
||||
// OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
/**
|
||||
* This class implements Rendezvous Time IE data structure.
|
||||
*
|
||||
* IEEE 802.15.4 Rendezvous Time IE contains two fields, Rendezvous Time and
|
||||
* Wake-up Interval, but the Wake-up Interval is not used in Thread, so it is
|
||||
* not included in this class.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class RendezvousTimeIe
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kHeaderIeId = 0x1d;
|
||||
static constexpr uint8_t kIeContentSize = sizeof(uint16_t);
|
||||
|
||||
/**
|
||||
* This method returns the Rendezvous Time.
|
||||
*
|
||||
* @returns the Rendezvous Time in the units of 10 symbols.
|
||||
*
|
||||
*/
|
||||
uint16_t GetRendezvousTime(void) const { return LittleEndian::HostSwap16(mRendezvousTime); }
|
||||
|
||||
/**
|
||||
* This method sets the Rendezvous Time.
|
||||
*
|
||||
* @param[in] aRendezvousTime The Rendezvous Time in the units of 10 symbols.
|
||||
*
|
||||
*/
|
||||
void SetRendezvousTime(uint16_t aRendezvousTime) { mRendezvousTime = LittleEndian::HostSwap16(aRendezvousTime); }
|
||||
|
||||
private:
|
||||
uint16_t mRendezvousTime;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* Implements Connection IE data structure.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ConnectionIe : public VendorIeHeader
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kHeaderIeId = ThreadIe::kHeaderIeId;
|
||||
static constexpr uint8_t kIeContentSize = ThreadIe::kIeContentSize + sizeof(uint8_t);
|
||||
static constexpr uint8_t kThreadIeSubtype = 0x01;
|
||||
|
||||
/**
|
||||
* Initializes the Connection IE.
|
||||
*
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
SetVendorOui(ThreadIe::kVendorOuiThreadCompanyId);
|
||||
SetSubType(kThreadIeSubtype);
|
||||
mConnectionWindow = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Retry Interval.
|
||||
*
|
||||
* The Retry Interval defines how frequently the Wake-up End Device is
|
||||
* supposed to retry sending the Parent Request to the Wake-up Coordinator.
|
||||
*
|
||||
* @returns the Retry Interval in the units of Wake-up Intervals (7.5ms by default).
|
||||
*
|
||||
*/
|
||||
uint8_t GetRetryInterval(void) const { return (mConnectionWindow & kRetryIntervalMask) >> kRetryIntervalOffset; }
|
||||
|
||||
/**
|
||||
* Sets the Retry Interval.
|
||||
*
|
||||
* @param[in] aRetryInterval The Retry Interval in the units of Wake-up Intervals (7.5ms by default).
|
||||
*
|
||||
*/
|
||||
void SetRetryInterval(uint8_t aRetryInterval)
|
||||
{
|
||||
mConnectionWindow = (aRetryInterval << kRetryIntervalOffset) | (mConnectionWindow & ~kRetryIntervalMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Retry Count.
|
||||
*
|
||||
* The Retry Count defines how many times the Wake-up End Device is supposed
|
||||
* to retry sending the Parent Request to the Wakeup Coordinator.
|
||||
*
|
||||
* @returns the Retry Count.
|
||||
*
|
||||
*/
|
||||
uint8_t GetRetryCount(void) const { return mConnectionWindow & kRetryCountMask; }
|
||||
|
||||
/**
|
||||
* Sets the Retry Count
|
||||
*
|
||||
* @param[in] aRetryCount The Retry Count.
|
||||
*
|
||||
*/
|
||||
void SetRetryCount(uint8_t aRetryCount)
|
||||
{
|
||||
mConnectionWindow = aRetryCount | (mConnectionWindow & ~kRetryCountMask);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kRetryIntervalOffset = 4;
|
||||
static constexpr uint8_t kRetryIntervalMask = 0x3 << kRetryIntervalOffset;
|
||||
static constexpr uint8_t kRetryCountMask = 0xf;
|
||||
|
||||
uint8_t mConnectionWindow;
|
||||
} OT_TOOL_PACKED_END;
|
||||
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
#include "config/time_sync.h"
|
||||
#include "config/tmf.h"
|
||||
#include "config/trel.h"
|
||||
#include "config/wakeup.h"
|
||||
|
||||
#undef OPENTHREAD_CORE_CONFIG_H_IN
|
||||
|
||||
|
||||
@@ -787,6 +787,218 @@ void TestMacFrameAckGeneration(void)
|
||||
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
constexpr uint16_t kMpFcfLongFrame = 1 << 3;
|
||||
constexpr uint16_t kMpFcfDstAddrShift = 4;
|
||||
constexpr uint16_t kMpFcfDstAddrExt = 3 << kMpFcfDstAddrShift;
|
||||
constexpr uint16_t kMpFcfSrcAddrShift = 6;
|
||||
constexpr uint16_t kMpFcfSrcAddrShort = 2 << kMpFcfSrcAddrShift;
|
||||
constexpr uint16_t kMpFcfSrcAddrExt = 3 << kMpFcfSrcAddrShift;
|
||||
constexpr uint16_t kMpFcfPanidPresent = 1 << 8;
|
||||
constexpr uint16_t kMpFcfSecurityEnabled = 1 << 9;
|
||||
constexpr uint16_t kMpFcfSequenceSuppression = 1 << 10;
|
||||
constexpr uint16_t kMpFcfAckRequest = 1 << 14;
|
||||
constexpr uint16_t kMpFcfIePresent = 1 << 15;
|
||||
|
||||
void TestMacWakeupFrameGeneration(void)
|
||||
{
|
||||
constexpr static uint8_t srcExtaddr[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
|
||||
constexpr static uint8_t dstExtaddr[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD};
|
||||
constexpr static uint8_t keySource[] = {0, 0, 0, 0x1C};
|
||||
|
||||
constexpr static uint8_t wakeupPsdu[] = {
|
||||
// Frame Control
|
||||
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
|
||||
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
|
||||
// PAN ID
|
||||
0xCE, 0xFA,
|
||||
// Destination Address
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
// Source Address
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
// Security Header
|
||||
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
|
||||
// Rendezvous Time IE
|
||||
0x82, 0x0E, 0xCD, 0xAB,
|
||||
// Connection IE
|
||||
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C};
|
||||
|
||||
uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||
Mac::Address src;
|
||||
Mac::Address dst;
|
||||
Mac::Address addr;
|
||||
Mac::TxFrame txFrame;
|
||||
Mac::Frame rxFrame;
|
||||
Mac::ConnectionIe *connectionIe;
|
||||
|
||||
printf("TestMacWakeupFrameGeneration\n");
|
||||
|
||||
src.SetExtended(srcExtaddr);
|
||||
dst.SetExtended(dstExtaddr);
|
||||
txFrame.mPsdu = psdu;
|
||||
txFrame.mLength = 0;
|
||||
txFrame.mRadioType = 0;
|
||||
|
||||
SuccessOrQuit(txFrame.GenerateWakeupFrame(0xface, dst, src));
|
||||
|
||||
// Validate that the frame satisfies the wake-up frame definition
|
||||
VerifyOrQuit(txFrame.GetType() == Mac::Frame::kTypeMultipurpose);
|
||||
VerifyOrQuit(!txFrame.GetAckRequest());
|
||||
VerifyOrQuit(txFrame.GetRendezvousTimeIe() != nullptr);
|
||||
VerifyOrQuit(txFrame.GetConnectionIe() != nullptr);
|
||||
VerifyOrQuit(txFrame.GetPayloadLength() == 0);
|
||||
SuccessOrQuit(txFrame.GetSrcAddr(addr));
|
||||
VerifyOrQuit(CompareAddresses(src, addr));
|
||||
SuccessOrQuit(txFrame.GetDstAddr(addr));
|
||||
VerifyOrQuit(CompareAddresses(dst, addr));
|
||||
|
||||
// Initialize remaining fields and check if the frame has the expected contents
|
||||
txFrame.SetFrameCounter(0xFCFCFCFC);
|
||||
txFrame.SetKeySource(keySource);
|
||||
txFrame.SetKeyId(0x1D);
|
||||
txFrame.GetRendezvousTimeIe()->SetRendezvousTime(0xABCD);
|
||||
connectionIe = txFrame.GetConnectionIe();
|
||||
connectionIe->SetRetryInterval(1);
|
||||
connectionIe->SetRetryCount(12);
|
||||
|
||||
VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xABCD);
|
||||
VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
|
||||
VerifyOrQuit(connectionIe->GetRetryCount() == 12);
|
||||
VerifyOrQuit(txFrame.GetLength() == sizeof(wakeupPsdu) + txFrame.GetFooterLength());
|
||||
VerifyOrQuit(memcmp(psdu, wakeupPsdu, sizeof(wakeupPsdu)) == 0);
|
||||
|
||||
// Initialize RX Frame with the same PSDU and check if it's recognized as wake-up frame
|
||||
rxFrame.mPsdu = psdu;
|
||||
rxFrame.mLength = txFrame.GetLength();
|
||||
rxFrame.mRadioType = 0;
|
||||
|
||||
SuccessOrQuit(rxFrame.ValidatePsdu());
|
||||
VerifyOrQuit(rxFrame.IsWakeupFrame());
|
||||
}
|
||||
|
||||
void TestMacWakeupFrameDetectionNegative(void)
|
||||
{
|
||||
struct TestCase
|
||||
{
|
||||
uint8_t *mPsdu;
|
||||
uint8_t mLength;
|
||||
};
|
||||
|
||||
uint8_t ackRequestedPsdu[] = {
|
||||
// Frame Control
|
||||
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
|
||||
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfAckRequest | kMpFcfIePresent) >>
|
||||
8,
|
||||
// PAN ID
|
||||
0xCE, 0xFA,
|
||||
// Destination Address
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
// Source Address
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
// Security Header
|
||||
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
|
||||
// Rendezvous Time IE
|
||||
0x82, 0x0E, 0xCD, 0xAB,
|
||||
// Connection IE
|
||||
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
|
||||
// Footer
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
uint8_t shortAddressPsdu[] = {
|
||||
// Frame Control
|
||||
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrShort,
|
||||
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
|
||||
// PAN ID
|
||||
0xCE, 0xFA,
|
||||
// Destination Address
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
// Source Address
|
||||
0x55, 0x55,
|
||||
// Security Header
|
||||
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
|
||||
// Rendezvous Time IE
|
||||
0x82, 0x0E, 0xCD, 0xAB,
|
||||
// Connection IE
|
||||
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
|
||||
// Footer
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
uint8_t noRendezvousIePsdu[] = {
|
||||
// Frame Control
|
||||
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
|
||||
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
|
||||
// PAN ID
|
||||
0xCE, 0xFA,
|
||||
// Destination Address
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
// Source Address
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
// Security Header
|
||||
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
|
||||
// Connection IE
|
||||
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
|
||||
// Footer
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
uint8_t noConnectionIePsdu[] = {
|
||||
// Frame Control
|
||||
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
|
||||
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
|
||||
// PAN ID
|
||||
0xCE, 0xFA,
|
||||
// Destination Address
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
// Source Address
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
// Security Header
|
||||
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
|
||||
// Rendezvous Time IE
|
||||
0x82, 0x0E, 0xCD, 0xAB,
|
||||
// Connection IE
|
||||
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x02, 0x1C,
|
||||
// Footer
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
uint8_t keyIdMode1Psdu[] = {
|
||||
// Frame Control
|
||||
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
|
||||
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
|
||||
// PAN ID
|
||||
0xCE, 0xFA,
|
||||
// Destination Address
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
// Source Address
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
// Security Header
|
||||
Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x1D,
|
||||
// Rendezvous Time IE
|
||||
0x82, 0x0E, 0xCD, 0xAB,
|
||||
// Connection IE
|
||||
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
|
||||
// Footer
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const TestCase testCases[] = {
|
||||
{ackRequestedPsdu, sizeof(ackRequestedPsdu)}, {shortAddressPsdu, sizeof(shortAddressPsdu)},
|
||||
{noRendezvousIePsdu, sizeof(noRendezvousIePsdu)}, {noConnectionIePsdu, sizeof(noConnectionIePsdu)},
|
||||
{keyIdMode1Psdu, sizeof(keyIdMode1Psdu)},
|
||||
};
|
||||
|
||||
Mac::Frame rxFrame;
|
||||
|
||||
printf("TestMacWakeupFrameDetectionNegative\n");
|
||||
|
||||
for (const TestCase &testCase : testCases)
|
||||
{
|
||||
rxFrame.mPsdu = testCase.mPsdu;
|
||||
rxFrame.mLength = testCase.mLength;
|
||||
rxFrame.mRadioType = 0;
|
||||
|
||||
SuccessOrQuit(rxFrame.ValidatePsdu());
|
||||
VerifyOrQuit(!rxFrame.IsWakeupFrame());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
@@ -796,6 +1008,10 @@ int main(void)
|
||||
ot::TestMacChannelMask();
|
||||
ot::TestMacFrameApi();
|
||||
ot::TestMacFrameAckGeneration();
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
ot::TestMacWakeupFrameGeneration();
|
||||
ot::TestMacWakeupFrameDetectionNegative();
|
||||
#endif
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user