[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:
Damian Królik
2024-09-23 09:02:15 -07:00
committed by GitHub
parent b605bb993e
commit bc50521cfa
11 changed files with 887 additions and 148 deletions
+1
View File
@@ -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
*
* @}
*
+2
View File
@@ -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 "- - - - - - - - - - - - - - - - ")
+2
View File
@@ -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
+1
View File
@@ -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 = [
+12
View File
@@ -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
*
+75
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+111 -6
View File
@@ -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
/**
* @}
+1
View File
@@ -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
+216
View File
@@ -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;
}