[mac] make Frame::ParseInfo public and unify frame field access (#13543)

This commit refactors MAC frame parsing and field inspection across
the OpenThread stack by making `Frame::ParseInfo`, `RxFrame::ParseInfo`,
and `TxFrame::ParseInfo` public and deprecating/removing individual
getter methods directly on `Frame`.

Previously, `Frame` provided dozens of separate getter methods
(`GetDstAddr()`, `GetSrcAddr()`, `GetDstPanId()`, `GetSrcPanId()`,
`GetSecurityLevel()`, `GetKeyIdMode()`, `GetFrameCounter()`,
`GetCommandId()`, `GetPayload()`, `Find<IeType>()`, etc.). Calling
these methods repeatedly on the same frame resulted in multiple
parsing passes over the PSDU buffer. Furthermore, callback handlers
across `SubMac`, `Mac`, `MeshForwarder`, and various schedulers had to
re-query individual fields or maintain partial state independently.

This commit unifies frame parsing into a single-pass model:
- `ParseInfo` extracts and caches all relevant frame header fields,
  addresses, PAN IDs, security attributes, Header IEs, and payload/header
  boundaries during a single parse pass.
- Frame parsing and validation can be done incrementally using
  `ParseMode` (`kParseAddrFields`, `kParseSecurityHeader`, or
  `kParseFully`).
- Passing `ParseInfo` across layer boundaries eliminates redundant
  parsing operations and simplifies code across the codebase.
This commit is contained in:
Abtin Keshavarzian
2026-09-02 17:33:40 -07:00
committed by GitHub
parent cedcc0c405
commit 608ab60f03
38 changed files with 1474 additions and 1641 deletions
+140 -75
View File
@@ -37,6 +37,51 @@
using namespace ot;
//---------------------------------------------------------------------------------------------------------------------
// Helpers
static inline Error ParseAddrFields(const otRadioFrame *aFrame, Mac::Frame::ParseInfo &aFrameInfo)
{
return aFrameInfo.ParseFrom(*static_cast<const Mac::Frame *>(aFrame), Mac::Frame::kParseAddrFields);
}
static inline Error ParseSecurityHeader(const otRadioFrame *aFrame, Mac::TxFrame::ParseInfo &aFrameInfo)
{
return aFrameInfo.ParseFrom(*static_cast<const Mac::TxFrame *>(aFrame), Mac::Frame::kParseSecurityHeader);
}
static inline Error ParseFully(const otRadioFrame *aFrame, Mac::Frame::ParseInfo &aFrameInfo)
{
return aFrameInfo.ParseFrom(*static_cast<const Mac::Frame *>(aFrame), Mac::Frame::kParseFully);
}
static bool IsFrameOfType(const otRadioFrame *aFrame, Mac::Frame::Type aType)
{
bool matches = false;
Mac::Frame::ParseInfo frameInfo;
SuccessOrExit(ParseAddrFields(aFrame, frameInfo));
matches = (frameInfo.mType == aType);
exit:
return matches;
}
static bool HasFrameKeyIdMode(const otRadioFrame *aFrame, Mac::Frame::KeyIdMode aKeyIdMode)
{
bool matches = false;
Mac::TxFrame::ParseInfo frameInfo;
SuccessOrExit(ParseSecurityHeader(aFrame, frameInfo));
VerifyOrExit(frameInfo.mKeyIdMode == aKeyIdMode);
matches = true;
exit:
return matches;
}
//---------------------------------------------------------------------------------------------------------------------
bool otMacFrameDoesAddrMatch(const otRadioFrame *aFrame,
otPanId aPanId,
otShortAddress aShortAddress,
@@ -51,59 +96,69 @@ bool otMacFrameDoesAddrMatchAny(const otRadioFrame *aFrame,
otShortAddress aAltShortAddress,
const otExtAddress *aExtAddress)
{
const Mac::Frame &frame = *static_cast<const Mac::Frame *>(aFrame);
bool rval = true;
Mac::Address dst;
Mac::PanId panid;
bool rval = true;
Mac::Frame::ParseInfo frameInfo;
VerifyOrExit(frame.GetDstAddr(dst) == kErrorNone, rval = false);
if (ParseAddrFields(aFrame, frameInfo) != kErrorNone)
{
rval = false;
ExitNow();
}
switch (dst.GetType())
switch (frameInfo.mAddrs.mDestination.GetType())
{
case Mac::Address::kTypeShort:
VerifyOrExit(dst.GetShort() == Mac::kShortAddrBroadcast || dst.GetShort() == aShortAddress ||
(aAltShortAddress != Mac::kShortAddrInvalid && dst.GetShort() == aAltShortAddress),
VerifyOrExit(frameInfo.mAddrs.mDestination.GetShort() == Mac::kShortAddrBroadcast ||
frameInfo.mAddrs.mDestination.GetShort() == aShortAddress ||
(aAltShortAddress != Mac::kShortAddrInvalid &&
frameInfo.mAddrs.mDestination.GetShort() == aAltShortAddress),
rval = false);
break;
case Mac::Address::kTypeExtended:
VerifyOrExit(dst.GetExtended() == *static_cast<const Mac::ExtAddress *>(aExtAddress), rval = false);
VerifyOrExit(frameInfo.mAddrs.mDestination.GetExtended() == *static_cast<const Mac::ExtAddress *>(aExtAddress),
rval = false);
break;
case Mac::Address::kTypeNone:
break;
}
SuccessOrExit(frame.GetDstPanId(panid));
VerifyOrExit(panid == Mac::kPanIdBroadcast || panid == aPanId, rval = false);
VerifyOrExit(frameInfo.mPanIds.IsDestinationPresent());
VerifyOrExit(frameInfo.mPanIds.GetDestination() == Mac::kPanIdBroadcast ||
frameInfo.mPanIds.GetDestination() == aPanId,
rval = false);
exit:
return rval;
}
bool otMacFrameIsAck(const otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->GetType() == Mac::Frame::kTypeAck;
}
bool otMacFrameIsAck(const otRadioFrame *aFrame) { return IsFrameOfType(aFrame, Mac::Frame::kTypeAck); }
bool otMacFrameIsData(const otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->GetType() == Mac::Frame::kTypeData;
}
bool otMacFrameIsData(const otRadioFrame *aFrame) { return IsFrameOfType(aFrame, Mac::Frame::kTypeData); }
bool otMacFrameIsCommand(const otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->GetType() == Mac::Frame::kTypeMacCmd;
}
bool otMacFrameIsCommand(const otRadioFrame *aFrame) { return IsFrameOfType(aFrame, Mac::Frame::kTypeMacCmd); }
bool otMacFrameIsDataRequest(const otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->IsDataRequestCommand();
bool matches = false;
Mac::Frame::ParseInfo frameInfo;
SuccessOrExit(ParseFully(aFrame, frameInfo));
VerifyOrExit(frameInfo.mType == Mac::Frame::kTypeMacCmd);
VerifyOrExit(frameInfo.mCommandId == Mac::Frame::kMacCmdDataRequest);
matches = true;
exit:
return matches;
}
bool otMacFrameIsAckRequested(const otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->GetAckRequest();
Mac::Frame::ParseInfo frameInfo;
IgnoreError(ParseAddrFields(aFrame, frameInfo));
return frameInfo.mIsAckRequest;
}
static void GetOtMacAddress(const Mac::Address &aInAddress, otMacAddress *aOutAddress)
@@ -128,13 +183,11 @@ static void GetOtMacAddress(const Mac::Address &aInAddress, otMacAddress *aOutAd
otError otMacFrameGetSrcAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress)
{
otError error;
Mac::Address address;
Error error;
Mac::Frame::ParseInfo frameInfo;
error = static_cast<const Mac::Frame *>(aFrame)->GetSrcAddr(address);
SuccessOrExit(error);
GetOtMacAddress(address, aMacAddress);
SuccessOrExit(error = ParseAddrFields(aFrame, frameInfo));
GetOtMacAddress(frameInfo.mAddrs.mSource, aMacAddress);
exit:
return error;
@@ -142,13 +195,11 @@ exit:
otError otMacFrameGetDstAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress)
{
otError error;
Mac::Address address;
Error error;
Mac::Frame::ParseInfo frameInfo;
error = static_cast<const Mac::Frame *>(aFrame)->GetDstAddr(address);
SuccessOrExit(error);
GetOtMacAddress(address, aMacAddress);
SuccessOrExit(error = ParseAddrFields(aFrame, frameInfo));
GetOtMacAddress(frameInfo.mAddrs.mDestination, aMacAddress);
exit:
return error;
@@ -156,29 +207,31 @@ exit:
otError otMacFrameGetSequence(const otRadioFrame *aFrame, uint8_t *aSequence)
{
otError error;
Error error;
Mac::Frame::ParseInfo frameInfo;
if (static_cast<const Mac::Frame *>(aFrame)->IsSequencePresent())
{
*aSequence = static_cast<const Mac::Frame *>(aFrame)->GetSequence();
error = kErrorNone;
}
else
{
error = kErrorParse;
}
SuccessOrExit(error = ParseAddrFields(aFrame, frameInfo));
VerifyOrExit(frameInfo.mIsSeqNumPresent, error = kErrorParse);
*aSequence = frameInfo.mSequenceNum;
exit:
return error;
}
void otMacFrameProcessTransmitAesCcm(otRadioFrame *aFrame, const otExtAddress *aExtAddress)
{
static_cast<Mac::TxFrame *>(aFrame)->ProcessTransmitAesCcm(*static_cast<const Mac::ExtAddress *>(aExtAddress));
Mac::TxFrame::ParseInfo frameInfo;
IgnoreError(ParseFully(aFrame, frameInfo));
frameInfo.ProcessTransmitAesCcm(AsCoreType(aExtAddress));
}
bool otMacFrameIsVersion2015(const otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->IsVersion2015();
Mac::Frame::ParseInfo frameInfo;
IgnoreError(ParseAddrFields(aFrame, frameInfo));
return frameInfo.mVersion == Mac::Frame::kVersion2015;
}
void otMacFrameGenerateImmAck(const otRadioFrame *aFrame, bool aIsFramePending, otRadioFrame *aAckFrame)
@@ -207,49 +260,58 @@ void otMacFrameSetCslIe(otRadioFrame *aFrame, uint16_t aCslPeriod, uint16_t aCsl
{
static_cast<Mac::Frame *>(aFrame)->UpdateCslIe(aCslPeriod, aCslPhase);
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#endif
bool otMacFrameIsSecurityEnabled(otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->GetSecurityEnabled();
Mac::Frame::ParseInfo frameInfo;
IgnoreError(ParseAddrFields(aFrame, frameInfo));
return frameInfo.mIsSecurityEnabled;
}
bool otMacFrameIsKeyIdMode1(otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->HasKeyIdMode(Mac::Frame::kKeyIdMode1);
}
bool otMacFrameIsKeyIdMode1(otRadioFrame *aFrame) { return HasFrameKeyIdMode(aFrame, Mac::Frame::kKeyIdMode1); }
bool otMacFrameIsKeyIdMode2(otRadioFrame *aFrame)
{
return static_cast<const Mac::Frame *>(aFrame)->HasKeyIdMode(Mac::Frame::kKeyIdMode2);
}
bool otMacFrameIsKeyIdMode2(otRadioFrame *aFrame) { return HasFrameKeyIdMode(aFrame, Mac::Frame::kKeyIdMode2); }
uint8_t otMacFrameGetKeyId(otRadioFrame *aFrame)
{
uint8_t keyIndex = 0;
uint8_t keyIndex = 0;
Mac::TxFrame::ParseInfo frameInfo;
IgnoreError(static_cast<const Mac::Frame *>(aFrame)->GetKeyIndex(keyIndex));
SuccessOrExit(ParseSecurityHeader(aFrame, frameInfo));
keyIndex = frameInfo.mKeyIndex;
exit:
return keyIndex;
}
void otMacFrameSetKeyId(otRadioFrame *aFrame, uint8_t aKeyId)
{
static_cast<Mac::Frame *>(aFrame)->SetKeyIndex(aKeyId);
Mac::TxFrame::ParseInfo frameInfo;
IgnoreError(ParseSecurityHeader(aFrame, frameInfo));
frameInfo.WriteKeyIndex(aKeyId);
}
uint32_t otMacFrameGetFrameCounter(otRadioFrame *aFrame)
{
uint32_t frameCounter = UINT32_MAX;
uint32_t frameCounter = UINT32_MAX;
Mac::TxFrame::ParseInfo frameInfo;
IgnoreError(static_cast<Mac::Frame *>(aFrame)->GetFrameCounter(frameCounter));
SuccessOrExit(ParseSecurityHeader(aFrame, frameInfo));
frameCounter = frameInfo.mFrameCounter;
exit:
return frameCounter;
}
void otMacFrameSetFrameCounter(otRadioFrame *aFrame, uint32_t aFrameCounter)
{
static_cast<Mac::Frame *>(aFrame)->SetFrameCounter(aFrameCounter);
Mac::TxFrame::ParseInfo frameInfo;
IgnoreError(ParseSecurityHeader(aFrame, frameInfo));
frameInfo.WriteFrameCounter(aFrameCounter);
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -397,10 +459,14 @@ otError otMacFrameProcessTxSfd(otRadioFrame *aFrame, uint64_t aRadioTime, otRadi
VerifyOrExit(!otMacFrameIsSecurityEnabled(aFrame) || !aFrame->mInfo.mTxInfo.mIsSecurityProcessed);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (static_cast<Mac::Frame *>(aFrame)->Has<Mac::CslIe>()) // CSL IE should be filled for every transmit attempt
{
otMacFrameSetCslIe(aFrame, aRadioContext->mCslPeriod,
ComputeCslPhase(static_cast<uint32_t>(aRadioTime), aRadioContext));
Mac::Frame::ParseInfo frameInfo;
if ((ParseFully(aFrame, frameInfo) == kErrorNone) && frameInfo.Has<Mac::CslIe>())
{
otMacFrameSetCslIe(aFrame, aRadioContext->mCslPeriod,
ComputeCslPhase(static_cast<uint32_t>(aRadioTime), aRadioContext));
}
}
#endif
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
@@ -414,23 +480,22 @@ exit:
bool otMacFrameSrcAddrMatchCslReceiverPeer(const otRadioFrame *aFrame, const otRadioContext *aRadioContext)
{
const Mac::Frame &frame = *static_cast<const Mac::Frame *>(aFrame);
bool matches = false;
Mac::Address src;
bool matches = false;
Mac::Frame::ParseInfo frameInfo;
VerifyOrExit(frame.GetSrcAddr(src) == kErrorNone);
SuccessOrExit(ParseAddrFields(aFrame, frameInfo));
switch (src.GetType())
switch (frameInfo.mAddrs.mSource.GetType())
{
case Mac::Address::kTypeShort:
VerifyOrExit(aRadioContext->mCslShortAddress != Mac::kShortAddrBroadcast &&
aRadioContext->mCslShortAddress != Mac::kShortAddrInvalid);
VerifyOrExit(src.GetShort() == aRadioContext->mCslShortAddress);
VerifyOrExit(frameInfo.mAddrs.mSource.GetShort() == aRadioContext->mCslShortAddress);
matches = true;
break;
case Mac::Address::kTypeExtended:
VerifyOrExit(src.GetExtended() == *static_cast<const Mac::ExtAddress *>(&aRadioContext->mCslExtAddress));
VerifyOrExit(frameInfo.mAddrs.mSource.GetExtended() == AsCoreType(&aRadioContext->mCslExtAddress));
matches = true;
break;
+4 -5
View File
@@ -967,12 +967,11 @@ exit:
bool Diags::ShouldHandleReceivedFrame(const otRadioFrame &aFrame) const
{
bool ret = false;
const Mac::RxFrame &frame = static_cast<const Mac::RxFrame &>(aFrame);
Mac::Address dstAddress;
bool ret = false;
Mac::RxFrame::ParseInfo frameInfo;
VerifyOrExit(frame.GetDstAddr(dstAddress) == kErrorNone);
VerifyOrExit(dstAddress == mReceiveConfig.mFilterAddress);
SuccessOrExit(frameInfo.ParseFrom(static_cast<const Mac::RxFrame &>(aFrame), Mac::Frame::kParseAddrFields));
VerifyOrExit(frameInfo.mAddrs.mDestination == mReceiveConfig.mFilterAddress);
ret = true;
exit:
+30 -32
View File
@@ -83,34 +83,33 @@ void DataPollHandler::RequestFrameChange(FrameChange aChange, Child &aChild)
}
}
void DataPollHandler::HandleDataPoll(Mac::RxFrame &aFrame)
void DataPollHandler::HandleDataPoll(Mac::RxFrame::ParseInfo &aFrameInfo)
{
Mac::Address macSource;
Child *child;
uint16_t indirectMsgCount;
Child *child;
uint16_t indirectMsgCount;
VerifyOrExit(aFrame.IsSecuredWith(Mac::RxFrame::kAllowKeyIdMode1));
VerifyOrExit(aFrameInfo.mIsSecurityEnabled);
VerifyOrExit(aFrameInfo.mKeyIdMode == Mac::Frame::kKeyIdMode1);
VerifyOrExit(!Get<Mle::Mle>().IsDetached());
SuccessOrExit(aFrame.GetSrcAddr(macSource));
child = Get<ChildTable>().FindChild(macSource, Child::kInStateValidOrRestoring);
child = Get<ChildTable>().FindChild(aFrameInfo.mAddrs.mSource, Child::kInStateValidOrRestoring);
VerifyOrExit(child != nullptr);
child->SetLastHeard(TimerMilli::GetNow());
child->ResetLinkFailures();
#if OPENTHREAD_CONFIG_MULTI_RADIO
child->SetLastPollRadioType(aFrame.GetRadioType());
child->SetLastPollRadioType(aFrameInfo.GetRxFrame()->GetRadioType());
#endif
indirectMsgCount = child->GetIndirectMessageCount();
LogInfo("Rx data poll, src:0x%04x, qed_msgs:%d, rss:%d, ack-fp:%d", child->GetRloc16(), indirectMsgCount,
aFrame.GetRssi(), aFrame.IsAckedWithFramePending());
aFrameInfo.GetRxFrame()->GetRssi(), aFrameInfo.GetRxFrame()->IsAckedWithFramePending());
if (!aFrame.IsAckedWithFramePending())
if (!aFrameInfo.GetRxFrame()->IsAckedWithFramePending())
{
if ((indirectMsgCount > 0) && macSource.IsShort())
if ((indirectMsgCount > 0) && aFrameInfo.mAddrs.mSource.IsShort())
{
Get<SourceMatchController>().SetSrcMatchAsShort(*child, true);
}
@@ -157,13 +156,18 @@ Mac::TxFrame *DataPollHandler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
// child, we ensure to use the same frame counter, key id, and
// data sequence number as the previous attempt.
frame->SetIsARetransmission(true);
frame->SetSequence(mIndirectTxChild->GetIndirectDataSequenceNumber());
Mac::TxFrame::ParseInfo frameInfo;
if (frame->GetSecurityEnabled())
frame->SetIsARetransmission(true);
IgnoreError(frameInfo.ParseFrom(*frame, Mac::Frame::kParseFully));
frameInfo.WriteSequenceNum(mIndirectTxChild->GetIndirectDataSequenceNumber());
if (frameInfo.mIsSecurityEnabled)
{
frame->SetFrameCounter(mIndirectTxChild->GetIndirectFrameCounter());
frame->SetKeyIndex(mIndirectTxChild->GetIndirectKeyIndex());
frameInfo.WriteFrameCounter(mIndirectTxChild->GetIndirectFrameCounter());
frameInfo.WriteKeyIndex(mIndirectTxChild->GetIndirectKeyIndex());
}
}
else
@@ -175,20 +179,20 @@ exit:
return frame;
}
void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
void DataPollHandler::HandleSentFrame(const Mac::TxFrame::ParseInfo &aFrameInfo, Error aError)
{
Child *child = mIndirectTxChild;
VerifyOrExit(child != nullptr);
mIndirectTxChild = nullptr;
HandleSentFrame(aFrame, aError, *child);
HandleSentFrame(aFrameInfo, aError, *child);
exit:
ProcessPendingPolls();
}
void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild)
void DataPollHandler::HandleSentFrame(const Mac::TxFrame::ParseInfo &aFrameInfo, Error aError, Child &aChild)
{
if (aChild.IsFramePurgePending())
{
@@ -207,7 +211,7 @@ void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError,
break;
case kErrorNoAck:
OT_ASSERT(!aFrame.GetSecurityEnabled() || aFrame.IsHeaderUpdated());
OT_ASSERT(!aFrameInfo.mIsSecurityEnabled || aFrameInfo.GetTxFrame()->IsHeaderUpdated());
aChild.IncrementIndirectTxAttempts();
LogInfo("Indirect tx to child %04x failed, attempt %d/%d", aChild.GetRloc16(), aChild.GetIndirectTxAttempts(),
@@ -226,24 +230,18 @@ void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError,
ExitNow();
}
if ((aChild.GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts) && !aFrame.IsEmpty())
if ((aChild.GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts) && !aFrameInfo.GetTxFrame()->IsEmpty())
{
// We save the frame counter, key id, and data sequence number of
// current frame so we use the same values for the retransmission
// of the frame following the receipt of the next data poll.
aChild.SetIndirectDataSequenceNumber(aFrame.GetSequence());
aChild.SetIndirectDataSequenceNumber(aFrameInfo.mSequenceNum);
if (aFrame.GetSecurityEnabled() && aFrame.IsHeaderUpdated())
if (aFrameInfo.mIsSecurityEnabled && aFrameInfo.GetTxFrame()->IsHeaderUpdated())
{
uint32_t frameCounter;
uint8_t keyIndex;
SuccessOrAssert(aFrame.GetFrameCounter(frameCounter));
aChild.SetIndirectFrameCounter(frameCounter);
SuccessOrAssert(aFrame.GetKeyIndex(keyIndex));
aChild.SetIndirectKeyIndex(keyIndex);
aChild.SetIndirectFrameCounter(aFrameInfo.mFrameCounter);
aChild.SetIndirectKeyIndex(aFrameInfo.mKeyIndex);
}
ExitNow();
@@ -256,7 +254,7 @@ void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError,
OT_ASSERT(false);
}
Get<IndirectSender>().HandleSentFrameToChild(aFrame, mFrameContext, aError, aChild);
Get<IndirectSender>().HandleSentFrameToChild(aFrameInfo, mFrameContext, aError, aChild);
exit:
return;
+3 -3
View File
@@ -185,11 +185,11 @@ private:
typedef IndirectSenderBase::FrameContext FrameContext;
// Callbacks from MAC
void HandleDataPoll(Mac::RxFrame &aFrame);
void HandleDataPoll(Mac::RxFrame::ParseInfo &aFrameInfo);
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError);
void HandleSentFrame(const Mac::TxFrame::ParseInfo &aFrameInfo, Error aError);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild);
void HandleSentFrame(const Mac::TxFrame::ParseInfo &aFrameInfo, Error aError, Child &aChild);
void ProcessPendingPolls(void);
void ResetTxAttempts(Child &aChild);
+17 -16
View File
@@ -190,18 +190,17 @@ uint32_t DataPollSender::GetKeepAlivePollPeriod(void) const
return period;
}
void DataPollSender::HandlePollSent(Mac::TxFrame &aFrame, Error aError)
void DataPollSender::HandlePollSent(Mac::TxFrame::ParseInfo &aFrameInfo, Error aError)
{
Mac::Address macDest;
bool shouldRecalculatePollPeriod = false;
uint8_t maxRetxAttempts;
bool shouldRecalculatePollPeriod = false;
uint8_t maxRetxAttempts;
VerifyOrExit(mEnabled);
if (!aFrame.IsEmpty())
if (!aFrameInfo.GetTxFrame()->IsEmpty())
{
IgnoreError(aFrame.GetDstAddr(macDest));
Get<MeshForwarder>().UpdateNeighborOnSentFrame(aFrame, aError, macDest, /* aIsDataPoll */ true);
Get<MeshForwarder>().UpdateNeighborOnSentFrame(aFrameInfo, aError, aFrameInfo.mAddrs.mDestination,
/* aIsDataPoll */ true);
}
if (GetParent().IsStateInvalid())
@@ -245,7 +244,7 @@ void DataPollSender::HandlePollSent(Mac::TxFrame &aFrame, Error aError)
mPollTxFailureCounter++;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
maxRetxAttempts = aFrame.Has<Mac::CslIe>() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts;
maxRetxAttempts = aFrameInfo.Has<Mac::CslIe>() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts;
#else
maxRetxAttempts = kMaxPollRetxAttempts;
#endif
@@ -304,13 +303,13 @@ exit:
return;
}
void DataPollSender::ProcessRxFrame(const Mac::RxFrame &aFrame)
void DataPollSender::ProcessRxFrame(const Mac::RxFrame::ParseInfo &aFrameInfo)
{
VerifyOrExit(mEnabled);
mPollTimeoutCounter = 0;
if (aFrame.GetFramePending())
if (aFrameInfo.mIsFramePending)
{
IgnoreError(SendDataPoll());
}
@@ -320,27 +319,29 @@ exit:
}
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
void DataPollSender::ProcessTxDone(const Mac::TxFrame &aFrame, const Mac::RxFrame *aAckFrame, Error aError)
void DataPollSender::ProcessTxDone(const Mac::TxFrame::ParseInfo &aFrameInfo,
const Mac::RxFrame::ParseInfo &aAckFrameInfo,
Error aError)
{
bool sendDataPoll = false;
VerifyOrExit(mEnabled);
VerifyOrExit(Get<Mle::Mle>().GetParent().IsEnhancedKeepAliveSupported());
VerifyOrExit(aFrame.GetSecurityEnabled());
VerifyOrExit(aFrameInfo.mIsSecurityEnabled);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (aFrame.IsARetransmission() && aFrame.Has<Mac::CslIe>())
if (aFrameInfo.GetTxFrame()->IsARetransmission() && aFrameInfo.Has<Mac::CslIe>())
{
// For retransmission frame, use a data poll to resync its parent with correct CSL phase
sendDataPoll = true;
}
#endif
if (aError == kErrorNone && aAckFrame != nullptr)
if (aError == kErrorNone && aAckFrameInfo.GetRxFrame() != nullptr)
{
mPollTimeoutCounter = 0;
if (aAckFrame->GetFramePending())
if (aAckFrameInfo.mIsFramePending)
{
sendDataPoll = true;
}
@@ -571,7 +572,7 @@ Mac::TxFrame *DataPollSender::PrepareDataRequest(Mac::TxFrames &aTxFrames)
Get<MessageFramer>().PrepareMacHeaders(*frame, buildInfo);
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (frame->Has<Mac::CslIe>())
if (buildInfo.mAppendCslIe)
{
// Disable frame retransmission when the data poll has CSL IE included
aTxFrames.SetMaxFrameRetries(0);
+14 -12
View File
@@ -128,10 +128,10 @@ public:
* In case of transmit failure, the data poll sender may choose to send the next data poll more quickly (up to
* some fixed number of attempts).
*
* @param[in] aFrame The data poll frame.
* @param[in] aError Error status of a data poll message transmission.
* @param[in] aFrameInfo The data poll frame information.
* @param[in] aError Error status of a data poll message transmission.
*/
void HandlePollSent(Mac::TxFrame &aFrame, Error aError);
void HandlePollSent(Mac::TxFrame::ParseInfo &aFrameInfo, Error aError);
/**
* Informs the data poll sender that a data poll timeout happened, i.e., when the ack in response to
@@ -144,22 +144,24 @@ public:
/**
* Informs the data poll sender to process a received MAC frame.
*
* @param[in] aFrame A reference to the received frame to process.
* @param[in] aFrameInfo The received frame parsed information to process.
*/
void ProcessRxFrame(const Mac::RxFrame &aFrame);
void ProcessRxFrame(const Mac::RxFrame::ParseInfo &aFrameInfo);
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
/**
* Informs the data poll sender to process a transmitted MAC frame.
*
* @param[in] aFrame A reference to the frame that was transmitted.
* @param[in] aAckFrame A pointer to the ACK frame, `nullptr` if no ACK was received.
* @param[in] aError kErrorNone when the frame was transmitted successfully,
* kErrorNoAck when the frame was transmitted but no ACK was received,
* kErrorChannelAccessFailure when the tx failed due to activity on the channel,
* kErrorAbort when transmission was aborted for other reasons.
* @param[in] aFrameInfo The sent frame information.
* @param[in] aAckFrameInfo The ACK frame information (its `mFrame` may be `nullptr` if no ACK was received).
* @param[in] aError kErrorNone when the frame was transmitted successfully,
* kErrorNoAck when the frame was transmitted but no ACK was received,
* kErrorChannelAccessFailure when the tx failed due to activity on the channel,
* kErrorAbort when transmission was aborted for other reasons.
*/
void ProcessTxDone(const Mac::TxFrame &aFrame, const Mac::RxFrame *aAckFrame, Error aError);
void ProcessTxDone(const Mac::TxFrame::ParseInfo &aFrameInfo,
const Mac::RxFrame::ParseInfo &aAckFrameInfo,
Error aError);
#endif
/**
+8 -5
View File
@@ -207,13 +207,13 @@ exit:
return error;
}
void LinkRaw::InvokeTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
void LinkRaw::InvokeTransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError)
{
LogDebg("TransmitDone(%d bytes), error:%s", aFrame.mLength, ErrorToString(aError));
LogDebg("TransmitDone(%u bytes), error:%s", aFrameInfo.GetTxFrame()->GetLength(), ErrorToString(aError));
if (mTransmitDoneCallback)
{
mTransmitDoneCallback(&GetInstance(), &aFrame, aAckFrame, aError);
mTransmitDoneCallback(&GetInstance(), aFrameInfo.GetTxFrame(), aAckFrame, aError);
mTransmitDoneCallback = nullptr;
}
}
@@ -267,14 +267,17 @@ exit:
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void LinkRaw::RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx)
void LinkRaw::RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx)
{
OT_UNUSED_VARIABLE(aWillRetx);
if (aError != kErrorNone)
{
LogInfo("Frame tx failed, error:%s, retries:%d/%d, %s", ErrorToString(aError), aRetryCount,
aFrame.GetMaxFrameRetries(), aFrame.ToInfoString().AsCString());
aFrameInfo.GetTxFrame()->GetMaxFrameRetries(), aFrameInfo.ToInfoString().AsCString());
}
}
+6 -3
View File
@@ -241,12 +241,15 @@ public:
private:
// Callbacks from `SubMac`
void InvokeReceiveDone(RxFrame *aFrame, Error aError);
void InvokeTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
void InvokeTransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError);
void InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx);
void RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx);
#else
void RecordFrameTransmitStatus(const TxFrame &, Error, uint8_t, bool) {}
void RecordFrameTransmitStatus(const TxFrame::ParseInfo &, Error, uint8_t, bool) {}
#endif
uint8_t mReceiveChannel;
+286 -246
View File
File diff suppressed because it is too large Load Diff
+23 -15
View File
@@ -754,17 +754,21 @@ private:
// Callbacks from `SubMac` or `Trel::Link`
void HandleReceivedFrame(RxFrame *aFrame, Error aError);
void RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel);
void RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx);
void HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
void RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx);
void HandleTransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError);
void EnergyScanDone(int8_t aEnergyScanMaxRssi);
Error ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neighbor *aNeighbor);
Error ProcessReceiveSecurity(RxFrame::ParseInfo &aFrameInfo, const Address &aSrcAddr, Neighbor *aNeighbor);
void ProcessTransmitSecurity(TxFrame &aFrame);
void ProcessTransmitSecurity(TxFrame::ParseInfo &aFrameInfo);
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
Error ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame);
Error ProcessEnhAckSecurity(TxFrame::ParseInfo &aTxFrameInfo, RxFrame::ParseInfo &aAckFrameInfo);
#endif
const KeyMaterial *DetermineMode1Key(const Frame &aFrame) const;
const KeyMaterial *DetermineMode1KeyAndSequence(const Frame &aFrame, uint32_t &aKeySequence) const;
const KeyMaterial *DetermineMode1Key(const Frame::ParseInfo &aFrameInfo) const;
const KeyMaterial *DetermineMode1KeyAndSequence(const Frame::ParseInfo &aFrameInfo, uint32_t &aKeySequence) const;
void UpdateIdleMode(void);
bool IsPending(Operation aOperation) const { return mPendingOperations & (1U << aOperation); }
@@ -779,27 +783,31 @@ private:
bool ShouldSendBeacon(void) const;
bool IsJoinable(void) const;
void BeginTransmit(void);
void HandleTxFramePrepFailed(TxFrames &aTxFrames);
Error FilterDestShortAddress(ShortAddress aDestAddress) const;
void UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame &aRxFrame);
void HandleMacCommand(RxFrame &aFrame);
void UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame::ParseInfo &aRxFrameInfo);
void HandleMacCommand(RxFrame::ParseInfo &aFrameInfo);
void HandleTimer(void);
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
Error ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError);
Error ProcessTxDone(TxFrame::ParseInfo &aFrameInfo, RxFrame::ParseInfo &aAckFrameInfo, Error &aError);
#endif
#if OPENTHREAD_CONFIG_MULTI_RADIO
Error ProcessMultiRadioTxDone(TxFrame &aFrame, Error &aError);
Error ProcessMultiRadioTxDone(TxFrame::ParseInfo &aFrameInfo, Error &aError);
#endif
Error CanScan(void) const;
void Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration);
Error UpdateScanChannel(void);
void PerformActiveScan(void);
void ReportActiveScanResult(const RxFrame *aBeaconFrame);
void ReportActiveScanResult(const RxFrame::ParseInfo *aBeaconFrameInfo);
void PerformEnergyScan(void);
void ReportEnergyScanResult(int8_t aRssi);
void LogFrameRxFailure(const RxFrame *aFrame, Error aError) const;
void LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) const;
void LogFrameRxFailure(const RxFrame::ParseInfo &aFrameInfo, Error aError) const;
void LogFrameTxFailure(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx) const;
void LogBeacon(const char *aActionText) const;
void LogOperation(OperationAction aAction, Operation aOperation) const;
@@ -807,14 +815,14 @@ private:
static const char *OperationActionToString(OperationAction aAction);
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr);
void ProcessCsl(const RxFrame::ParseInfo &aFrameInfo, const Address &aSrcAddr);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
void UpdateCslParameters(void);
void UpdateCslState(void);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
void ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor);
void ProcessEnhAckProbing(const RxFrame::ParseInfo &aFrameInfo, const Neighbor &aNeighbor);
#endif
#if OPENTHREAD_CONFIG_TD_WAKE_LISTENER_ENABLE
void UpdateWakeupListening(void);
+152 -330
View File
@@ -278,6 +278,10 @@ Error Frame::ParseInfo::ParseFrom(const Frame &aFrame, ParseMode aMode)
PanId panId;
uint8_t value;
Clear();
mFrame = &aFrame;
VerifyOrExit(aFrame.GetPsdu() != nullptr);
frameData.Init(aFrame.GetPsdu(), aFrame.GetLength());
@@ -332,6 +336,8 @@ Error Frame::ParseInfo::ParseFrom(const Frame &aFrame, ParseMode aMode)
SuccessOrExit(frameData.RemoveFooter(aFrame.GetFcsSize()));
mParsedAddrFields = true;
if (aMode == kParseAddrFields)
{
ExitNow(error = kErrorNone);
@@ -369,6 +375,8 @@ Error Frame::ParseInfo::ParseFrom(const Frame &aFrame, ParseMode aMode)
mMicSize = CalculateMicSize(mSecurityLevel);
SuccessOrExit(frameData.RemoveFooter(mMicSize));
mParsedSecurityHeader = true;
}
if (aMode == kParseSecurityHeader)
@@ -439,6 +447,8 @@ Error Frame::ParseInfo::ParseFrom(const Frame &aFrame, ParseMode aMode)
mHeader.InitFromRange(aFrame.GetPsdu(), frameData.GetBytes());
mPayload = frameData;
mParsedFully = true;
error = kErrorNone;
exit:
@@ -476,15 +486,55 @@ exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
Error Frame::ValidatePsdu(void) const
Error Frame::ParseInfo::PerformAesCcm(AesCcmOperation aOperation,
const ExtAddress &aExtAddress,
const KeyMaterial &aMacKey)
{
ParseInfo info;
Error error = kErrorSecurity;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
Crypto::AesCcm::Operation operation;
return info.ParseFrom(*this, kParseFully);
static_assert(static_cast<uint8_t>(kEncrypt) == Crypto::AesCcm::kEncrypt, "kEncrypt enum value is incorrect");
static_assert(static_cast<uint8_t>(kDecrypt) == Crypto::AesCcm::kDecrypt, "kDecrypt enum value is incorrect");
VerifyOrExit(mParsedFully, error = kErrorParse);
VerifyOrExit(mIsSecurityEnabled, error = kErrorNone);
nonce.InitFrom(aExtAddress, mFrameCounter, mSecurityLevel);
aesCcm.SetKey(aMacKey);
aesCcm.SetNonce(nonce);
aesCcm.SetAuthData(mHeader.GetBytes(), mHeader.GetLength());
aesCcm.SetTagLength(mMicSize);
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (aOperation == kDecrypt)
{
// Do not decrypt when fuzzing
ExitNow(error = kErrorNone);
}
#endif
operation = static_cast<Crypto::AesCcm::Operation>(aOperation);
SuccessOrExit(error = aesCcm.Process(operation, AsNonConst(mPayload.GetBytes()), mPayload.GetLength()));
// In a 2015 version, the Command ID of a MAC command frame is
// part of the encrypted payload. Now that the payload is
// decrypted, we update `mCommandId` with its decrypted value.
if ((aOperation == kDecrypt) && (mType == kTypeMacCmd) && (mVersion == kVersion2015))
{
mCommandId = *mPayload.GetBytes();
}
exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
uint16_t Frame::ConstructFrameControlField(Type aType, uint8_t aVersion)
{
return static_cast<uint16_t>(aType | (aVersion << kFcfVersionShift));
@@ -560,43 +610,16 @@ bool Frame::IsDstPanIdPresent(uint16_t aFcf)
return present;
}
Error Frame::GetDstPanId(PanId &aPanId) const
void TxFrame::ParseInfo::WriteSequenceNum(uint8_t aSequenceNum)
{
Error error;
ParseInfo info;
VerifyOrExit(mParsedAddrFields);
VerifyOrExit(mIsSeqNumPresent);
SuccessOrExit(error = info.ParseFrom(*this, kParseAddrFields));
VerifyOrExit(info.mPanIds.IsDestinationPresent(), error = kErrorNotFound);
aPanId = info.mPanIds.GetDestination();
mSequenceNum = aSequenceNum;
GetTxFrame()->GetPsdu()[kSeqNumIndex] = aSequenceNum;
exit:
return error;
}
uint8_t Frame::GetSequence(void) const
{
OT_ASSERT(IsSequencePresent());
return GetPsdu()[kFcfSize];
}
void Frame::SetSequence(uint8_t aSequence)
{
OT_ASSERT(IsSequencePresent());
GetPsdu()[kFcfSize] = aSequence;
}
Error Frame::GetDstAddr(Address &aAddress) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseAddrFields));
aAddress = info.mAddrs.mDestination;
exit:
return error;
return;
}
bool Frame::IsSrcPanIdPresent(uint16_t aFcf)
@@ -643,107 +666,17 @@ bool Frame::IsSrcPanIdPresent(uint16_t aFcf)
return present;
}
Error Frame::GetSrcPanId(PanId &aPanId) const
void TxFrame::ParseInfo::WriteFrameCounter(uint32_t aFrameCounter)
{
Error error;
ParseInfo info;
VerifyOrExit(mParsedSecurityHeader);
SuccessOrExit(error = info.ParseFrom(*this, kParseAddrFields));
VerifyOrExit(info.mPanIds.IsSourcePresent(), error = kErrorNotFound);
aPanId = info.mPanIds.GetSource();
mFrameCounter = aFrameCounter;
LittleEndian::WriteUint32(aFrameCounter, mFrameCounterBytes);
GetTxFrame()->SetIsHeaderUpdated(true);
exit:
return error;
}
Error Frame::GetSrcAddr(Address &aAddress) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseAddrFields));
aAddress = info.mAddrs.mSource;
exit:
return error;
}
Error Frame::GetSecurityLevel(SecurityLevel &aSecurityLevel) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseSecurityHeader));
aSecurityLevel = info.mSecurityLevel;
exit:
return error;
}
bool Frame::HasSecurityLevel(SecurityLevel aSecurityLevel) const
{
bool has = false;
SecurityLevel securityLevel;
SuccessOrExit(GetSecurityLevel(securityLevel));
has = (securityLevel == aSecurityLevel);
exit:
return has;
}
Error Frame::GetKeyIdMode(KeyIdMode &aKeyIdMode) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseSecurityHeader));
aKeyIdMode = info.mKeyIdMode;
exit:
return error;
}
bool Frame::HasKeyIdMode(KeyIdMode aKeyIdMode) const
{
bool has = false;
KeyIdMode keyIdMode;
SuccessOrExit(GetKeyIdMode(keyIdMode));
has = (keyIdMode == aKeyIdMode);
exit:
return has;
}
Error Frame::GetFrameCounter(uint32_t &aFrameCounter) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseSecurityHeader));
aFrameCounter = info.mFrameCounter;
exit:
return error;
}
void Frame::SetFrameCounter(uint32_t aFrameCounter)
{
ParseInfo info;
SuccessOrAssert(info.ParseFrom(*this, kParseSecurityHeader));
LittleEndian::WriteUint32(aFrameCounter, info.mFrameCounterBytes);
static_cast<TxFrame *>(this)->SetIsHeaderUpdated(true);
}
void Frame::GetKeySource(FrameData &aKeySource) const
{
ParseInfo info;
SuccessOrAssert(info.ParseFrom(*this, kParseSecurityHeader));
aKeySource = info.mKeySource;
return;
}
uint8_t Frame::CalculateKeySourceSize(KeyIdMode aKeyIdMode)
@@ -764,75 +697,29 @@ uint8_t Frame::CalculateKeySourceSize(KeyIdMode aKeyIdMode)
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void Frame::SetKeySource(const uint8_t *aKeySource)
void TxFrame::ParseInfo::WriteKeySource(const uint8_t *aKeySource)
{
ParseInfo info;
VerifyOrExit(mParsedSecurityHeader);
VerifyOrExit(!mKeySource.IsEmpty());
SuccessOrAssert(info.ParseFrom(*this, kParseSecurityHeader));
memcpy(AsNonConst(info.mKeySource.GetBytes()), aKeySource, info.mKeySource.GetLength());
}
VerifyOrExit(aKeySource != nullptr);
Error Frame::GetKeyIndex(uint8_t &aKeyIndex) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseSecurityHeader));
VerifyOrExit(info.mKeyIdMode != kKeyIdMode0, error = kErrorNotFound);
aKeyIndex = info.mKeyIndex;
exit:
return error;
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void Frame::SetKeyIndex(uint8_t aKeyIndex)
{
ParseInfo info;
SuccessOrAssert(info.ParseFrom(*this, kParseSecurityHeader));
VerifyOrExit(info.mKeyIdMode != kKeyIdMode0);
*info.mKeyIndexByte = aKeyIndex;
memcpy(AsNonConst(mKeySource.GetBytes()), aKeySource, mKeySource.GetLength());
exit:
return;
}
Error Frame::GetCommandId(uint8_t &aCommandId) const
void TxFrame::ParseInfo::WriteKeyIndex(uint8_t aKeyIndex)
{
Error error;
ParseInfo info;
VerifyOrExit(mParsedSecurityHeader);
VerifyOrExit(mKeyIdMode != kKeyIdMode0);
SuccessOrExit(error = info.ParseFrom(*this, kParseFully));
VerifyOrExit(info.mType == kTypeMacCmd, error = kErrorNotFound);
aCommandId = info.mCommandId;
mKeyIndex = aKeyIndex;
*mKeyIndexByte = aKeyIndex;
exit:
return error;
}
bool Frame::IsDataRequestCommand(void) const
{
bool isDataRequest = false;
uint8_t commandId;
SuccessOrExit(GetCommandId(commandId));
isDataRequest = (commandId == kMacCmdDataRequest);
exit:
return isDataRequest;
}
Error Frame::GetPayload(FrameData &aPayloadData) const
{
Error error;
ParseInfo info;
SuccessOrExit(error = info.ParseFrom(*this, kParseFully));
aPayloadData = info.mPayload;
exit:
return error;
return;
}
Error Frame::DetermineLengths(Lengths &aLengths) const
@@ -909,22 +796,18 @@ Frame::KeyIdMode Frame::ReadKeyIdMode(uint8_t aSecCtl)
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
const HeaderIe *Frame::FindHeaderIe(HeaderIeMatcher aMatcher) const
const HeaderIe *Frame::ParseInfo::FindHeaderIe(HeaderIeMatcher aMatcher) const
{
const HeaderIe *matchedIe = nullptr;
ParseInfo info;
FrameData ieData;
SuccessOrExit(info.ParseFrom(*this, kParseFully));
VerifyOrExit(mIsIePresent);
VerifyOrExit(info.mIsIePresent);
// `ParseFrom()` already validates that Header IE(s) are
// well-formed and contained within the frame. Here we
// just iterate through them and try to match them.
ieData = mIeData;
while (true)
{
const HeaderIe *ie = info.mIeData.Read<HeaderIe>();
const HeaderIe *ie = ieData.Read<HeaderIe>();
VerifyOrExit(ie != nullptr);
@@ -934,7 +817,7 @@ const HeaderIe *Frame::FindHeaderIe(HeaderIeMatcher aMatcher) const
ExitNow();
}
info.mIeData.SkipOver(ie->GetLength());
ieData.SkipOver(ie->GetLength());
}
exit:
@@ -942,10 +825,15 @@ exit:
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
// NOLINTNEXTLINE(readability-make-member-function-const)
void Frame::UpdateCslIe(uint16_t aCslPeriod, uint16_t aCslPhase)
{
CslIe *csl = Find<CslIe>();
ParseInfo info;
CslIe *csl;
SuccessOrExit(info.ParseFrom(*this, kParseFully));
csl = info.Find<CslIe>();
VerifyOrExit(csl != nullptr);
csl->SetPeriod(aCslPeriod);
@@ -957,10 +845,15 @@ exit:
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
// NOLINTNEXTLINE(readability-make-member-function-const)
void Frame::UpdateEnhAckProbingIe(const uint8_t *aData, uint8_t aLen)
{
LinkMetricsProbingIe *probingIe = Find<LinkMetricsProbingIe>();
ParseInfo info;
LinkMetricsProbingIe *probingIe;
SuccessOrExit(info.ParseFrom(*this, kParseFully));
probingIe = info.Find<LinkMetricsProbingIe>();
VerifyOrExit(probingIe != nullptr);
VerifyOrExit(aLen >= probingIe->GetMetricsDataLen());
@@ -1024,68 +917,40 @@ void TxFrame::CopyFrom(const TxFrame &aFromFrame)
#endif
}
void TxFrame::ProcessTransmitAesCcm(const ExtAddress &aExtAddress)
void TxFrame::ParseInfo::ProcessTransmitAesCcm(const ExtAddress &aExtAddress)
{
#if OPENTHREAD_FTD || OPENTHREAD_MTD || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
VerifyOrExit(GetSecurityEnabled());
SuccessOrExit(PerformAesCcm(kEncrypt, aExtAddress));
SetIsSecurityProcessed(true);
VerifyOrExit(mParsedFully);
VerifyOrExit(mIsSecurityEnabled);
SuccessOrExit(PerformAesCcm(kEncrypt, aExtAddress, GetTxFrame()->GetAesKey()));
GetTxFrame()->SetIsSecurityProcessed(true);
exit:
return;
#else
OT_UNUSED_VARIABLE(aExtAddress);
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
}
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
void TxFrame::RestoreTransmitSecurity(const ExtAddress &aExtAddress)
void TxFrame::ParseInfo::RestoreTransmitSecurity(const ExtAddress &aExtAddress)
{
VerifyOrExit(GetSecurityEnabled() && IsSecurityProcessed());
IgnoreError(PerformAesCcm(kDecrypt, aExtAddress));
SetIsSecurityProcessed(false);
VerifyOrExit(mParsedFully);
VerifyOrExit(mIsSecurityEnabled);
VerifyOrExit(GetTxFrame()->IsSecurityProcessed());
IgnoreError(PerformAesCcm(kDecrypt, aExtAddress, GetTxFrame()->GetAesKey()));
GetTxFrame()->SetIsSecurityProcessed(false);
exit:
SetIsHeaderUpdated(false);
GetTxFrame()->SetIsHeaderUpdated(false);
}
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
#if OPENTHREAD_FTD || OPENTHREAD_MTD || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE || \
(OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE)
Error TxFrame::PerformAesCcm(AesCcmOperation aOperation, const ExtAddress &aExtAddress)
{
static_assert(static_cast<uint8_t>(kEncrypt) == Crypto::AesCcm::kEncrypt, "kEncrypt enum value is incorrect");
static_assert(static_cast<uint8_t>(kDecrypt) == Crypto::AesCcm::kDecrypt, "kDecrypt enum value is incorrect");
Error error;
ParseInfo info;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
SuccessOrExit(error = info.ParseFrom(*this, kParseFully));
nonce.InitFrom(aExtAddress, info.mFrameCounter, info.mSecurityLevel);
aesCcm.SetKey(GetAesKey());
aesCcm.SetNonce(nonce);
aesCcm.SetAuthData(info.mHeader.GetBytes(), info.mHeader.GetLength());
aesCcm.SetTagLength(info.mMicSize);
error = aesCcm.Process(static_cast<Crypto::AesCcm::Operation>(aOperation), AsNonConst(info.mPayload.GetBytes()),
info.mPayload.GetLength());
exit:
return error;
}
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE || ...
#endif
void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
{
uint16_t fcf = ConstructFrameControlField(kTypeAck, aFrame.GetVersion());
uint16_t fcf;
RxFrame::ParseInfo rxInfo;
mChannel = aFrame.mChannel;
IgnoreError(rxInfo.ParseFrom(aFrame, kParseAddrFields));
fcf = ConstructFrameControlField(kTypeAck, rxInfo.mVersion);
mChannel = aFrame.GetChannel();
ClearAllBytes(mInfo.mTxInfo);
if (aIsFramePending)
@@ -1094,7 +959,7 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
}
LittleEndian::WriteUint16(fcf, mPsdu);
mPsdu[kFcfSize] = aFrame.GetSequence();
mPsdu[kFcfSize] = rxInfo.mSequenceNum;
mLength = kImmAckLength;
}
@@ -1102,9 +967,10 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength)
{
Error error = kErrorParse;
ParseInfo rxInfo;
BuildInfo buildInfo;
Error error = kErrorParse;
RxFrame::ParseInfo rxInfo;
BuildInfo buildInfo;
ParseInfo ackInfo;
buildInfo.mType = kTypeAck;
buildInfo.mVersion = kVersion2015;
@@ -1156,23 +1022,22 @@ Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, con
PrepareHeadersWithEmptyPayload(buildInfo);
IgnoreError(ackInfo.ParseFrom(*this, kParseFully));
SetFramePending(aIsFramePending);
SetSequence(rxInfo.mSequenceNum);
ackInfo.WriteSequenceNum(rxInfo.mSequenceNum);
if (rxInfo.mIsSecurityEnabled)
{
SetKeyIndex(rxInfo.mKeyIndex);
ackInfo.WriteKeyIndex(rxInfo.mKeyIndex);
}
if (aIeLength > 0)
{
ParseInfo info;
SuccessOrAssert(info.ParseFrom(*this, kParseFully));
OT_ASSERT(aIeData != nullptr);
SetIePresent(true);
memcpy(GetPsduStartingAt(info.mHeader.GetLength()), aIeData, aIeLength);
memcpy(GetPsduStartingAt(ackInfo.mHeader.GetLength()), aIeData, aIeLength);
SetLength(GetLength() + aIeLength);
}
@@ -1181,90 +1046,45 @@ exit:
}
#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
bool RxFrame::IsSecuredWith(KeyIdModeFlags aFlags) const
{
bool isSecure = false;
KeyIdMode keyIdMode;
VerifyOrExit(GetSecurityEnabled());
SuccessOrExit(GetKeyIdMode(keyIdMode));
switch (keyIdMode)
{
case kKeyIdMode0:
VerifyOrExit(aFlags & kAllowKeyIdMode0);
break;
case kKeyIdMode1:
VerifyOrExit(aFlags & kAllowKeyIdMode1);
break;
default:
ExitNow();
}
isSecure = true;
exit:
return isSecure;
}
#if OPENTHREAD_FTD || OPENTHREAD_MTD
Error RxFrame::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey)
Error RxFrame::ParseInfo::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey)
{
Error error = kErrorSecurity;
ParseInfo info;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
VerifyOrExit(GetSecurityEnabled(), error = kErrorNone);
SuccessOrExit(info.ParseFrom(*this, kParseFully));
nonce.InitFrom(aExtAddress, info.mFrameCounter, info.mSecurityLevel);
aesCcm.SetKey(aMacKey);
aesCcm.SetNonce(nonce);
aesCcm.SetAuthData(info.mHeader.GetBytes(), info.mHeader.GetLength());
aesCcm.SetTagLength(info.mMicSize);
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
// Do not decrypt when fuzzing
ExitNow(error = kErrorNone);
#endif
error = aesCcm.Process(Crypto::AesCcm::kDecrypt, AsNonConst(info.mPayload.GetBytes()), info.mPayload.GetLength());
exit:
return error;
return PerformAesCcm(kDecrypt, aExtAddress, aMacKey);
}
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
#endif
// LCOV_EXCL_START
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
Frame::InfoString Frame::ToInfoString(void) const
Frame::InfoString Frame::ParseInfo::ToInfoString(void) const
{
InfoString string;
ParseInfo info;
string.Append("len:%u", mLength);
if (mFrame == nullptr)
{
string.Append("no-frame");
ExitNow();
}
if (info.ParseFrom(*this, kParseFully) != kErrorNone)
string.Append("len:%u", mFrame->mLength);
if (!mParsedFully)
{
string.Append(", invalid-format");
ExitNow();
}
if (info.mIsSeqNumPresent)
if (mIsSeqNumPresent)
{
string.Append(", seqnum:%u", info.mSequenceNum);
string.Append(", seqnum:%u", mSequenceNum);
}
string.Append(", type:");
switch (info.mType)
switch (mType)
{
case kTypeBeacon:
string.Append("Beacon");
@@ -1279,7 +1099,7 @@ Frame::InfoString Frame::ToInfoString(void) const
break;
case kTypeMacCmd:
switch (info.mCommandId)
switch (mCommandId)
{
case kMacCmdDataRequest:
string.Append("Cmd(DataReq)");
@@ -1290,29 +1110,31 @@ Frame::InfoString Frame::ToInfoString(void) const
break;
default:
string.Append("Cmd(%u)", info.mCommandId);
string.Append("Cmd(%u)", mCommandId);
break;
}
break;
default:
string.Append("%u", info.mType);
string.Append("%u", mType);
break;
}
string.Append(", src:%s, dst:%s, sec:%s, ackreq:%s", info.mAddrs.mSource.ToString().AsCString(),
info.mAddrs.mDestination.ToString().AsCString(), ToYesNo(info.mIsSecurityEnabled),
ToYesNo(info.mIsAckRequest));
string.Append(", src:%s, dst:%s, sec:%s, ackreq:%s", mAddrs.mSource.ToString().AsCString(),
mAddrs.mDestination.ToString().AsCString(), ToYesNo(mIsSecurityEnabled), ToYesNo(mIsAckRequest));
if (info.mIsSecurityEnabled)
if (mIsSecurityEnabled)
{
string.Append(", fc:%lu", ToUlong(info.mFrameCounter));
string.Append(", fc:%lu", ToUlong(mFrameCounter));
}
exit:
#if OPENTHREAD_CONFIG_MULTI_RADIO
string.Append(", radio:%s", Radio::TypeToString(GetRadioType()));
if (mFrame != nullptr)
{
string.Append(", radio:%s", Radio::TypeToString(mFrame->GetRadioType()));
}
#endif
return string;
+274 -416
View File
@@ -63,6 +63,9 @@ namespace Mac {
*/
class Frame : public Radio::Frame
{
protected:
enum AddrMode : uint8_t;
public:
/**
* Represents the MAC frame type.
@@ -138,6 +141,19 @@ public:
kMacCmdGtsRequest = 9,
};
/**
* Specifies the parsing mode for `ParseInfo::ParseFrom()`.
*
* In `kParseSecurityHeader` mode, the frame is explicitly required to have security enabled in FCF; otherwise
* `kErrorNotFound` is returned.
*/
enum ParseMode : uint8_t
{
kParseAddrFields, ///< Parse up through address fields (FCF, SecNum, PAN IDs, Addrs) and FCS.
kParseSecurityHeader, ///< Parse up through Auxiliary Security Header (requires security enabled).
kParseFully, ///< Parse all headers fully.
};
static constexpr uint8_t kKeySourceSizeMode0 = 0; ///< Key Source size in bytes for Key ID Mode 0.
static constexpr uint8_t kKeySourceSizeMode1 = 0; ///< Key Source size in bytes for Key ID Mode 1.
static constexpr uint8_t kKeySourceSizeMode2 = 4; ///< Key Source size in bytes for Key ID Mode 2.
@@ -162,65 +178,156 @@ public:
};
/**
* Validates the frame.
*
* @retval kErrorNone Successfully parsed the MAC header.
* @retval kErrorParse Failed to parse through the MAC header.
* Represents parsed information from a MAC frame header.
*/
Error ValidatePsdu(void) const;
class ParseInfo : public Clearable<ParseInfo>
{
friend class Frame; // TODO: At some point we should no longer need this, remove it.
/**
* Returns the IEEE 802.15.4 Frame Type.
*
* @returns The IEEE 802.15.4 Frame Type.
*/
uint8_t GetType(void) const { return ReadType(GetFrameControlField()); }
public:
/**
* Initializes the `ParseInfo` object.
*/
ParseInfo(void) { Clear(); }
/**
* Returns whether the frame is an Ack frame.
*
* @retval TRUE If this is an Ack.
* @retval FALSE If this is not an Ack.
*/
bool IsAck(void) const { return GetType() == kTypeAck; }
/**
* Parses the MAC frame header according to the specified parsing mode.
*
* @param[in] aFrame The frame to parse from.
* @param[in] aMode The parsing mode.
*
* @retval kErrorNone Successfully parsed the frame according to @p aMode.
* @retval kErrorNotFound Security is not enabled when @p aMode is `kParseSecurityHeader`.
* @retval kErrorParse Failed to parse the frame (frame is malformed).
*/
Error ParseFrom(const Frame &aFrame, ParseMode aMode);
/**
* Returns whether the frame is a MAC Command frame.
*
* @retval TRUE If this is a MAC Command frame.
* @retval FALSE If this is not a MAC Command Frame.
*/
bool IsMacCommand(void) const { return GetType() == kTypeMacCmd; }
/**
* Returns human-readable string corresponding to the frame information.
*
* @returns An `InfoString` containing info about the frame.
*/
InfoString ToInfoString(void) const;
/**
* Returns the IEEE 802.15.4 Frame Version.
*
* @returns The IEEE 802.15.4 Frame Version.
*/
uint8_t GetVersion(void) const { return ReadVersion(GetFrameControlField()); }
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
/**
* Returns if this IEEE 802.15.4 frame's version is 2015.
*
* @returns TRUE if version is 2015, FALSE otherwise.
*/
bool IsVersion2015(void) const { return IsVersion2015(GetFrameControlField()); }
/**
* Finds a specific Information Element (IE) in the frame.
*
* This method searches the frame for a Header IE matching the Element ID of @p IeType and also validates that
* the content of the IE is well-formed according to @p IeType.
*
* @tparam IeType The IE subclass type to find.
*
* @returns A pointer to the IE, or `nullptr` if not found or if the IE content is malformed.
*/
template <typename IeType> const IeType *Find(void) const
{
return static_cast<const IeType *>(FindHeaderIe(HeaderIe::ValidateAs<IeType>));
}
/**
* Indicates whether or not security is enabled.
*
* @retval TRUE If security is enabled.
* @retval FALSE If security is not enabled.
*/
bool GetSecurityEnabled(void) const { return IsSecurityEnabled(GetFrameControlField()); }
/**
* Finds a specific Information Element (IE) in the frame.
*
* This method searches the frame for a Header IE matching the Element ID of @p IeType and also validates that
* the content of the IE is well-formed according to @p IeType.
*
* @tparam IeType The IE subclass type to find.
*
* @returns A pointer to the IE, or `nullptr` if not found or if the IE content is malformed.
*/
template <typename IeType> IeType *Find(void) { return AsNonConst(AsConst(this)->Find<IeType>()); }
/**
* Indicates whether or not the Frame Pending bit is set.
*
* @retval TRUE If the Frame Pending bit is set.
* @retval FALSE If the Frame Pending bit is not set.
*/
bool GetFramePending(void) const { return IsFramePending(GetFrameControlField()); }
/**
* Indicates whether or not the frame contains a specific Information Element (IE).
*
* This method checks whether the frame contains a Header IE matching the Element ID of @p IeType with valid
* content according to @p IeType.
*
* @tparam IeType The IE subclass type to check.
*
* @retval TRUE The frame contains a valid instance of the IE.
* @retval FALSE The frame does not contain the IE or its content is malformed.
*/
template <typename IeType> bool Has(void) const { return Find<IeType>() != nullptr; }
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - -
const Frame *mFrame; ///< The parsed frame.
bool mParsedAddrFields : 1; ///< TRUE if address fields are successfully parsed.
bool mParsedSecurityHeader : 1; ///< TRUE if Auxiliary Security Header is present and successfully parsed.
bool mParsedFully : 1; ///< TRUE if the frame is fully parsed.
// - - - - - - - - - - - - - - - - - - - - - - - - -
// Mac Header Address Info
bool mIsSecurityEnabled : 1; ///< TRUE if security is enabled, FALSE otherwise.
bool mIsFramePending : 1; ///< TRUE if frame pending bit is set, FALSE otherwise.
bool mIsAckRequest : 1; ///< TRUE if ACK request bit is set, FALSE otherwise.
bool mIsSeqNumPresent : 1; ///< TRUE if sequence number is present, FALSE otherwise.
bool mIsIePresent : 1; ///< TRUE if IE present bit is set, FALSE otherwise.
Type mType; ///< The frame type.
Version mVersion; ///< The frame version.
uint8_t mSequenceNum; ///< The sequence number (valid if `mIsSeqNumPresent`).
PanIds mPanIds; ///< Source and Destination PAN IDs.
Addresses mAddrs; ///< Source and Destination addresses.
// - - - - - - - - - - - - - - - - - - - - - - - - -
// Aux Security Header (valid if `mIsSecurityEnabled`)
SecurityLevel mSecurityLevel; ///< The security level.
KeyIdMode mKeyIdMode; ///< The Key ID mode.
uint8_t mKeyIndex; ///< The Key Index.
uint8_t mMicSize; ///< The MIC size in bytes.
uint32_t mFrameCounter; ///< The security frame counter.
FrameData mKeySource; ///< The Key Source data.
// - - - - - - - - - - - - - - - - - - - - - - - - -
FrameData mIeData; ///< The Header IE data.
// - - - - - - - - - - - - - - - - - - - - - - - - -
uint8_t mCommandId; ///< The MAC Command ID (valid if `mType == kTypeMacCmd`).
// - - - - - - - - - - - - - - - - - - - - - - - - -
FrameData mHeader; ///< The frame header (MHR) sub-range (see `mPayload` for treatment of Command ID).
/**
* The frame payload (MAC payload) sub-range.
*
* For MAC Command frames (`kTypeMacCmd`), the treatment of the Command ID field depends on the frame version:
* - For 2015 version, the Command ID is part of the payload and included in `mPayload`.
* - For earlier versions (2003/2006), the Command ID is part of the MAC header, so `mPayload` starts after
* the Command ID. In this case the Command ID is part of `mHeader`.
*/
FrameData mPayload;
protected:
enum AesCcmOperation : uint8_t
{
kEncrypt,
kDecrypt,
};
Error PerformAesCcm(AesCcmOperation aOperation, const ExtAddress &aExtAddress, const KeyMaterial &aMacKey);
uint8_t *mKeyIndexByte;
uint8_t *mFrameCounterBytes;
private:
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
typedef bool (&HeaderIeMatcher)(const HeaderIe &aHeaderIe);
const HeaderIe *FindHeaderIe(HeaderIeMatcher aMatcher) const;
#endif
static Error ParseAddress(FrameData &aFrameData, AddrMode aAddrMode, Address &aAddress);
};
/**
* Sets the Frame Pending bit.
@@ -229,14 +336,6 @@ public:
*/
void SetFramePending(bool aFramePending) { UpdateFcfFlag(aFramePending, kFcfFramePending); }
/**
* Indicates whether or not the Ack Request bit is set.
*
* @retval TRUE If the Ack Request bit is set.
* @retval FALSE If the Ack Request bit is not set.
*/
bool GetAckRequest(void) const { return IsAckRequest(GetFrameControlField()); }
/**
* Sets the Ack Request bit.
*
@@ -244,14 +343,6 @@ public:
*/
void SetAckRequest(bool aAckRequest) { UpdateFcfFlag(aAckRequest, kFcfAckRequest); }
/**
* Indicates whether or not IEs present.
*
* @retval TRUE If IEs present.
* @retval FALSE If no IE present.
*/
bool IsIePresent(void) const { return IsIePresent(GetFrameControlField()); }
/**
* Sets the IE Present bit.
*
@@ -259,194 +350,6 @@ public:
*/
void SetIePresent(bool aIePresent) { UpdateFcfFlag(aIePresent, kFcfIePresent); }
/**
* Returns the Sequence Number value.
*
* @returns The Sequence Number value.
*/
uint8_t GetSequence(void) const;
/**
* Sets the Sequence Number value.
*
* @param[in] aSequence The Sequence Number value.
*/
void SetSequence(uint8_t aSequence);
/**
* Indicates whether or not the Sequence Number is present.
*
* @returns TRUE if the Sequence Number is present, FALSE otherwise.
*/
bool IsSequencePresent(void) const { return IsSeqPresent(GetFrameControlField()); }
/**
* Gets the Destination PAN Identifier.
*
* @param[out] aPanId The Destination PAN Identifier.
*
* @retval kErrorNone Successfully retrieved the Destination PAN Identifier.
* @retval kErrorNotFound Destination PAN Identifier is not present in the frame.
* @retval kErrorParse Failed to parse the frame.
*/
Error GetDstPanId(PanId &aPanId) const;
/**
* Gets the Destination Address.
*
* @param[out] aAddress The Destination Address.
*
* @retval kErrorNone Successfully retrieved the Destination Address.
* @retval kErrorParse Failed to parse the frame.
*/
Error GetDstAddr(Address &aAddress) const;
/**
* Gets the Source PAN Identifier.
*
* @param[out] aPanId The Source PAN Identifier.
*
* @retval kErrorNone Successfully retrieved the Source PAN Identifier.
* @retval kErrorNotFound Source PAN Identifier is not present in the frame.
* @retval kErrorParse Failed to parse the frame.
*/
Error GetSrcPanId(PanId &aPanId) const;
/**
* Gets the Source Address.
*
* @param[out] aAddress The Source Address.
*
* @retval kErrorNone Successfully retrieved the Source Address.
* @retval kErrorParse Failed to parse the frame.
*/
Error GetSrcAddr(Address &aAddress) const;
/**
* Gets the Security Level Identifier.
*
* @param[out] aSecurityLevel The Security Level Identifier.
*
* @retval kErrorNone Successfully retrieved the Security Level Identifier.
* @retval kErrorNotFound Frame does not have a security header (security is not enabled)
* @retval kErrorParse Failed to parse MAC or security header.
*/
Error GetSecurityLevel(SecurityLevel &aSecurityLevel) const;
/**
* Indicates whether or not the frame has a specific Security Level.
*
* @param[in] aSecurityLevel The Security Level to check.
*
* @retval TRUE The frame contains a valid security header matching @p aSecurityLevel.
* @retval FALSE The frame does not match @p aSecurityLevel or fails to parse MAC or security header.
*/
bool HasSecurityLevel(SecurityLevel aSecurityLevel) const;
/**
* Gets the Key Identifier Mode.
*
* @param[out] aKeyIdMode The Key Identifier Mode.
*
* @retval kErrorNone Successfully retrieved the Key Identifier Mode.
* @retval kErrorParse Failed to parse MAC or security header.
*/
Error GetKeyIdMode(KeyIdMode &aKeyIdMode) const;
/**
* Indicates whether or not the frame has a specific Key Identifier Mode.
*
* @param[in] aKeyIdMode The Key Identifier Mode to check.
*
* @retval TRUE The frame contains a valid security header matching @p aKeyIdMode.
* @retval FALSE The frame does not match @p aKeyIdMode or fails to parse MAC or security header.
*/
bool HasKeyIdMode(KeyIdMode aKeyIdMode) const;
/**
* Gets the Frame Counter.
*
* @param[out] aFrameCounter The Frame Counter.
*
* @retval kErrorNone Successfully retrieved the Frame Counter.
* @retval kErrorParse Failed to parse MAC or security header.
*/
Error GetFrameCounter(uint32_t &aFrameCounter) const;
/**
* Sets the Frame Counter.
*
* @param[in] aFrameCounter The Frame Counter.
*/
void SetFrameCounter(uint32_t aFrameCounter);
/**
* Returns a pointer to the Key Source.
*
* @param[out] aKeySource A `FrameData` to point to key source data bytes.
*/
void GetKeySource(FrameData &aKeySource) const;
/**
* Sets the Key Source.
*
* @param[in] aKeySource A pointer to the Key Source value.
*/
void SetKeySource(const uint8_t *aKeySource);
/**
* Gets the Key Index (sub-field of Key ID).
*
* @param[out] aKeyIndex The Key Index
*
* @retval kErrorNone Successfully retrieved the Key Index.
* @retval kErrorNotFound Frame is using `kKeyIdMode0` which does not have any Key Index.
* @retval kErrorParse Failed to parse MAC or security header.
*/
Error GetKeyIndex(uint8_t &aKeyIndex) const;
/**
* Sets the Key Index (sub-field of Key ID).
*
* @param[in] aKeyIndex The Key Index.
*/
void SetKeyIndex(uint8_t aKeyIndex);
/**
* Gets the Command ID.
*
* @param[out] aCommandId The Command ID.
*
* @retval kErrorNone Successfully retrieved the Command ID.
* @retval kErrorNotFound The frame is not a MAC command.
* @retval kErrorParse Failed to parse frame.
*/
Error GetCommandId(uint8_t &aCommandId) const;
/**
* Indicates whether the frame is a MAC Data Request command (data poll).
*
* For 802.15.4-2015 and above frame, the frame should be already decrypted.
*
* @returns TRUE if frame is a MAC Data Request command, FALSE otherwise.
*/
bool IsDataRequestCommand(void) const;
/**
* Gets the frame payload as `FrameData`.
*
* For MAC Command frames (`kTypeMacCmd`), the treatment of the Command ID field depends on the frame version:
* - For 2015 version , the Command ID is part of the payload, so @p aPayloadData includes it.
* - For earlier versions (2003/2006), the Command ID is part of the MAC header, so @p aPayloadData starts after
* the Command ID.
*
* @param[out] aPayloadData A reference to a `FrameData` to return the frame payload.
*
* @retval kErrorNone Successfully retrieved the frame payload.
* @retval kErrorParse Failed to parse the frame.
*/
Error GetPayload(FrameData &aPayloadData) const;
/**
* Determines the length breakdown of the frame.
*
@@ -458,45 +361,6 @@ public:
Error DetermineLengths(Lengths &aLengths) const;
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
/**
* Finds a specific Information Element (IE) in the frame.
*
* This method searches the frame for a Header IE matching the Element ID of @p IeType and also validates that
* the content of the IE is well-formed according to @p IeType.
*
* @tparam IeType The IE subclass type to find.
*
* @returns A pointer to the IE, or `nullptr` if not found or if the IE content is malformed.
*/
template <typename IeType> const IeType *Find(void) const
{
return static_cast<const IeType *>(FindHeaderIe(HeaderIe::ValidateAs<IeType>));
}
/**
* Finds a specific Information Element (IE) in the frame.
*
* This method searches the frame for a Header IE matching the Element ID of @p IeType and also validates that
* the content of the IE is well-formed according to @p IeType.
*
* @tparam IeType The IE subclass type to find.
*
* @returns A pointer to the IE, or `nullptr` if not found or if the IE content is malformed.
*/
template <typename IeType> IeType *Find(void) { return AsNonConst(AsConst(this)->Find<IeType>()); }
/**
* Indicates whether or not the frame contains a specific Information Element (IE).
*
* This method checks whether the frame contains a Header IE matching the Element ID of @p IeType with valid
* content according to @p IeType.
*
* @tparam IeType The IE subclass type to check.
*
* @retval TRUE The frame contains a valid instance of the IE.
* @retval FALSE The frame does not contain the IE or its content is malformed.
*/
template <typename IeType> bool Has(void) const { return Find<IeType>() != nullptr; }
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
/**
@@ -520,20 +384,6 @@ public:
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
/**
* Returns information about the frame object as an `InfoString` object.
*
* @returns An `InfoString` containing info about the frame.
*/
InfoString ToInfoString(void) const;
/**
* Returns the Frame Control field of the frame.
*
* @returns The Frame Control field.
*/
uint16_t GetFrameControlField(void) const { return LittleEndian::ReadUint16(mPsdu); }
/**
* Returns the Immediate Acknowledgment (Imm-Ack) frame length in bytes.
*
@@ -558,6 +408,7 @@ public:
protected:
static constexpr uint8_t kFcfSize = sizeof(uint16_t);
static constexpr uint8_t kDsnSize = sizeof(uint8_t);
static constexpr uint8_t kSeqNumIndex = kFcfSize;
static constexpr uint8_t kImmAckLength = kFcfSize + kDsnSize + k154FcsSize;
static constexpr uint8_t kSecurityControlSize = sizeof(uint8_t);
@@ -612,60 +463,8 @@ protected:
static constexpr uint8_t kInvalidSize = kInvalidIndex;
static constexpr uint8_t kMaxPsduSize = kInvalidSize - 1;
enum ParseMode : uint8_t
{
kParseAddrFields,
kParseSecurityHeader,
kParseFully,
};
class ParseInfo
{
public:
// - - - - - - - - - - - - - - - - - - - - - - - - -
// Mac Header Address Info
Type mType;
Version mVersion;
bool mIsSecurityEnabled : 1;
bool mIsFramePending : 1;
bool mIsAckRequest : 1;
bool mIsSeqNumPresent : 1;
bool mIsIePresent : 1;
uint8_t mSequenceNum;
PanIds mPanIds;
Addresses mAddrs;
// - - - - - - - - - - - - - - - - - - - - - - - - -
// Aux Security Header
SecurityLevel mSecurityLevel;
KeyIdMode mKeyIdMode;
uint8_t mKeyIndex;
uint8_t mMicSize;
uint32_t mFrameCounter;
FrameData mKeySource;
uint8_t *mFrameCounterBytes;
uint8_t *mKeyIndexByte;
// - - - - - - - - - - - - - - - - - - - - - - - - -
// Header IEs
FrameData mIeData;
// - - - - - - - - - - - - - - - - - - - - - - - - -
// MAC Command ID
uint8_t mCommandId;
// - - - - - - - - - - - - - - - - - - - - - - - - -
// Header and Payload breakdown
FrameData mHeader;
FrameData mPayload;
Error ParseFrom(const Frame &aFrame, ParseMode aMode);
private:
static Error ParseAddress(FrameData &aFrameData, AddrMode aAddrMode, Address &aAddress);
};
void UpdateFcfFlag(bool aSet, uint16_t aBitFlag);
uint16_t GetFrameControlField(void) const { return LittleEndian::ReadUint16(mPsdu); }
void UpdateFcfFlag(bool aSet, uint16_t aBitFlag);
static uint8_t ReadType(uint16_t aFcf) { return As<uint8_t>(ReadBits<uint16_t, kFcfFrameTypeMask>(aFcf)); }
static AddrMode ReadDstAddrMode(uint16_t aFcf) { return As<AddrMode>(ReadBits<uint16_t, kFcfDstAddrMask>(aFcf)); }
@@ -693,13 +492,6 @@ protected:
private:
template <typename EnumType> static EnumType As(uint16_t aValue) { return static_cast<EnumType>(aValue); }
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
typedef bool (&HeaderIeMatcher)(const HeaderIe &aHeaderIe);
const HeaderIe *FindHeaderIe(HeaderIeMatcher aMatcher) const;
HeaderIe *FindHeaderIe(HeaderIeMatcher aMatcher) { return AsNonConst(AsConst(this)->FindHeaderIe(aMatcher)); }
#endif
};
/**
@@ -707,46 +499,43 @@ private:
*/
class RxFrame : public Frame, public Radio::RxFrameProperties<RxFrame>
{
public:
friend class TxFrame;
public:
/**
* Defines flags to indicate allowed Key ID Modes, used in `IsSecuredWith()`.
* Represents parsed information from a received MAC frame.
*/
enum KeyIdModeFlag : uint8_t
class ParseInfo : public Frame::ParseInfo
{
kAllowKeyIdMode0 = (1 << 0), ///< Allow Key ID Mode 0.
kAllowKeyIdMode1 = (1 << 1), ///< Allow Key ID Mode 1.
};
public:
/**
* Returns a pointer to the associated `RxFrame`.
*
* @returns A pointer to the `RxFrame`.
*/
const RxFrame *GetRxFrame(void) const { return static_cast<const RxFrame *>(mFrame); }
/**
* Represents a set of `KeyIdModeFlag`s.
*/
typedef uint8_t KeyIdModeFlags;
/**
* Indicates whether the frame is secured with a given set of allowed Key ID Modes.
*
* @param[in] aFlags A bitmask of `KeyIdModeFlags` specifying the allowed modes.
*
* @retval TRUE The frame has security enabled and uses one of the allowed Key ID Modes.
* @retval FALSE The frame does not have security enabled, or its Key ID Mode is not allowed.
*/
bool IsSecuredWith(KeyIdModeFlags aFlags) const;
/**
* Returns a pointer to the associated `RxFrame`.
*
* @returns A pointer to the `RxFrame`.
*/
RxFrame *GetRxFrame(void) { return AsNonConst(AsConst(this)->GetRxFrame()); }
#if OPENTHREAD_FTD || OPENTHREAD_MTD
/**
* Performs AES CCM on the frame which is received.
*
* @param[in] aExtAddress A reference to the extended address, which will be used to generate nonce
* for AES CCM computation.
* @param[in] aMacKey A reference to the MAC key to decrypt the received frame.
*
* @retval kErrorNone Process of received frame AES CCM succeeded.
* @retval kErrorSecurity Received frame MIC check failed.
*/
Error ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey);
/**
* Performs AES CCM on the frame which is received.
*
* @param[in] aExtAddress A reference to the extended address, which will be used to generate nonce
* for AES CCM computation.
* @param[in] aMacKey A reference to the MAC key to decrypt the received frame.
*
* @retval kErrorNone Process of received frame AES CCM succeeded.
* @retval kErrorSecurity Received frame MIC check failed.
*/
Error ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey);
#endif
};
};
/**
@@ -755,6 +544,91 @@ public:
class TxFrame : public Frame, public Radio::TxFrameProperties<TxFrame>
{
public:
/**
* Represents parsed information from a transmitted MAC frame.
*/
class ParseInfo : public Frame::ParseInfo
{
public:
/**
* Returns a pointer to the associated `TxFrame`.
*
* @returns A pointer to the `TxFrame`.
*/
const TxFrame *GetTxFrame(void) const { return static_cast<const TxFrame *>(mFrame); }
/**
* Returns a pointer to the associated `TxFrame`.
*
* @returns A pointer to the `TxFrame`.
*/
TxFrame *GetTxFrame(void) { return AsNonConst(AsConst(this)->GetTxFrame()); }
/**
* Writes the Sequence Number value in the frame.
*
* The Address fields MUST be parsed successfully before calling this method. If the Sequence Number is not
* present in the frame, this method performs no action.
*
* @param[in] aSequenceNum The Sequence Number value.
*/
void WriteSequenceNum(uint8_t aSequenceNum);
/**
* Writes the Key Index (sub-field of Key ID) in the frame.
*
* If the Auxiliary Security Header is not parsed or not present, or if the Key ID Mode is `kKeyIdMode0`, this
* method performs no action.
*
* @param[in] aKeyIndex The Key Index.
*/
void WriteKeyIndex(uint8_t aKeyIndex);
/**
* Writes the security Frame Counter in the frame.
*
* If the Auxiliary Security Header is not parsed or not present, this method performs no action. Otherwise,
* it writes the Frame Counter and marks the frame header as updated (`SetIsHeaderUpdated(true)`).
*
* @param[in] aFrameCounter The Frame Counter.
*/
void WriteFrameCounter(uint32_t aFrameCounter);
/**
* Writes the Key Source in the frame.
*
* If the Auxiliary Security Header is not parsed or not present, or if the Key ID Mode does not require a Key
* Source, this method performs no action.
*
* @param[in] aKeySource A pointer to the Key Source value.
*/
void WriteKeySource(const uint8_t *aKeySource);
/**
* Performs AES-CCM encryption on the frame to be transmitted.
*
* The frame MUST be fully parsed before calling this method. If security is enabled on the frame,
* this method encrypts the payload, appends the MIC tag, and marks security as processed
* (`SetIsSecurityProcessed(true)`). If security is not enabled, this method performs no action.
*
* @param[in] aExtAddress A reference to the extended address used to generate the AES-CCM nonce.
*/
void ProcessTransmitAesCcm(const ExtAddress &aExtAddress);
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
/**
* Restores transmit security by decrypting the frame for retransmission.
*
* The frame MUST be fully parsed before calling this method. If security is enabled and was previously
* processed, this method decrypts the frame in-place using AES-CCM and resets both the security-processed
* and header-updated flags (`SetIsSecurityProcessed(false)` and `SetIsHeaderUpdated(false)`).
*
* @param[in] aExtAddress A reference to the extended address used to generate the AES-CCM nonce.
*/
void RestoreTransmitSecurity(const ExtAddress &aExtAddress);
#endif
};
/**
* Represents the information to use to build the frame.
*/
@@ -882,22 +756,6 @@ public:
*/
void CopyFrom(const TxFrame &aFromFrame);
/**
* Performs AES CCM on the frame which is going to be sent.
*
* @param[in] aExtAddress A reference to the extended address, which will be used to generate nonce
* for AES CCM computation.
*/
void ProcessTransmitAesCcm(const ExtAddress &aExtAddress);
/**
* Restore the frame for transmit processing.
*
* @param[in] aExtAddress A reference to the extended address, which will be used to generate nonce
* for AES CCM computation.
*/
void RestoreTransmitSecurity(const ExtAddress &aExtAddress);
/**
* Generate Imm-Ack in this frame object.
*
+4 -14
View File
@@ -169,27 +169,17 @@ void Links::Send(TxFrame &aFrame, Radio::Types aRadioTypes)
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
void Links::SetMacFrameCounter(TxFrame &aFrame)
void Links::SetMacFrameCounter(TxFrame::ParseInfo &aFrameInfo)
{
#if OPENTHREAD_CONFIG_MULTI_RADIO
Radio::Type radioType = aFrame.GetRadioType();
#endif
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#if OPENTHREAD_CONFIG_MULTI_RADIO
if (radioType == Radio::kTypeTrel)
if (aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeTrel)
#endif
{
aFrame.SetFrameCounter(Get<KeyManager>().GetTrelMacFrameCounter());
aFrameInfo.WriteFrameCounter(Get<KeyManager>().GetTrelMacFrameCounter());
Get<KeyManager>().IncrementTrelMacFrameCounter();
ExitNow();
}
#endif
exit:
return;
}
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#endif
} // namespace Mac
} // namespace ot
+3 -21
View File
@@ -204,21 +204,6 @@ public:
#endif
}
/**
* Sets the Sequence Number value on all supported radio tx frames.
*
* @param[in] aSequence The Sequence Number value.
*/
void SetSequence(uint8_t aSequence)
{
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
mTxFrame802154.SetSequence(aSequence);
#endif
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
mTxFrameTrel.SetSequence(aSequence);
#endif
}
/**
* Sets the maximum number of the CSMA-CA backoffs on all supported radio tx
* frames.
@@ -649,14 +634,11 @@ public:
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
/**
* Sets the current MAC frame counter value from the value from a `TxFrame`.
* Sets the MAC frame counter in a TX frame for TREL link.
*
* @param[in] TxFrame The `TxFrame` from which to get the counter value.
*
* @retval kErrorNone If successful.
* @retval kErrorInvalidState If the raw link-layer isn't enabled.
* @param[in,out] aFrameInfo The TX frame information to update.
*/
void SetMacFrameCounter(TxFrame &aFrame);
void SetMacFrameCounter(TxFrame::ParseInfo &aFrameInfo);
#endif
private:
+11 -17
View File
@@ -38,29 +38,23 @@
namespace ot {
Error ScanResult::PopulateFromBeacon(const Mac::RxFrame *aBeaconFrame)
Error ScanResult::PopulateFromBeacon(const Mac::RxFrame::ParseInfo &aFrameInfo)
{
Error error = kErrorNone;
Mac::Address address;
Error error = kErrorNone;
Clear();
VerifyOrExit(aBeaconFrame != nullptr, error = kErrorInvalidArgs);
VerifyOrExit(aFrameInfo.mType == Mac::Frame::kTypeBeacon, error = kErrorParse);
VerifyOrExit(aBeaconFrame->GetType() == Mac::Frame::kTypeBeacon, error = kErrorParse);
VerifyOrExit(aFrameInfo.mAddrs.mSource.IsExtended(), error = kErrorParse);
mExtAddress = aFrameInfo.mAddrs.mSource.GetExtended();
SuccessOrExit(error = aBeaconFrame->GetSrcAddr(address));
VerifyOrExit(address.IsExtended(), error = kErrorParse);
mExtAddress = address.GetExtended();
mPanId =
aFrameInfo.mPanIds.IsSourcePresent() ? aFrameInfo.mPanIds.GetSource() : aFrameInfo.mPanIds.GetDestination();
if (aBeaconFrame->GetSrcPanId(mPanId) != kErrorNone)
{
IgnoreError(aBeaconFrame->GetDstPanId(mPanId));
}
mChannel = aBeaconFrame->GetChannel();
mRssi = aBeaconFrame->GetRssi();
mLqi = aBeaconFrame->GetLqi();
mChannel = aFrameInfo.GetRxFrame()->GetChannel();
mRssi = aFrameInfo.GetRxFrame()->GetRssi();
mLqi = aFrameInfo.GetRxFrame()->GetLqi();
#if OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE
{
@@ -68,7 +62,7 @@ Error ScanResult::PopulateFromBeacon(const Mac::RxFrame *aBeaconFrame)
const Mac::BeaconHeader *beaconHeader;
const Mac::BeaconPayload *beaconPayload;
SuccessOrExit(aBeaconFrame->GetPayload(frameData));
frameData = aFrameInfo.mPayload;
beaconHeader = frameData.Read<Mac::BeaconHeader>();
VerifyOrExit((beaconHeader != nullptr) && beaconHeader->IsValid());
+1 -1
View File
@@ -169,7 +169,7 @@ public:
private:
typedef Callback<Handler> ScanCallback;
Error PopulateFromBeacon(const Mac::RxFrame *aBeaconFrame);
Error PopulateFromBeacon(const Mac::RxFrame::ParseInfo &aFrameInfo);
};
/**
+78 -61
View File
@@ -314,7 +314,8 @@ void SubMac::HandleReceiveDone(RxFrame *aFrame, Error aError)
Error SubMac::Send(void)
{
Error error = kErrorNone;
Error error = kErrorNone;
TxFrame::ParseInfo frameInfo;
switch (mState)
{
@@ -340,15 +341,23 @@ Error SubMac::Send(void)
mTimer.Stop();
// We ignore the parsing error here because `Send()` must allow
// transmission of raw frames (when `LinkRaw` is enabled) which may
// not follow the standard IEEE 802.15.4 frame format.
// `ProcessTransmitSecurity()` validates `mParsedFully` before
// performing any security operations on the frame.
IgnoreError(frameInfo.ParseFrom(mTransmitFrame, Frame::kParseFully));
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
if (mRadioFilterEnabled)
{
mCallbacks.TransmitDone(mTransmitFrame, nullptr, mTransmitFrame.GetAckRequest() ? kErrorNoAck : kErrorNone);
mCallbacks.TransmitDone(frameInfo, nullptr, frameInfo.mIsAckRequest ? kErrorNoAck : kErrorNone);
ExitNow();
}
#endif
ProcessTransmitSecurity();
ProcessTransmitSecurity(frameInfo);
mCsmaBackoffs = 0;
mTransmitRetries = 0;
@@ -363,46 +372,38 @@ exit:
return error;
}
void SubMac::ProcessTransmitSecurity(void)
void SubMac::ProcessTransmitSecurity(TxFrame::ParseInfo &aFrameInfo)
{
const ExtAddress *extAddress = nullptr;
uint8_t keyIndex;
VerifyOrExit(aFrameInfo.mParsedFully);
VerifyOrExit(aFrameInfo.mIsSecurityEnabled);
VerifyOrExit(mTransmitFrame.GetSecurityEnabled());
VerifyOrExit(!mTransmitFrame.IsSecurityProcessed());
VerifyOrExit(!aFrameInfo.GetTxFrame()->IsSecurityProcessed());
if (!mTransmitFrame.IsHeaderUpdated())
if (!aFrameInfo.GetTxFrame()->IsHeaderUpdated())
{
keyIndex = mKeyTrio.GetKeyIndex();
mTransmitFrame.SetKeyIndex(keyIndex);
}
else
{
SuccessOrExit(mTransmitFrame.GetKeyIndex(keyIndex));
aFrameInfo.WriteKeyIndex(mKeyTrio.GetKeyIndex());
}
VerifyOrExit(ShouldHandle(kCapTransmitSec));
VerifyOrExit(mTransmitFrame.HasKeyIdMode(Frame::kKeyIdMode1));
VerifyOrExit(aFrameInfo.mKeyIdMode == Frame::kKeyIdMode1);
mTransmitFrame.SetAesKey(mKeyTrio.SelectKey(keyIndex));
aFrameInfo.GetTxFrame()->SetAesKey(mKeyTrio.SelectKey(aFrameInfo.mKeyIndex));
if (!mTransmitFrame.IsHeaderUpdated())
if (!aFrameInfo.GetTxFrame()->IsHeaderUpdated())
{
uint32_t frameCounter = GetFrameCounter();
mTransmitFrame.SetFrameCounter(frameCounter);
SignalFrameCounterUsed(frameCounter, keyIndex);
aFrameInfo.WriteFrameCounter(frameCounter);
SignalFrameCounterUsed(frameCounter, aFrameInfo.mKeyIndex);
}
extAddress = &GetExtAddress();
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
// Transmit security will be processed after time IE content is updated.
VerifyOrExit(!mTransmitFrame.Has<TimeIe>());
VerifyOrExit(!aFrameInfo.Has<TimeIe>());
#endif
mTransmitFrame.ProcessTransmitAesCcm(*extAddress);
aFrameInfo.ProcessTransmitAesCcm(GetExtAddress());
exit:
return;
@@ -513,21 +514,41 @@ exit:
void SubMac::HandleTransmitStarted(TxFrame &aFrame)
{
TxFrame::ParseInfo frameInfo;
if (mPcapCallback.IsSet())
{
mPcapCallback.Invoke(&aFrame, true);
}
if (ShouldHandle(kCapAckTimeout) && aFrame.GetAckRequest())
VerifyOrExit(ShouldHandle(kCapAckTimeout));
SuccessOrExit(frameInfo.ParseFrom(aFrame, Frame::kParseAddrFields));
if (frameInfo.mIsAckRequest)
{
StartTimer(kAckTimeout);
}
exit:
return;
}
void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
{
bool ccaSuccess = true;
bool shouldRetx;
bool ccaSuccess = true;
bool shouldRetx;
TxFrame::ParseInfo frameInfo;
// We ignore the parsing error here because `HandleTransmitDone()`
// must proceed with transmit-done handling (stopping timers,
// recording CCA status, handling retries) even if the frame is not
// a valid IEEE 802.15.4 frame (e.g., when `LinkRaw` is enabled with
// a vendor-specific format). Sub-handlers methods like
// `SignalFrameCounterUsedOnTxDone()` validate `mParsedFully`
// in `frameInfo` individually.
IgnoreError(frameInfo.ParseFrom(aFrame, Frame::kParseFully));
// Stop ack timeout timer.
@@ -554,7 +575,7 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
mCallbacks.RecordCcaStatus(ccaSuccess, aFrame.GetChannel());
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
UpdateCslLastSyncTimestamp(aFrame, aAckFrame);
UpdateCslLastSyncTimestamp(frameInfo, aAckFrame);
#endif
break;
@@ -563,7 +584,7 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
OT_UNREACHABLE_CODE(ExitNow());
}
SignalFrameCounterUsedOnTxDone(aFrame);
SignalFrameCounterUsedOnTxDone(frameInfo);
// Determine whether a CSMA retry is required.
@@ -581,7 +602,7 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
shouldRetx = ((aError != kErrorNone) && ShouldHandle(kCapTransmitRetries) &&
(mTransmitRetries < aFrame.GetMaxFrameRetries()));
mCallbacks.RecordFrameTransmitStatus(aFrame, aError, mTransmitRetries, shouldRetx);
mCallbacks.RecordFrameTransmitStatus(frameInfo, aError, mTransmitRetries, shouldRetx);
if (shouldRetx)
{
@@ -589,7 +610,7 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
aFrame.SetIsARetransmission(true);
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
ReprocessSecurityForRetx(aFrame);
ReprocessSecurityForRetx(frameInfo);
#endif
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
@@ -622,7 +643,7 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
}
#endif
mCallbacks.TransmitDone(aFrame, aAckFrame, aError);
mCallbacks.TransmitDone(frameInfo, aAckFrame, aError);
exit:
return;
@@ -630,32 +651,31 @@ exit:
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
void SubMac::ReprocessSecurityForRetx(TxFrame &aFrame)
void SubMac::ReprocessSecurityForRetx(TxFrame::ParseInfo &aFrameInfo)
{
// Re-processes transmit security on a frame being retransmitted if
// it contains Header IEs. The frame is first restored back to
// plaintext and then re-encrypted with a new frame counter value.
VerifyOrExit(aFrame.GetSecurityEnabled() && aFrame.IsIePresent());
VerifyOrExit(aFrameInfo.mParsedFully);
VerifyOrExit(aFrameInfo.mIsSecurityEnabled);
VerifyOrExit(aFrameInfo.mIsIePresent);
// When transmit security is handled by `SubMac`, the AES key is already set
// on `aFrame`. However, when transmit security is delegated to the radio
// platform, the radio is not required to set or preserve the AES key on
// `aFrame`. To ensure `RestoreTransmitSecurity()` can properly decrypt the
// frame back to plaintext, we determine and set the key on `aFrame` using
// its key index.
// on `aFrameInfo.GetTxFrame()`. However, when transmit security is delegated
// to the radio platform, the radio is not required to set or preserve the AES
// key on the frame. To ensure `RestoreTransmitSecurity()` can properly decrypt
// the frame back to plaintext, we determine and set the key on the frame
// using its key index.
if (!ShouldHandle(kCapTransmitSec))
if (!ShouldHandle(kCapTransmitSec) && (aFrameInfo.mKeyIdMode == Frame::kKeyIdMode1))
{
uint8_t keyIndex;
SuccessOrExit(aFrame.GetKeyIndex(keyIndex));
aFrame.SetAesKey(mKeyTrio.SelectKey(keyIndex));
aFrameInfo.GetTxFrame()->SetAesKey(mKeyTrio.SelectKey(aFrameInfo.mKeyIndex));
}
aFrame.RestoreTransmitSecurity(GetExtAddress());
aFrameInfo.RestoreTransmitSecurity(GetExtAddress());
ProcessTransmitSecurity();
ProcessTransmitSecurity(aFrameInfo);
exit:
return;
@@ -663,16 +683,9 @@ exit:
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
void SubMac::SignalFrameCounterUsedOnTxDone(const TxFrame &aFrame)
void SubMac::SignalFrameCounterUsedOnTxDone(const TxFrame::ParseInfo &aFrameInfo)
{
Frame::KeyIdMode keyIdMode;
uint8_t keyIndex;
uint32_t frameCounter;
bool allowError = false;
OT_UNUSED_VARIABLE(allowError);
VerifyOrExit(!ShouldHandle(kCapTransmitSec) && aFrame.GetSecurityEnabled() && aFrame.IsHeaderUpdated());
VerifyOrExit(!ShouldHandle(kCapTransmitSec));
// In an FTD/MTD build, if/when link-raw is enabled, the `TxFrame`
// is prepared and given by user and may not necessarily follow 15.4
@@ -683,17 +696,21 @@ void SubMac::SignalFrameCounterUsedOnTxDone(const TxFrame &aFrame)
// OpenThread core, we expect no error and therefore assert if
// parsing fails.
if (!aFrameInfo.mParsedFully)
{
#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE
allowError = Get<LinkRaw>().IsEnabled();
VerifyOrExit(!Get<LinkRaw>().IsEnabled());
#endif
OT_ASSERT(false);
OT_UNREACHABLE_CODE(ExitNow());
}
VerifyOrExit(aFrame.GetKeyIdMode(keyIdMode) == kErrorNone, OT_ASSERT(allowError));
VerifyOrExit(keyIdMode == Frame::kKeyIdMode1);
VerifyOrExit(aFrameInfo.mIsSecurityEnabled);
VerifyOrExit(aFrameInfo.GetTxFrame()->IsHeaderUpdated());
VerifyOrExit(aFrame.GetFrameCounter(frameCounter) == kErrorNone, OT_ASSERT(allowError));
VerifyOrExit(aFrame.GetKeyIndex(keyIndex) == kErrorNone, OT_ASSERT(allowError));
VerifyOrExit(aFrameInfo.mKeyIdMode == Frame::kKeyIdMode1);
SignalFrameCounterUsed(frameCounter, keyIndex);
SignalFrameCounterUsed(aFrameInfo.mFrameCounter, aFrameInfo.mKeyIndex);
exit:
return;
+11 -8
View File
@@ -168,7 +168,7 @@ public:
* @note Unlike `TransmitDone` which is invoked after all re-transmission attempts to indicate the final status
* of a frame transmission, this method is invoked on all frame transmission attempts.
*
* @param[in] aFrame The transmitted frame.
* @param[in] aFrameInfo The transmitted frame information.
* @param[in] aError kErrorNone when the frame was transmitted successfully,
* kErrorNoAck when the frame was transmitted but no ACK was received,
* kErrorChannelAccessFailure tx failed due to activity on the channel,
@@ -177,20 +177,23 @@ public:
* @param[in] aWillRetx Indicates whether frame will be retransmitted or not. This is applicable only
* when there was an error in current transmission attempt.
*/
void RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx);
void RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx);
/**
* The method notifies user of `SubMac` that the transmit operation has completed, providing, if applicable,
* the received ACK frame.
*
* @param[in] aFrame The transmitted frame.
* @param[in] aFrameInfo The transmitted frame information.
* @param[in] aAckFrame A pointer to the ACK frame, `nullptr` if no ACK was received.
* @param[in] aError kErrorNone when the frame was transmitted,
* kErrorNoAck when the frame was transmitted but no ACK was received,
* kErrorChannelAccessFailure tx failed due to activity on the channel,
* kErrorAbort when transmission was aborted for other reasons.
*/
void TransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
void TransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError);
/**
* Notifies user of `SubMac` that energy scan is complete.
@@ -637,8 +640,8 @@ private:
bool ShouldHandle(Capability aCapability) const;
bool ShouldHandleCsmaBackoff(void) const;
void ProcessTransmitSecurity(void);
void ReprocessSecurityForRetx(TxFrame &aFrame);
void ProcessTransmitSecurity(TxFrame::ParseInfo &aFrameInfo);
void ReprocessSecurityForRetx(TxFrame::ParseInfo &aFrameInfo);
void SignalFrameCounterUsed(uint32_t aFrameCounter, uint8_t aKeyIndex);
void StartCsmaBackoff(void);
void StartTimerForBackoff(uint8_t aBackoffExponent);
@@ -650,7 +653,7 @@ private:
void HandleReceiveDone(RxFrame *aFrame, Error aError);
void HandleTransmitStarted(TxFrame &aFrame);
void HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
void SignalFrameCounterUsedOnTxDone(const TxFrame &aFrame);
void SignalFrameCounterUsedOnTxDone(const TxFrame::ParseInfo &aFrameInfo);
void HandleEnergyScanDone(int8_t aMaxRssi);
void HandleTimer(void);
@@ -665,7 +668,7 @@ private:
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
void CslInit(void);
void RestartCslTimerAfterSyncUpdate(void);
void UpdateCslLastSyncTimestamp(TxFrame &aFrame, RxFrame *aAckFrame);
void UpdateCslLastSyncTimestamp(const TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame);
void UpdateCslLastSyncTimestamp(RxFrame *aFrame, Error aError);
void SetCslLastSyncToNow(void);
void HandleCslTimer(void);
+15 -15
View File
@@ -64,25 +64,25 @@ void SubMac::Callbacks::RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel)
Get<Mac>().RecordCcaStatus(aCcaSuccess, aChannel);
}
void SubMac::Callbacks::RecordFrameTransmitStatus(const TxFrame &aFrame,
Error aError,
uint8_t aRetryCount,
bool aWillRetx)
void SubMac::Callbacks::RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx)
{
Get<Mac>().RecordFrameTransmitStatus(aFrame, aError, aRetryCount, aWillRetx);
Get<Mac>().RecordFrameTransmitStatus(aFrameInfo, aError, aRetryCount, aWillRetx);
}
void SubMac::Callbacks::TransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
void SubMac::Callbacks::TransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError)
{
#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE
if (Get<LinkRaw>().IsEnabled())
{
Get<LinkRaw>().InvokeTransmitDone(aFrame, aAckFrame, aError);
Get<LinkRaw>().InvokeTransmitDone(aFrameInfo, aAckFrame, aError);
}
else
#endif
{
Get<Mac>().HandleTransmitDone(aFrame, aAckFrame, aError);
Get<Mac>().HandleTransmitDone(aFrameInfo, aAckFrame, aError);
}
}
@@ -111,17 +111,17 @@ void SubMac::Callbacks::ReceiveDone(RxFrame *aFrame, Error aError) { Get<LinkRaw
void SubMac::Callbacks::RecordCcaStatus(bool, uint8_t) {}
void SubMac::Callbacks::RecordFrameTransmitStatus(const TxFrame &aFrame,
Error aError,
uint8_t aRetryCount,
bool aWillRetx)
void SubMac::Callbacks::RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo,
Error aError,
uint8_t aRetryCount,
bool aWillRetx)
{
Get<LinkRaw>().RecordFrameTransmitStatus(aFrame, aError, aRetryCount, aWillRetx);
Get<LinkRaw>().RecordFrameTransmitStatus(aFrameInfo, aError, aRetryCount, aWillRetx);
}
void SubMac::Callbacks::TransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
void SubMac::Callbacks::TransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError)
{
Get<LinkRaw>().InvokeTransmitDone(aFrame, aAckFrame, aError);
Get<LinkRaw>().InvokeTransmitDone(aFrameInfo, aAckFrame, aError);
}
void SubMac::Callbacks::EnergyScanDone(int8_t aMaxRssi) { Get<LinkRaw>().InvokeEnergyScanDone(aMaxRssi); }
+19 -13
View File
@@ -73,15 +73,20 @@ void SubMac::RestartCslTimerAfterSyncUpdate(void)
}
}
void SubMac::UpdateCslLastSyncTimestamp(TxFrame &aFrame, RxFrame *aAckFrame)
void SubMac::UpdateCslLastSyncTimestamp(const TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame)
{
// Actual synchronization timestamp should be from the sent frame instead of the current time.
// Assuming the error here since it is bounded and has very small effect on the final window duration.
if (aAckFrame != nullptr && aFrame.Has<CslIe>())
{
SetCslLastSyncToNow();
RestartCslTimerAfterSyncUpdate();
}
VerifyOrExit(aAckFrame != nullptr);
VerifyOrExit(aFrameInfo.mParsedFully);
VerifyOrExit(aFrameInfo.Has<CslIe>());
SetCslLastSyncToNow();
RestartCslTimerAfterSyncUpdate();
exit:
return;
}
void SubMac::UpdateCslLastSyncTimestamp(RxFrame *aFrame, Error aError)
@@ -241,15 +246,16 @@ void SubMac::LogReceived(RxFrame *aFrame)
{
static constexpr uint8_t kLogStringSize = 72;
String<kLogStringSize> logString;
Address dst;
int32_t deviation;
uint32_t sampleTime, ahead, after;
String<kLogStringSize> logString;
Mac::RxFrame::ParseInfo frameInfo;
int32_t deviation;
uint32_t sampleTime, ahead, after;
IgnoreError(aFrame->GetDstAddr(dst));
IgnoreError(frameInfo.ParseFrom(*aFrame, Mac::Frame::kParseAddrFields));
VerifyOrExit((dst.GetType() == Address::kTypeShort && dst.GetShort() == GetShortAddress()) ||
(dst.GetType() == Address::kTypeExtended && dst.GetExtended() == GetExtAddress()));
VerifyOrExit(
(frameInfo.mAddrs.mDestination.IsShort() && frameInfo.mAddrs.mDestination.GetShort() == GetShortAddress()) ||
(frameInfo.mAddrs.mDestination.IsExtended() && frameInfo.mAddrs.mDestination.GetExtended() == GetExtAddress()));
LogDebg("Received frame in state %s, timestamp %lu", StateToString(mState),
ToUlong(Radio::ConvertTime64To32(aFrame->GetTimestamp())));
+19 -10
View File
@@ -79,13 +79,15 @@ void WakeupTxScheduler::RequestWakeupFrameTransmission(void) { Get<Mac::Mac>().R
Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
{
Mac::TxFrame *frame = nullptr;
Mac::Address source;
uint32_t radioTxDelay;
uint32_t rendezvousTimeUs;
TimeMicro nowUs = TimerMicro::GetNow();
Radio::Time64 radioNow = Get<Radio::Radio>().GetNow();
Mac::ConnectionIe *connectionIe;
Mac::TxFrame *frame = nullptr;
Mac::TxFrame::ParseInfo txFrameInfo;
Mac::Address source;
uint32_t radioTxDelay;
uint32_t rendezvousTimeUs;
TimeMicro nowUs = TimerMicro::GetNow();
Radio::Time64 radioNow = Get<Radio::Radio>().GetNow();
Mac::RendezvousTimeIe *rendezvousTimeIe;
Mac::ConnectionIe *connectionIe;
VerifyOrExit(mIsRunning);
@@ -102,6 +104,11 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
VerifyOrExit(frame->GenerateWakeupFrame(Get<Mac::Mac>().GetPanId(), mWakeupRequest, source) == kErrorNone,
frame = nullptr);
if (txFrameInfo.ParseFrom(*frame, Mac::Frame::kParseFully) != kErrorNone)
{
ExitNow(frame = nullptr);
}
frame->SetTargetTxTime(radioNow + radioTxDelay, radioNow);
frame->SetCsmaCaEnabled(kWakeupFrameTxCca);
frame->SetMaxCsmaBackoffs(0);
@@ -113,10 +120,12 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
rendezvousTimeUs = mIntervalUs;
rendezvousTimeUs += (mIntervalUs - (kWakeupFrameLength + kParentRequestLength) * Radio::kOctetDuration) / 2;
frame->Find<Mac::RendezvousTimeIe>()->SetRendezvousTime(
ClampToUint16(rendezvousTimeUs / Radio::kTenSymbolsDuration));
rendezvousTimeIe = txFrameInfo.Find<Mac::RendezvousTimeIe>();
VerifyOrExit(rendezvousTimeIe != nullptr, frame = nullptr);
rendezvousTimeIe->SetRendezvousTime(ClampToUint16(rendezvousTimeUs / Radio::kTenSymbolsDuration));
connectionIe = frame->Find<Mac::ConnectionIe>();
connectionIe = txFrameInfo.Find<Mac::ConnectionIe>();
VerifyOrExit(connectionIe != nullptr, frame = nullptr);
connectionIe->SetRetryInterval(kConnectionRetryInterval);
connectionIe->SetRetryCount(kConnectionRetryCount);
+26 -15
View File
@@ -115,13 +115,14 @@ void Link::HandleTxTasklet(void) { BeginTransmit(); }
void Link::BeginTransmit(void)
{
Mac::Address destAddr;
Mac::PanId destPanId;
Header::Type type;
Packet txPacket;
Neighbor *neighbor = nullptr;
Mac::RxFrame *ackFrame = nullptr;
bool isDiscovery = false;
Mac::TxFrame::ParseInfo txFrameInfo;
Mac::Address destAddr;
Mac::PanId destPanId;
Header::Type type;
Packet txPacket;
Neighbor *neighbor = nullptr;
Mac::RxFrame *ackFrame = nullptr;
bool isDiscovery = false;
VerifyOrExit(mState == kStateTransmit);
@@ -131,7 +132,9 @@ void Link::BeginTransmit(void)
VerifyOrExit(!mTxFrame.IsEmpty(), InvokeSendDone(kErrorAbort));
IgnoreError(mTxFrame.GetDstAddr(destAddr));
IgnoreError(txFrameInfo.ParseFrom(mTxFrame, Mac::Frame::kParseFully));
destAddr = txFrameInfo.mAddrs.mDestination;
if (destAddr.IsNone() || destAddr.IsBroadcast())
{
@@ -166,17 +169,21 @@ void Link::BeginTransmit(void)
// MAC Key ID mode 2. All data communication uses MAC Key ID
// Mode 1.
if (!mTxFrame.GetSecurityEnabled())
if (!txFrameInfo.mIsSecurityEnabled)
{
isDiscovery = true;
}
else
{
isDiscovery = mTxFrame.HasKeyIdMode(Mac::Frame::kKeyIdMode2);
isDiscovery = (txFrameInfo.mKeyIdMode == Mac::Frame::kKeyIdMode2);
}
}
if (mTxFrame.GetDstPanId(destPanId) != kErrorNone)
if (txFrameInfo.mPanIds.IsDestinationPresent())
{
destPanId = txFrameInfo.mPanIds.GetDestination();
}
else
{
destPanId = Mac::kPanIdBroadcast;
}
@@ -209,7 +216,7 @@ void Link::BeginTransmit(void)
VerifyOrExit(mInterface.Send(txPacket, isDiscovery) == kErrorNone, InvokeSendDone(kErrorAbort));
if (mTxFrame.GetAckRequest())
if (txFrameInfo.mIsAckRequest)
{
uint16_t fcf = Mac::Frame::kTypeAck;
@@ -220,7 +227,7 @@ void Link::BeginTransmit(void)
// Prepare the ack frame (FCF followed by sequence number)
LittleEndian::WriteUint16(fcf, mAckFrameBuffer);
mAckFrameBuffer[sizeof(fcf)] = mTxFrame.GetSequence();
mAckFrameBuffer[sizeof(fcf)] = txFrameInfo.mSequenceNum;
mRxFrame.mPsdu = mAckFrameBuffer;
mRxFrame.mLength = k154AckFrameSize;
@@ -244,10 +251,14 @@ exit:
void Link::InvokeSendDone(Error aError, Mac::RxFrame *aAckFrame)
{
Mac::TxFrame::ParseInfo frameInfo;
SetState(kStateReceive);
Get<Mac::Mac>().RecordFrameTransmitStatus(mTxFrame, aError, /* aRetryCount */ 0, /* aWillRetx */ false);
Get<Mac::Mac>().HandleTransmitDone(mTxFrame, aAckFrame, aError);
IgnoreError(frameInfo.ParseFrom(mTxFrame, Mac::Frame::kParseFully));
Get<Mac::Mac>().RecordFrameTransmitStatus(frameInfo, aError, /* aRetryCount */ 0, /* aWillRetx */ false);
Get<Mac::Mac>().HandleTransmitDone(frameInfo, aAckFrame, aError);
}
void Link::HandleTimer(void)
+17 -19
View File
@@ -258,13 +258,17 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
// child, we ensure to use the same frame counter, key id, and
// data sequence number as the previous attempt.
frame->SetIsARetransmission(true);
frame->SetSequence(mCslTxNeighbor->GetIndirectDataSequenceNumber());
Mac::TxFrame::ParseInfo frameInfo;
if (frame->GetSecurityEnabled())
frame->SetIsARetransmission(true);
IgnoreError(frameInfo.ParseFrom(*frame, Mac::Frame::kParseFully));
frameInfo.WriteSequenceNum(mCslTxNeighbor->GetIndirectDataSequenceNumber());
if (frameInfo.mIsSecurityEnabled)
{
frame->SetFrameCounter(mCslTxNeighbor->GetIndirectFrameCounter());
frame->SetKeyIndex(mCslTxNeighbor->GetIndirectKeyIndex());
frameInfo.WriteFrameCounter(mCslTxNeighbor->GetIndirectFrameCounter());
frameInfo.WriteKeyIndex(mCslTxNeighbor->GetIndirectKeyIndex());
}
}
else
@@ -303,7 +307,7 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &) { return nullp
#endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
void CslTxScheduler::HandleSentFrame(const Mac::TxFrame::ParseInfo &aFrameInfo, Error aError)
{
VerifyOrExit(mCslTxNeighbor != nullptr);
@@ -315,7 +319,7 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
break;
case kErrorNoAck:
OT_ASSERT(!aFrame.GetSecurityEnabled() || aFrame.IsHeaderUpdated());
OT_ASSERT(!aFrameInfo.mIsSecurityEnabled || aFrameInfo.GetTxFrame()->IsHeaderUpdated());
mCslTxNeighbor->IncrementCslTxAttempts();
LogInfo("CSL tx to %04x failed, attempt %d/%d", mCslTxNeighbor->GetRloc16(), mCslTxNeighbor->GetCslTxAttempts(),
@@ -337,20 +341,14 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
// dropped until indirect tx attempts count reaches max. So here it
// would set sequence number and schedule next CSL tx.
if (!aFrame.IsEmpty())
if (!aFrameInfo.GetTxFrame()->IsEmpty())
{
mCslTxNeighbor->SetIndirectDataSequenceNumber(aFrame.GetSequence());
mCslTxNeighbor->SetIndirectDataSequenceNumber(aFrameInfo.mSequenceNum);
if (aFrame.GetSecurityEnabled() && aFrame.IsHeaderUpdated())
if (aFrameInfo.mIsSecurityEnabled && aFrameInfo.GetTxFrame()->IsHeaderUpdated())
{
uint32_t frameCounter;
uint8_t keyIndex;
IgnoreError(aFrame.GetFrameCounter(frameCounter));
mCslTxNeighbor->SetIndirectFrameCounter(frameCounter);
IgnoreError(aFrame.GetKeyIndex(keyIndex));
mCslTxNeighbor->SetIndirectKeyIndex(keyIndex);
mCslTxNeighbor->SetIndirectFrameCounter(aFrameInfo.mFrameCounter);
mCslTxNeighbor->SetIndirectKeyIndex(aFrameInfo.mKeyIndex);
}
}
@@ -361,7 +359,7 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
OT_UNREACHABLE_CODE(break);
}
Get<IndirectSender>().HandleSentFrameToCslNeighbor(aFrame, mFrameContext, aError, *mCslTxNeighbor);
Get<IndirectSender>().HandleSentFrameToCslNeighbor(aFrameInfo, mFrameContext, aError, *mCslTxNeighbor);
exit:
mCslTxMessage = nullptr;
+1 -1
View File
@@ -243,7 +243,7 @@ private:
// Callbacks from `Mac`
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError);
void HandleSentFrame(const Mac::TxFrame::ParseInfo &aFrameInfo, Error aError);
void HandleMacEnableStatusChanged(void);
// Callback from `Radio`
+13 -13
View File
@@ -381,10 +381,10 @@ exit:
return error;
}
void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
Error aError,
Child &aChild)
void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame::ParseInfo &aFrameInfo,
const FrameContext &aContext,
Error aError,
Child &aChild)
{
Message *message = aChild.GetIndirectMessage();
uint16_t nextOffset = aContext.mMessageNextOffset;
@@ -484,9 +484,9 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
}
#endif
if (!aFrame.IsEmpty())
if (!aFrameInfo.GetTxFrame()->IsEmpty())
{
IgnoreError(aFrame.GetDstAddr(macDest));
macDest = aFrameInfo.mAddrs.mDestination;
Get<MeshForwarder>().LogMessage(MeshForwarder::kMessageTransmit, *message, txError, &macDest);
}
@@ -501,7 +501,7 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
message->InvokeTxCallback(txError);
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
if (aFrame.IsEmpty())
if (aFrameInfo.GetTxFrame()->IsEmpty())
{
aChild.GetMacAddress(macDest);
}
@@ -567,15 +567,15 @@ Error IndirectSender::PrepareFrameForCslNeighbor(Mac::TxFrame &aFrame,
return error;
}
void IndirectSender::HandleSentFrameToCslNeighbor(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
Error aError,
CslNeighbor &aCslNeighbor)
void IndirectSender::HandleSentFrameToCslNeighbor(const Mac::TxFrame::ParseInfo &aFrameInfo,
const FrameContext &aContext,
Error aError,
CslNeighbor &aCslNeighbor)
{
#if OPENTHREAD_FTD
HandleSentFrameToChild(aFrame, aContext, aError, static_cast<Child &>(aCslNeighbor));
HandleSentFrameToChild(aFrameInfo, aContext, aError, static_cast<Child &>(aCslNeighbor));
#else
OT_UNUSED_VARIABLE(aFrame);
OT_UNUSED_VARIABLE(aFrameInfo);
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aError);
OT_UNUSED_VARIABLE(aCslNeighbor);
+8 -5
View File
@@ -261,16 +261,19 @@ private:
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
// Callbacks from `CslTxScheduler`
Error PrepareFrameForCslNeighbor(Mac::TxFrame &aFrame, FrameContext &aContext, CslNeighbor &aCslNeighbor);
void HandleSentFrameToCslNeighbor(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
Error aError,
CslNeighbor &aCslNeighbor);
void HandleSentFrameToCslNeighbor(const Mac::TxFrame::ParseInfo &aFrameInfo,
const FrameContext &aContext,
Error aError,
CslNeighbor &aCslNeighbor);
#endif
#if OPENTHREAD_FTD
// Callbacks from `DataPollHandler`
Error PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild);
void HandleSentFrameToChild(const Mac::TxFrame &aFrame, const FrameContext &aContext, Error aError, Child &aChild);
void HandleSentFrameToChild(const Mac::TxFrame::ParseInfo &aFrameInfo,
const FrameContext &aContext,
Error aError,
Child &aChild);
void HandleFrameChangeDone(Child &aChild);
void UpdateIndirectMessage(Child &aChild);
+23 -26
View File
@@ -736,10 +736,10 @@ exit:
return frame;
}
Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame,
Error aError,
const Mac::Address &aMacDest,
bool aIsDataPoll)
Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::TxFrame::ParseInfo &aFrameInfo,
Error aError,
const Mac::Address &aMacDest,
bool aIsDataPoll)
{
OT_UNUSED_VARIABLE(aIsDataPoll);
@@ -751,14 +751,14 @@ Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame,
neighbor = Get<NeighborTable>().FindNeighbor(aMacDest);
VerifyOrExit(neighbor != nullptr);
VerifyOrExit(aFrame.GetAckRequest());
VerifyOrExit(aFrameInfo.mIsAckRequest);
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
// TREL radio link uses deferred ack model. We ignore
// `SendDone` event from `Mac` layer with success status and
// wait for deferred ack callback instead.
#if OPENTHREAD_CONFIG_MULTI_RADIO
if (aFrame.GetRadioType() == Radio::kTypeTrel)
if (aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeTrel)
#endif
{
VerifyOrExit(aError != kErrorNone);
@@ -766,7 +766,7 @@ Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame,
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (aFrame.Has<Mac::CslIe>() && aIsDataPoll)
if (aFrameInfo.Has<Mac::CslIe>() && aIsDataPoll)
{
failLimit = kFailedCslDataPollTransmissions;
}
@@ -831,10 +831,9 @@ exit:
}
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, Error aError)
void MeshForwarder::HandleSentFrame(Mac::TxFrame::ParseInfo &aFrameInfo, Error aError)
{
Neighbor *neighbor = nullptr;
Mac::Address macDest;
Neighbor *neighbor = nullptr;
OT_ASSERT((aError == kErrorNone) || (aError == kErrorChannelAccessFailure) || (aError == kErrorAbort) ||
(aError == kErrorNoAck));
@@ -855,13 +854,13 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, Error aError)
}
#endif
if (!aFrame.IsEmpty())
if (!aFrameInfo.GetTxFrame()->IsEmpty())
{
IgnoreError(aFrame.GetDstAddr(macDest));
neighbor = UpdateNeighborOnSentFrame(aFrame, aError, macDest, /* aIsDataPoll */ false);
neighbor =
UpdateNeighborOnSentFrame(aFrameInfo, aError, aFrameInfo.mAddrs.mDestination, /* aIsDataPoll */ false);
}
UpdateSendMessage(aError, macDest, neighbor);
UpdateSendMessage(aError, aFrameInfo.mAddrs.mDestination, neighbor);
exit:
return;
@@ -1005,19 +1004,17 @@ exit:
return error;
}
void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
void MeshForwarder::HandleReceivedFrame(Mac::RxFrame::ParseInfo &aFrameInfo)
{
Error error = kErrorNone;
RxInfo rxInfo(GetInstance());
VerifyOrExit(mEnabled, error = kErrorInvalidState);
SuccessOrExit(error = aFrame.GetPayload(rxInfo.mFrameData));
rxInfo.mFrameData = aFrameInfo.mPayload;
rxInfo.mMacAddrs = aFrameInfo.mAddrs;
SuccessOrExit(error = aFrame.GetSrcAddr(rxInfo.mMacAddrs.mSource));
SuccessOrExit(error = aFrame.GetDstAddr(rxInfo.mMacAddrs.mDestination));
rxInfo.mLinkInfo.SetFrom(aFrame);
rxInfo.mLinkInfo.SetFrom(aFrameInfo);
Get<SupervisionListener>().UpdateOnReceive(rxInfo.mMacAddrs.mSource, rxInfo.IsLinkSecurityEnabled());
@@ -1039,14 +1036,14 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
{
VerifyOrExit(rxInfo.mFrameData.GetLength() == 0, error = kErrorNotLowpanDataFrame);
LogFrame("Received empty payload frame", aFrame, kErrorNone);
LogFrame("Received empty payload frame", aFrameInfo, kErrorNone);
}
exit:
if (error != kErrorNone)
{
LogFrame("Dropping rx frame", aFrame, error);
LogFrame("Dropping rx frame", aFrameInfo, error);
}
}
@@ -1589,15 +1586,15 @@ void MeshForwarder::LogMessage(MessageAction, const Message &, Error, const Mac:
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void MeshForwarder::LogFrame(const char *aActionText, const Mac::Frame &aFrame, Error aError)
void MeshForwarder::LogFrame(const char *aActionText, const Mac::Frame::ParseInfo &aFrameInfo, Error aError)
{
if (aError != kErrorNone)
{
LogInfo("%s, aError:%s, %s", aActionText, ErrorToString(aError), aFrame.ToInfoString().AsCString());
LogInfo("%s, aError:%s, %s", aActionText, ErrorToString(aError), aFrameInfo.ToInfoString().AsCString());
}
else
{
LogInfo("%s, %s", aActionText, aFrame.ToInfoString().AsCString());
LogInfo("%s, %s", aActionText, aFrameInfo.ToInfoString().AsCString());
}
}
@@ -1627,7 +1624,7 @@ MeshForwarder::RxInfo::InfoString MeshForwarder::RxInfo::ToString(void) const
#else // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void MeshForwarder::LogFrame(const char *, const Mac::Frame &, Error) {}
void MeshForwarder::LogFrame(const char *, const Mac::Frame::ParseInfo &, Error) {}
void MeshForwarder::LogFragmentFrameDrop(Error, const RxInfo &, const Lowpan::FragmentHeader &) {}
+7 -7
View File
@@ -456,14 +456,14 @@ private:
Error RemoveUnsecureReassemblyMessage(EvictReason aEvictReason);
void HandleDiscoverComplete(void);
void HandleReceivedFrame(Mac::RxFrame &aFrame);
void HandleReceivedFrame(Mac::RxFrame::ParseInfo &aFrameInfo);
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
Neighbor *UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame,
Error aError,
const Mac::Address &aMacDest,
bool aIsDataPoll);
Neighbor *UpdateNeighborOnSentFrame(Mac::TxFrame::ParseInfo &aFrameInfo,
Error aError,
const Mac::Address &aMacDest,
bool aIsDataPoll);
void UpdateNeighborLinkFailures(Neighbor &aNeighbor, Error aError, bool aAllowNeighborRemove, uint8_t aFailLimit);
void HandleSentFrame(Mac::TxFrame &aFrame, Error aError);
void HandleSentFrame(Mac::TxFrame::ParseInfo &aFrameInfo, Error aError);
void UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDest, Neighbor *aNeighbor);
void FinalizeMessageDirectTx(Message &aMessage, Error aError);
void FinalizeAndRemoveMessage(Message &aMessage, Error aError, MessageAction aAction);
@@ -497,7 +497,7 @@ private:
void LogMessage(MessageAction aAction, const Message &aMessage);
void LogMessage(MessageAction aAction, const Message &aMessage, Error aError);
void LogMessage(MessageAction aAction, const Message &aMessage, Error aError, const Mac::Address *aAddress);
void LogFrame(const char *aActionText, const Mac::Frame &aFrame, Error aError);
void LogFrame(const char *aActionText, const Mac::Frame::ParseInfo &aFrameInfo, Error aError);
void LogFragmentFrameDrop(Error aError, const RxInfo &aRxInfo, const Lowpan::FragmentHeader &aFragmentHeader);
void LogLowpanHcFrameDrop(Error aError, const RxInfo &aRxInfo);
+6 -8
View File
@@ -125,12 +125,11 @@ void RadioSelector::UpdateOnReceive(Neighbor &aNeighbor, Radio::Type aRadioType,
}
}
void RadioSelector::UpdateOnSendDone(Mac::TxFrame &aFrame, Error aTxError)
void RadioSelector::UpdateOnSendDone(Mac::TxFrame::ParseInfo &aFrameInfo, Error aTxError)
{
LogLevel logLevel = kLogLevelInfo;
Radio::Type radioType = aFrame.GetRadioType();
Mac::Address macDest;
Neighbor *neighbor;
LogLevel logLevel = kLogLevelInfo;
Radio::Type radioType = aFrameInfo.GetTxFrame()->GetRadioType();
Neighbor *neighbor;
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
if (radioType == Radio::kTypeTrel)
@@ -142,10 +141,9 @@ void RadioSelector::UpdateOnSendDone(Mac::TxFrame &aFrame, Error aTxError)
}
#endif
VerifyOrExit(aFrame.GetAckRequest());
VerifyOrExit(aFrameInfo.mIsAckRequest);
IgnoreError(aFrame.GetDstAddr(macDest));
neighbor = Get<NeighborTable>().FindNeighbor(macDest, Neighbor::kInStateAnyExceptInvalid);
neighbor = Get<NeighborTable>().FindNeighbor(aFrameInfo.mAddrs.mDestination, Neighbor::kInStateAnyExceptInvalid);
VerifyOrExit(neighbor != nullptr);
if (neighbor->GetSupportedRadioTypes().Contains(radioType))
+2 -2
View File
@@ -131,10 +131,10 @@ public:
* Notifies `RadioSelector` the status of frame transmission on a radio link type. The radio link
* type is provided by the `aFrame` itself.
*
* @param[in] aFrame A transmitted frame.
* @param[in] aFrameInfo A transmitted frame information.
* @param[in] aTxError The transmission error.
*/
void UpdateOnSendDone(Mac::TxFrame &aFrame, Error aTxError);
void UpdateOnSendDone(Mac::TxFrame::ParseInfo &aFrameInfo, Error aTxError);
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
/**
+33 -11
View File
@@ -35,19 +35,27 @@
namespace ot {
void ThreadLinkInfo::SetFrom(const Mac::RxFrame &aFrame)
void ThreadLinkInfo::SetFrom(const Mac::RxFrame::ParseInfo &aFrameInfo)
{
Clear();
if (kErrorNone != aFrame.GetSrcPanId(mPanId))
if (aFrameInfo.mPanIds.IsSourcePresent())
{
IgnoreError(aFrame.GetDstPanId(mPanId));
mPanId = aFrameInfo.mPanIds.GetSource();
}
else
{
mPanId = aFrameInfo.mPanIds.GetDestination();
}
{
Mac::PanId dstPanId;
if (kErrorNone != aFrame.GetDstPanId(dstPanId))
if (aFrameInfo.mPanIds.IsDestinationPresent())
{
dstPanId = aFrameInfo.mPanIds.GetDestination();
}
else
{
dstPanId = mPanId;
}
@@ -55,25 +63,39 @@ void ThreadLinkInfo::SetFrom(const Mac::RxFrame &aFrame)
mIsDstPanIdBroadcast = (dstPanId == Mac::kPanIdBroadcast);
}
mLinkSecurity = aFrame.IsSecuredWith(Mac::RxFrame::kAllowKeyIdMode0 | Mac::RxFrame::kAllowKeyIdMode1);
mChannel = aFrame.GetChannel();
mRss = aFrame.GetRssi();
mLqi = aFrame.GetLqi();
mLinkSecurity = false;
if (aFrameInfo.mIsSecurityEnabled)
{
switch (aFrameInfo.mKeyIdMode)
{
case Mac::Frame::kKeyIdMode0:
case Mac::Frame::kKeyIdMode1:
mLinkSecurity = true;
break;
default:
break;
}
}
mChannel = aFrameInfo.GetRxFrame()->GetChannel();
mRss = aFrameInfo.GetRxFrame()->GetRssi();
mLqi = aFrameInfo.GetRxFrame()->GetLqi();
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
{
const Mac::TimeIe *timeIe = aFrame.Find<Mac::TimeIe>();
const Mac::TimeIe *timeIe = aFrameInfo.Find<Mac::TimeIe>();
if (timeIe != nullptr)
{
mNetworkTimeOffset = static_cast<int64_t>(timeIe->GetTime() - aFrame.GetTimestamp());
mNetworkTimeOffset = static_cast<int64_t>(timeIe->GetTime() - aFrameInfo.GetRxFrame()->GetTimestamp());
mTimeSyncSeq = timeIe->GetSequence();
}
}
#endif
#if OPENTHREAD_CONFIG_MULTI_RADIO
mRadioType = static_cast<uint8_t>(aFrame.GetRadioType());
mRadioType = static_cast<uint8_t>(aFrameInfo.GetRxFrame()->GetRadioType());
#endif
}
+1 -1
View File
@@ -115,7 +115,7 @@ public:
*
* @param[in] aFrame A received frame.
*/
void SetFrom(const Mac::RxFrame &aFrame);
void SetFrom(const Mac::RxFrame::ParseInfo &aFrameInfo);
};
DefineCoreType(otThreadLinkInfo, ThreadLinkInfo);
+15 -9
View File
@@ -68,20 +68,26 @@ void Otns::EmitStatus(const StatusString &aString) const { otPlatOtnsStatus(aStr
void Otns::EmitTransmit(const Mac::TxFrame &aFrame) const
{
StatusString string;
Mac::Address dst;
uint16_t fcf = 0;
Mac::TxFrame::ParseInfo frameInfo;
StatusString string;
IgnoreError(aFrame.GetDstAddr(dst));
IgnoreError(frameInfo.ParseFrom(aFrame, Mac::Frame::kParseAddrFields));
string.Append("transmit=%d,%04x,%d", aFrame.GetChannel(), aFrame.GetFrameControlField(), aFrame.GetSequence());
if (dst.IsShort())
if (aFrame.GetLength() >= sizeof(uint16_t))
{
string.Append(",%04x", dst.GetShort());
fcf = LittleEndian::ReadUint16(aFrame.GetPsdu());
}
else if (dst.IsExtended())
string.Append("transmit=%u,%04x,%u", aFrame.GetChannel(), fcf, frameInfo.mSequenceNum);
if (frameInfo.mAddrs.mDestination.IsShort())
{
string.Append(",%s", dst.ToString().AsCString());
string.Append(",%04x", frameInfo.mAddrs.mDestination.GetShort());
}
else if (frameInfo.mAddrs.mDestination.IsExtended())
{
string.Append(",%s", frameInfo.mAddrs.mDestination.ToString().AsCString());
}
EmitStatus(string);
+18 -11
View File
@@ -1596,22 +1596,29 @@ void RadioSpinel::HandleTransmitDone(uint32_t aCommand,
error = SpinelStatusToOtError(status);
}
if ((sRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) && (!mTransmitFrame->mInfo.mTxInfo.mIsHeaderUpdated) &&
headerUpdated && static_cast<Mac::TxFrame *>(mTransmitFrame)->GetSecurityEnabled())
if ((sRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) && (!mTransmitFrame->mInfo.mTxInfo.mIsHeaderUpdated) && headerUpdated)
{
uint8_t keyIndex;
uint32_t frameCounter;
Mac::TxFrame::ParseInfo frameInfo;
// Replace transmit frame security key index and frame counter with the one filled by RCP
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT32_S, &keyIndex,
&frameCounter);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
static_cast<Mac::TxFrame *>(mTransmitFrame)->SetKeyIndex(keyIndex);
static_cast<Mac::TxFrame *>(mTransmitFrame)->SetFrameCounter(frameCounter);
IgnoreError(frameInfo.ParseFrom(*static_cast<Mac::TxFrame *>(mTransmitFrame), Mac::Frame::kParseFully));
if (frameInfo.mIsSecurityEnabled)
{
uint8_t keyIndex;
uint32_t frameCounter;
// Replace transmit frame security key index and frame counter with the one filled by RCP
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT32_S,
&keyIndex, &frameCounter);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
frameInfo.WriteKeyIndex(keyIndex);
frameInfo.WriteFrameCounter(frameCounter);
#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
mMacFrameCounterSet = true;
mMacFrameCounterSet = true;
#endif
}
}
static_cast<Mac::TxFrame *>(mTransmitFrame)->SetIsHeaderUpdated(headerUpdated);
+25 -19
View File
@@ -173,9 +173,25 @@ void NcpBase::LinkRawTransmitDone(uint8_t aIid, otRadioFrame *aFrame, otRadioFra
if (mCurTransmitTID[aIid])
{
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(aIid) | mCurTransmitTID[aIid];
bool framePending = (aAckFrame != nullptr && static_cast<Mac::RxFrame *>(aAckFrame)->GetFramePending());
bool headerUpdated = static_cast<Mac::TxFrame *>(aFrame)->IsHeaderUpdated();
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(aIid) | mCurTransmitTID[aIid];
Mac::TxFrame::ParseInfo txFrameInfo;
bool framePending;
bool headerUpdated;
IgnoreError(txFrameInfo.ParseFrom(*static_cast<Mac::TxFrame *>(aFrame), Mac::Frame::kParseFully));
headerUpdated = txFrameInfo.GetTxFrame()->IsHeaderUpdated();
if (aAckFrame != nullptr)
{
Mac::RxFrame::ParseInfo ackFrameInfo;
IgnoreError(ackFrameInfo.ParseFrom(*static_cast<Mac::RxFrame *>(aAckFrame), Mac::Frame::kParseFully));
framePending = ackFrameInfo.mIsFramePending;
}
else
{
framePending = false;
}
// Clear cached transmit TID
mCurTransmitTID[aIid] = 0;
@@ -190,24 +206,14 @@ void NcpBase::LinkRawTransmitDone(uint8_t aIid, otRadioFrame *aFrame, otRadioFra
SuccessOrExit(PackRadioFrame(aAckFrame, aError));
}
if (static_cast<Mac::TxFrame *>(aFrame)->GetSecurityEnabled() && headerUpdated)
if (txFrameInfo.mIsSecurityEnabled && headerUpdated)
{
uint8_t keyIndex;
uint32_t frameCounter;
// If the frame uses Key ID Mode 0, there is no Key Index
// field in the Security Header. We default and still
// write `txFrameInfo.mKeyIndex` (as zero) in this case.
SuccessOrExit(static_cast<Mac::TxFrame *>(aFrame)->GetFrameCounter(frameCounter));
// If the frame uses Key ID Mode 0, there is no Key Index field in
// the Security Header, so `GetKeyIndex()` may return an error.
// We default `keyIndex` to 0 in this case.
if (static_cast<Mac::TxFrame *>(aFrame)->GetKeyIndex(keyIndex) != OT_ERROR_NONE)
{
keyIndex = 0;
}
SuccessOrExit(mEncoder.WriteUint8(keyIndex));
SuccessOrExit(mEncoder.WriteUint32(frameCounter));
SuccessOrExit(mEncoder.WriteUint8(txFrameInfo.mKeyIndex));
SuccessOrExit(mEncoder.WriteUint32(txFrameInfo.mFrameCounter));
}
SuccessOrExit(mEncoder.EndFrame());
+17 -26
View File
@@ -722,25 +722,20 @@ void Core::Process(Node &aNode)
void Core::ProcessRadio(Node &aNode)
{
Mac::Address dstAddr;
uint16_t dstPanId;
bool ackRequested;
AckMode ackMode = kNoAck;
Node *ackNode = nullptr;
Mac::TxFrame::ParseInfo txFrameInfo;
Mac::Address dstAddr;
uint16_t dstPanId;
bool ackRequested;
AckMode ackMode = kNoAck;
Node *ackNode = nullptr;
VerifyOrExit(aNode.mRadio.mState == Radio::kStateTransmit);
if (aNode.mRadio.mTxFrame.GetDstAddr(dstAddr) != kErrorNone)
{
dstAddr.SetNone();
}
IgnoreError(txFrameInfo.ParseFrom(aNode.mRadio.mTxFrame, Mac::Frame::kParseFully));
if (aNode.mRadio.mTxFrame.GetDstPanId(dstPanId) != kErrorNone)
{
dstPanId = Mac::kPanIdBroadcast;
}
ackRequested = aNode.mRadio.mTxFrame.GetAckRequest();
dstAddr = txFrameInfo.mAddrs.mDestination;
dstPanId = txFrameInfo.mPanIds.IsDestinationPresent() ? txFrameInfo.mPanIds.GetDestination() : Mac::kPanIdBroadcast;
ackRequested = txFrameInfo.mIsAckRequest;
SuccessOrQuit(otMacFrameProcessTxSfd(&aNode.mRadio.mTxFrame, mNow, &aNode.mRadio.mRadioContext));
static_cast<Radio::Frame &>(aNode.mRadio.mTxFrame).UpdateFcs();
@@ -816,13 +811,10 @@ void Core::ProcessRadio(Node &aNode)
if (matchesDst && !dstAddr.IsNone() && !dstAddr.IsBroadcast() && ackRequested)
{
Mac::Address srcAddr;
ackMode = kSendAckNoFramePending;
ackNode = &rxNode;
if ((aNode.mRadio.mTxFrame.GetSrcAddr(srcAddr) == kErrorNone) &&
rxNode.mRadio.HasFramePendingFor(srcAddr))
if (rxNode.mRadio.HasFramePendingFor(txFrameInfo.mAddrs.mSource))
{
ackMode = kSendAckFramePending;
rxFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
@@ -849,7 +841,7 @@ void Core::ProcessRadio(Node &aNode)
const Mac::RxFrame &rxFrame =
static_cast<const Mac::RxFrame &>(static_cast<const Mac::Frame &>(aNode.mRadio.mTxFrame));
if (rxFrame.IsVersion2015())
if (txFrameInfo.mVersion == Mac::Frame::kVersion2015)
{
uint8_t ackIeData[OT_ACK_IE_MAX_SIZE];
uint8_t ackIeDataLength = 0;
@@ -864,14 +856,13 @@ void Core::ProcessRadio(Node &aNode)
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
{
uint8_t linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
uint8_t linkMetricsDataLen;
Mac::Address srcAddr;
uint8_t linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
uint8_t linkMetricsDataLen;
if (aNode.mRadio.mTxFrame.GetSrcAddr(srcAddr) == kErrorNone)
if (!txFrameInfo.mAddrs.mSource.IsNone())
{
linkMetricsDataLen = ackNode->mRadio.GenerateEnhAckProbingData(srcAddr, kDefaultRxLqi,
kDefaultRxRssi, linkMetricsData);
linkMetricsDataLen = ackNode->mRadio.GenerateEnhAckProbingData(
txFrameInfo.mAddrs.mSource, kDefaultRxLqi, kDefaultRxRssi, linkMetricsData);
if (linkMetricsDataLen > 0)
{
+9 -6
View File
@@ -427,19 +427,22 @@ void GrpcServer::ClearQueue(void)
GrpcServer::PacketInfo GrpcServer::GetPacketInfo(const Mac::Frame &aFrame)
{
PacketInfo info;
PacketInfo info;
Mac::Frame::ParseInfo frameInfo;
if (aFrame.IsAck())
IgnoreError(frameInfo.ParseFrom(aFrame, Mac::Frame::kParseFully));
if (frameInfo.mType == Mac::Frame::kTypeAck)
{
info.mProtocol = "IEEE 802.15.4 ACK";
info.mSummary = "ACK";
}
else if (aFrame.GetType() == Mac::Frame::kTypeData)
else if (frameInfo.mType == Mac::Frame::kTypeData)
{
info.mProtocol = "IEEE 802.15.4 Data";
info.mSummary = "Data";
}
else if (aFrame.IsMacCommand())
else if (frameInfo.mType == Mac::Frame::kTypeMacCmd)
{
info.mProtocol = "IEEE 802.15.4 Command";
info.mSummary = "Command";
@@ -450,11 +453,11 @@ GrpcServer::PacketInfo GrpcServer::GetPacketInfo(const Mac::Frame &aFrame)
info.mSummary = "Other";
}
if (aFrame.IsSequencePresent())
if (frameInfo.mIsSeqNumPresent)
{
char buf[32];
snprintf(buf, sizeof(buf), " (seq=%u)", aFrame.GetSequence());
snprintf(buf, sizeof(buf), " (seq=%u)", frameInfo.mSequenceNum);
info.mSummary += buf;
}
+135 -144
View File
@@ -290,11 +290,9 @@ void TestMacHeader(void)
uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
uint8_t offset;
Mac::TxFrame frame;
Mac::TxFrame::ParseInfo parseInfo;
Mac::TxFrame::BuildInfo buildInfo;
Mac::Address address;
Mac::PanId panId;
Mac::Frame::Lengths lengths;
Error error;
frame.mPsdu = psdu;
frame.mLength = 0;
@@ -369,50 +367,38 @@ void TestMacHeader(void)
VerifyOrQuit(lengths.mFooter == testCase.mFooterLength);
VerifyOrQuit(frame.GetLength() == testCase.mHeaderLength + testCase.mFooterLength);
VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeData);
VerifyOrQuit(!frame.IsAck());
VerifyOrQuit(frame.GetVersion() == testCase.mVersion);
VerifyOrQuit(frame.GetSecurityEnabled() == (testCase.mSecurity != kNoSec));
VerifyOrQuit(!frame.GetFramePending());
VerifyOrQuit(!frame.IsIePresent());
VerifyOrQuit(frame.GetAckRequest() == (testCase.mDstAddrType != kNoneAddr));
SuccessOrQuit(frame.GetSrcAddr(address));
VerifyOrQuit(CompareAddresses(address, buildInfo.mAddrs.mSource));
SuccessOrQuit(frame.GetDstAddr(address));
VerifyOrQuit(CompareAddresses(address, buildInfo.mAddrs.mDestination));
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseFully));
VerifyOrQuit(parseInfo.mType == Mac::Frame::kTypeData);
VerifyOrQuit(parseInfo.mVersion == testCase.mVersion);
VerifyOrQuit(parseInfo.mIsSecurityEnabled == (testCase.mSecurity != kNoSec));
VerifyOrQuit(!parseInfo.mIsFramePending);
VerifyOrQuit(!parseInfo.mIsIePresent);
VerifyOrQuit(parseInfo.mIsAckRequest == (testCase.mDstAddrType != kNoneAddr));
VerifyOrQuit(CompareAddresses(parseInfo.mAddrs.mSource, buildInfo.mAddrs.mSource));
VerifyOrQuit(CompareAddresses(parseInfo.mAddrs.mDestination, buildInfo.mAddrs.mDestination));
if (testCase.mDstPanIdMode == kNoPanId)
{
VerifyOrQuit(frame.GetDstPanId(panId) == kErrorNotFound);
VerifyOrQuit(!parseInfo.mPanIds.IsDestinationPresent());
}
else
{
SuccessOrQuit(frame.GetDstPanId(panId));
VerifyOrQuit(panId == buildInfo.mPanIds.GetDestination());
VerifyOrQuit(parseInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(parseInfo.mPanIds.GetDestination() == buildInfo.mPanIds.GetDestination());
VerifyOrQuit(buildInfo.mPanIds.IsDestinationPresent());
}
error = frame.GetSrcPanId(panId);
if (error != kErrorNotFound)
if (parseInfo.mPanIds.IsSourcePresent())
{
SuccessOrQuit(error);
VerifyOrQuit(panId == buildInfo.mPanIds.GetSource());
VerifyOrQuit(parseInfo.mPanIds.GetSource() == buildInfo.mPanIds.GetSource());
VerifyOrQuit(buildInfo.mPanIds.IsSourcePresent());
}
if (frame.GetSecurityEnabled())
if (parseInfo.mIsSecurityEnabled)
{
Mac::Frame::SecurityLevel security;
Mac::Frame::KeyIdMode keyIdMode;
SuccessOrQuit(frame.GetSecurityLevel(security));
VerifyOrQuit(security == testCase.mSecurity);
VerifyOrQuit(frame.HasSecurityLevel(testCase.mSecurity));
SuccessOrQuit(frame.GetKeyIdMode(keyIdMode));
VerifyOrQuit(keyIdMode == testCase.mKeyIdMode);
VerifyOrQuit(frame.HasKeyIdMode(testCase.mKeyIdMode));
VerifyOrQuit(parseInfo.mSecurityLevel == testCase.mSecurity);
VerifyOrQuit(parseInfo.mKeyIdMode == testCase.mKeyIdMode);
}
offset = snprintf(string, sizeof(string), "\nver:%s, src[addr:%s, pan:%s], dst[addr:%s, pan:%s], sec:%s",
@@ -422,12 +408,12 @@ void TestMacHeader(void)
if (!testCase.mSuppressSequence)
{
VerifyOrQuit(frame.IsSequencePresent());
offset += snprintf(string + offset, sizeof(string) - offset, ", seq:%u", frame.GetSequence());
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
offset += snprintf(string + offset, sizeof(string) - offset, ", seq:%u", parseInfo.mSequenceNum);
}
else
{
VerifyOrQuit(!frame.IsSequencePresent());
VerifyOrQuit(!parseInfo.mIsSeqNumPresent);
}
DumpBuffer(string, frame.GetPsdu(), frame.GetLength());
@@ -437,7 +423,8 @@ void TestMacHeader(void)
// versions (2003/2006).
frame.SetIePresent(true);
VerifyOrQuit(frame.IsIePresent() == (testCase.mVersion == Mac::Frame::kVersion2015));
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(parseInfo.mIsIePresent == (testCase.mVersion == Mac::Frame::kVersion2015));
}
}
@@ -667,9 +654,8 @@ void TestMacFrameApi(void)
0xb2, 0x6e, 0x81, 0x25, 0xc9, 0xdb, 0xac, 0x2b, 0x0a, 0x0d, 0x00, 0x00,
0x00, 0x00, 0x01, 0x04, 0xaf, 0x14, 0xce, 0xaa, 0x5a, 0xe5};
Mac::Frame frame;
Mac::PanId panId;
Mac::Address address;
Mac::Frame frame;
Mac::Frame::ParseInfo parseInfo;
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
uint8_t data_psdu1[] = {0x29, 0xee, 0x53, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a,
@@ -697,19 +683,18 @@ void TestMacFrameApi(void)
// FCS: 0x9bd2 (Correct)
frame.mPsdu = ack_psdu1;
frame.mLength = sizeof(ack_psdu1);
VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeAck);
VerifyOrQuit(!frame.GetSecurityEnabled());
VerifyOrQuit(!frame.GetFramePending());
VerifyOrQuit(!frame.GetAckRequest());
VerifyOrQuit(!frame.IsIePresent());
VerifyOrQuit(frame.GetDstPanId(panId) == kErrorNotFound);
SuccessOrQuit(frame.GetDstAddr(address));
VerifyOrQuit(address.IsNone());
VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
SuccessOrQuit(frame.GetSrcAddr(address));
VerifyOrQuit(address.IsNone());
VerifyOrQuit(frame.IsSequencePresent());
VerifyOrQuit(frame.GetSequence() == 94);
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseFully));
VerifyOrQuit(parseInfo.mType == Mac::Frame::kTypeAck);
VerifyOrQuit(!parseInfo.mIsSecurityEnabled);
VerifyOrQuit(!parseInfo.mIsFramePending);
VerifyOrQuit(!parseInfo.mIsAckRequest);
VerifyOrQuit(!parseInfo.mIsIePresent);
VerifyOrQuit(!parseInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(parseInfo.mAddrs.mDestination.IsNone());
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2006);
VerifyOrQuit(parseInfo.mAddrs.mSource.IsNone());
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
VerifyOrQuit(parseInfo.mSequenceNum == 94);
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
// IEEE 802.15.4-2015 Data
@@ -721,30 +706,29 @@ void TestMacFrameApi(void)
// Security Control Field: 0x0d
frame.mPsdu = data_psdu1;
frame.mLength = sizeof(data_psdu1);
VerifyOrQuit(frame.IsVersion2015());
SuccessOrQuit(frame.GetDstPanId(panId));
VerifyOrQuit(panId == 0xface);
SuccessOrQuit(frame.GetDstAddr(address));
VerifyOrQuit(address.IsExtended());
SuccessOrQuit(frame.GetSrcAddr(address));
VerifyOrQuit(!address.IsNone());
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2015);
VerifyOrQuit(parseInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(parseInfo.mPanIds.GetDestination() == 0xface);
VerifyOrQuit(parseInfo.mAddrs.mDestination.IsExtended());
VerifyOrQuit(!parseInfo.mAddrs.mSource.IsNone());
#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
// IEEE 802.15.4-2006 Mac Command
// Sequence Number: 133
// Command Identifier: Data Request (0x04)
uint8_t commandId;
frame.mPsdu = mac_cmd_psdu1;
frame.mLength = sizeof(mac_cmd_psdu1);
VerifyOrQuit(frame.IsSequencePresent());
VerifyOrQuit(frame.GetSequence() == 133);
VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeMacCmd);
SuccessOrQuit(frame.GetCommandId(commandId));
VerifyOrQuit(commandId == Mac::Frame::kMacCmdDataRequest);
VerifyOrQuit(!frame.IsIePresent());
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseFully));
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
VerifyOrQuit(parseInfo.mSequenceNum == 133);
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2006);
VerifyOrQuit(parseInfo.mType == Mac::Frame::kTypeMacCmd);
VerifyOrQuit(parseInfo.mCommandId == Mac::Frame::kMacCmdDataRequest);
VerifyOrQuit(!parseInfo.mIsIePresent);
frame.SetIePresent(true);
VerifyOrQuit(!frame.IsIePresent());
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(!parseInfo.mIsIePresent);
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
// IEEE 802.15.4-2015 Mac Command
@@ -755,54 +739,72 @@ void TestMacFrameApi(void)
// Command Identifier: Data Request (0x04)
frame.mPsdu = mac_cmd_psdu2;
frame.mLength = sizeof(mac_cmd_psdu2);
VerifyOrQuit(frame.IsSequencePresent());
VerifyOrQuit(frame.GetSequence() == 141);
VerifyOrQuit(frame.IsVersion2015());
VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeMacCmd);
SuccessOrQuit(frame.GetCommandId(commandId));
VerifyOrQuit(commandId == Mac::Frame::kMacCmdDataRequest);
printf("commandId:%d\n", commandId);
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseFully));
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
VerifyOrQuit(parseInfo.mSequenceNum == 141);
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2015);
VerifyOrQuit(parseInfo.mType == Mac::Frame::kTypeMacCmd);
VerifyOrQuit(parseInfo.mCommandId == Mac::Frame::kMacCmdDataRequest);
printf("commandId:%d\n", parseInfo.mCommandId);
#endif
{
uint8_t psdu2003WithBit8[] = {0x00, 0x01, 0x11};
uint8_t psdu2006WithBit8[] = {0x00, 0x11, 0x22};
uint8_t psdu2015WithBit8[] = {0x00, 0x21, 0x33};
uint8_t psdu2015NoBit8[] = {0x00, 0x20, 0x44};
uint8_t psdu2003WithBit8[] = {0x00, 0x01, 0x11, 0x00, 0x00};
uint8_t psdu2006WithBit8[] = {0x00, 0x11, 0x22, 0x00, 0x00};
uint8_t psdu2015WithBit8[] = {0x00, 0x21, 0x33, 0x00, 0x00};
uint8_t psdu2015NoBit8[] = {0x00, 0x20, 0x44, 0x00, 0x00};
frame.mPsdu = psdu2003WithBit8;
frame.mLength = sizeof(psdu2003WithBit8);
VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2003);
VerifyOrQuit(frame.IsSequencePresent());
VerifyOrQuit(frame.GetSequence() == 0x11);
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2003);
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
VerifyOrQuit(parseInfo.mSequenceNum == 0x11);
frame.mPsdu = psdu2006WithBit8;
frame.mLength = sizeof(psdu2006WithBit8);
VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
VerifyOrQuit(frame.IsSequencePresent());
VerifyOrQuit(frame.GetSequence() == 0x22);
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2006);
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
VerifyOrQuit(parseInfo.mSequenceNum == 0x22);
frame.mPsdu = psdu2015WithBit8;
frame.mLength = sizeof(psdu2015WithBit8);
VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2015);
VerifyOrQuit(!frame.IsSequencePresent());
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2015);
VerifyOrQuit(!parseInfo.mIsSeqNumPresent);
frame.mPsdu = psdu2015NoBit8;
frame.mLength = sizeof(psdu2015NoBit8);
VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2015);
VerifyOrQuit(frame.IsSequencePresent());
VerifyOrQuit(frame.GetSequence() == 0x44);
SuccessOrQuit(parseInfo.ParseFrom(frame, Mac::Frame::kParseAddrFields));
VerifyOrQuit(parseInfo.mVersion == Mac::Frame::kVersion2015);
VerifyOrQuit(parseInfo.mIsSeqNumPresent);
VerifyOrQuit(parseInfo.mSequenceNum == 0x44);
}
}
void TestMacFrameAckGeneration(void)
{
Mac::RxFrame receivedFrame;
Mac::TxFrame ackFrame;
uint8_t ackFrameBuffer[100];
Mac::PanId panId;
Mac::Address address;
Mac::RxFrame receivedFrame;
Mac::TxFrame ackFrame;
Mac::TxFrame::ParseInfo ackInfo;
uint8_t ackFrameBuffer[100];
uint8_t data_psdu1[] = {
0x61, 0xdc, 0xbd, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x02, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x6e, 0x16, 0x7f, 0x33, 0xf0, 0x4d, 0x4c, 0x4d, 0x4c, 0x8b, 0xf0, 0x00, 0x15, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2, 0x57, 0x9c, 0x31, 0xb3, 0x2a, 0xa1, 0x86, 0xba, 0x9a,
0xed, 0x5a, 0xb9, 0xa3, 0x59, 0x88, 0xeb, 0xbb, 0x0d, 0xc3, 0xed, 0xeb, 0x8a, 0x53, 0xa6, 0xed, 0xf7,
0xdd, 0x45, 0x6e, 0xf7, 0x9a, 0x17, 0xb4, 0xab, 0xc6, 0x75, 0x71, 0x46, 0x37, 0x93, 0x4a, 0x32, 0xb1,
0x21, 0x9f, 0x9d, 0xb3, 0x65, 0x27, 0xd5, 0xfc, 0x50, 0x16, 0x90, 0xd2, 0xd4,
};
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
uint8_t data_psdu2[] = {0x69, 0xa8, 0x8e, 0xce, 0xfa, 0x02, 0x24, 0x00, 0x24, 0x0d, 0x02,
0x00, 0x00, 0x00, 0x01, 0x6b, 0x64, 0x60, 0x08, 0x55, 0xb8, 0x10,
0x18, 0xc7, 0x40, 0x2e, 0xfb, 0xf3, 0xda, 0xf9, 0x4e, 0x58, 0x70};
uint8_t ie_data[] = {0x04, 0x0d, 0x21, 0x0c, 0x35, 0x0c};
const Mac::CslIe *csl;
#endif
ackFrame.mPsdu = ackFrameBuffer;
ackFrame.mLength = sizeof(ackFrameBuffer);
@@ -824,32 +826,24 @@ void TestMacFrameAckGeneration(void)
// Destination PAN: 0xface
// Destination: 16:6e:0a:00:00:00:00:01 (16:6e:0a:00:00:00:00:01)
// Extended Source: 16:6e:0a:00:00:00:00:02 (16:6e:0a:00:00:00:00:02)
uint8_t data_psdu1[] = {0x61, 0xdc, 0xbd, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x02,
0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x7f, 0x33, 0xf0, 0x4d, 0x4c, 0x4d, 0x4c,
0x8b, 0xf0, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2,
0x57, 0x9c, 0x31, 0xb3, 0x2a, 0xa1, 0x86, 0xba, 0x9a, 0xed, 0x5a, 0xb9, 0xa3, 0x59,
0x88, 0xeb, 0xbb, 0x0d, 0xc3, 0xed, 0xeb, 0x8a, 0x53, 0xa6, 0xed, 0xf7, 0xdd, 0x45,
0x6e, 0xf7, 0x9a, 0x17, 0xb4, 0xab, 0xc6, 0x75, 0x71, 0x46, 0x37, 0x93, 0x4a, 0x32,
0xb1, 0x21, 0x9f, 0x9d, 0xb3, 0x65, 0x27, 0xd5, 0xfc, 0x50, 0x16, 0x90, 0xd2, 0xd4};
receivedFrame.mPsdu = data_psdu1;
receivedFrame.mLength = sizeof(data_psdu1);
ackFrame.GenerateImmAck(receivedFrame, false);
VerifyOrQuit(ackFrame.mLength == Mac::Frame::GetImmAckLength());
VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
VerifyOrQuit(!ackFrame.GetSecurityEnabled());
VerifyOrQuit(!ackFrame.GetFramePending());
SuccessOrQuit(ackInfo.ParseFrom(ackFrame, Mac::Frame::kParseFully));
VerifyOrQuit(ackInfo.mType == Mac::Frame::kTypeAck);
VerifyOrQuit(!ackInfo.mIsSecurityEnabled);
VerifyOrQuit(!ackInfo.mIsFramePending);
VerifyOrQuit(!ackFrame.GetAckRequest());
VerifyOrQuit(!ackFrame.IsIePresent());
VerifyOrQuit(ackFrame.GetDstPanId(panId) == kErrorNotFound);
SuccessOrQuit(ackFrame.GetDstAddr(address));
VerifyOrQuit(address.IsNone());
SuccessOrQuit(ackFrame.GetSrcAddr(address));
VerifyOrQuit(address.IsNone());
VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2006);
VerifyOrQuit(ackFrame.IsSequencePresent());
VerifyOrQuit(ackFrame.GetSequence() == 189);
VerifyOrQuit(!ackInfo.mIsAckRequest);
VerifyOrQuit(!ackInfo.mIsIePresent);
VerifyOrQuit(!ackInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(ackInfo.mAddrs.mDestination.IsNone());
VerifyOrQuit(ackInfo.mAddrs.mSource.IsNone());
VerifyOrQuit(ackInfo.mVersion == Mac::Frame::kVersion2006);
VerifyOrQuit(ackInfo.mIsSeqNumPresent);
VerifyOrQuit(ackInfo.mSequenceNum == 189);
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
// Received Frame 2
@@ -887,36 +881,32 @@ void TestMacFrameAckGeneration(void)
// MIC: f94e5870
// [Key Number: 0]
// FCS: 0x8c40 (Correct)
uint8_t data_psdu2[] = {0x69, 0xa8, 0x8e, 0xce, 0xfa, 0x02, 0x24, 0x00, 0x24, 0x0d, 0x02,
0x00, 0x00, 0x00, 0x01, 0x6b, 0x64, 0x60, 0x08, 0x55, 0xb8, 0x10,
0x18, 0xc7, 0x40, 0x2e, 0xfb, 0xf3, 0xda, 0xf9, 0x4e, 0x58, 0x70};
receivedFrame.mPsdu = data_psdu2;
receivedFrame.mLength = sizeof(data_psdu2);
uint8_t ie_data[6] = {0x04, 0x0d, 0x21, 0x0c, 0x35, 0x0c};
Mac::CslIe *csl;
SuccessOrQuit(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)));
csl = ackFrame.Find<Mac::CslIe>();
VerifyOrQuit(ackFrame.mLength == 25);
VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
VerifyOrQuit(ackFrame.GetSecurityEnabled());
VerifyOrQuit(ackFrame.IsIePresent());
SuccessOrQuit(ackFrame.GetDstPanId(panId));
VerifyOrQuit(panId == 0xface);
SuccessOrQuit(ackFrame.GetDstAddr(address));
VerifyOrQuit(!address.IsNone());
SuccessOrQuit(ackFrame.GetSrcAddr(address));
VerifyOrQuit(address.IsNone());
VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2015);
VerifyOrQuit(ackFrame.IsSequencePresent());
VerifyOrQuit(ackFrame.GetSequence() == 142);
SuccessOrQuit(ackInfo.ParseFrom(ackFrame, Mac::Frame::kParseFully));
csl = ackInfo.Find<Mac::CslIe>();
VerifyOrQuit(csl != nullptr);
VerifyOrQuit(ackInfo.mType == Mac::Frame::kTypeAck);
VerifyOrQuit(ackInfo.mIsSecurityEnabled);
VerifyOrQuit(ackInfo.mIsIePresent);
VerifyOrQuit(ackInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(ackInfo.mPanIds.GetDestination() == 0xface);
VerifyOrQuit(!ackInfo.mAddrs.mDestination.IsNone());
VerifyOrQuit(ackInfo.mAddrs.mSource.IsNone());
VerifyOrQuit(ackInfo.mVersion == Mac::Frame::kVersion2015);
VerifyOrQuit(ackInfo.mIsSeqNumPresent);
VerifyOrQuit(ackInfo.mSequenceNum == 142);
VerifyOrQuit(csl->GetPeriod() == 3125 && csl->GetPhase() == 3105);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
ackFrame.UpdateCslIe(123, 456);
csl = ackFrame.Find<Mac::CslIe>();
SuccessOrQuit(ackInfo.ParseFrom(ackFrame, Mac::Frame::kParseFully));
csl = ackInfo.Find<Mac::CslIe>();
VerifyOrQuit(csl != nullptr);
VerifyOrQuit(csl->GetPeriod() == 123 && csl->GetPhase() == 456);
#endif
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
@@ -925,33 +915,34 @@ void TestMacFrameAckGeneration(void)
void TestMacFrameValidation(void)
{
// Simple IEEE 802.15.4-2003 Data Frame (FCF: 0x0001, DSN: 0x01, FCS: 2 bytes)
uint8_t psdu[] = {0x01, 0x00, 0x01, 0x00, 0x00};
Mac::Frame frame;
uint8_t psdu[] = {0x01, 0x00, 0x01, 0x00, 0x00};
Mac::Frame frame;
Mac::Frame::ParseInfo frameInfo;
frame.mPsdu = psdu;
frame.mLength = sizeof(psdu);
// Verify valid 2003 Data frame passes validation
SuccessOrQuit(frame.ValidatePsdu());
SuccessOrQuit(frameInfo.ParseFrom(frame, Mac::Frame::kParseFully));
// Verify unsupported frame types fail validation (Multipurpose = 5, Reserved = 4)
psdu[0] = (psdu[0] & ~0x07) | 5;
VerifyOrQuit(frame.ValidatePsdu() == kErrorParse);
VerifyOrQuit(frameInfo.ParseFrom(frame, Mac::Frame::kParseFully) == kErrorParse);
psdu[0] = (psdu[0] & ~0x07) | 4;
VerifyOrQuit(frame.ValidatePsdu() == kErrorParse);
VerifyOrQuit(frameInfo.ParseFrom(frame, Mac::Frame::kParseFully) == kErrorParse);
// Restore valid frame type (Data = 1)
psdu[0] = (psdu[0] & ~0x07) | 1;
SuccessOrQuit(frame.ValidatePsdu());
SuccessOrQuit(frameInfo.ParseFrom(frame, Mac::Frame::kParseFully));
// Verify unsupported frame version fails validation (Version 3 = 3 << 4 in high byte of FCF)
psdu[1] = (psdu[1] & ~0x30) | (3 << 4);
VerifyOrQuit(frame.ValidatePsdu() == kErrorParse);
VerifyOrQuit(frameInfo.ParseFrom(frame, Mac::Frame::kParseFully) == kErrorParse);
// Restore valid frame version (2003 = 0)
psdu[1] = (psdu[1] & ~0x30) | (0 << 4);
SuccessOrQuit(frame.ValidatePsdu());
SuccessOrQuit(frameInfo.ParseFrom(frame, Mac::Frame::kParseFully));
}
} // namespace ot