From 608ab60f03b2de712ea883d3fcaa017324d312a0 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 2 Sep 2026 17:33:40 -0700 Subject: [PATCH] [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()`, 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. --- examples/platforms/utils/mac_frame.cpp | 215 +++++--- src/core/diags/factory_diags.cpp | 9 +- src/core/mac/data_poll_handler.cpp | 62 ++- src/core/mac/data_poll_handler.hpp | 6 +- src/core/mac/data_poll_sender.cpp | 33 +- src/core/mac/data_poll_sender.hpp | 26 +- src/core/mac/link_raw.cpp | 13 +- src/core/mac/link_raw.hpp | 9 +- src/core/mac/mac.cpp | 532 ++++++++++--------- src/core/mac/mac.hpp | 38 +- src/core/mac/mac_frame.cpp | 482 ++++++----------- src/core/mac/mac_frame.hpp | 690 ++++++++++--------------- src/core/mac/mac_links.cpp | 18 +- src/core/mac/mac_links.hpp | 24 +- src/core/mac/scan_result.cpp | 28 +- src/core/mac/scan_result.hpp | 2 +- src/core/mac/sub_mac.cpp | 139 ++--- src/core/mac/sub_mac.hpp | 19 +- src/core/mac/sub_mac_callbacks.cpp | 30 +- src/core/mac/sub_mac_csl_receiver.cpp | 32 +- src/core/mac/wakeup_tx_scheduler.cpp | 29 +- src/core/radio/trel_link.cpp | 41 +- src/core/thread/csl_tx_scheduler.cpp | 36 +- src/core/thread/csl_tx_scheduler.hpp | 2 +- src/core/thread/indirect_sender.cpp | 26 +- src/core/thread/indirect_sender.hpp | 13 +- src/core/thread/mesh_forwarder.cpp | 49 +- src/core/thread/mesh_forwarder.hpp | 14 +- src/core/thread/radio_selector.cpp | 14 +- src/core/thread/radio_selector.hpp | 4 +- src/core/thread/thread_link_info.cpp | 44 +- src/core/thread/thread_link_info.hpp | 2 +- src/core/utils/otns.cpp | 24 +- src/lib/spinel/radio_spinel.cpp | 29 +- src/ncp/ncp_base_radio.cpp | 44 +- tests/nexus/platform/nexus_core.cpp | 43 +- tests/nexus/platform/nexus_grpc.cpp | 15 +- tests/unit/test_mac_frame.cpp | 279 +++++----- 38 files changed, 1474 insertions(+), 1641 deletions(-) diff --git a/examples/platforms/utils/mac_frame.cpp b/examples/platforms/utils/mac_frame.cpp index 5e84042d7..5445b1f5e 100644 --- a/examples/platforms/utils/mac_frame.cpp +++ b/examples/platforms/utils/mac_frame.cpp @@ -37,6 +37,51 @@ using namespace ot; +//--------------------------------------------------------------------------------------------------------------------- +// Helpers + +static inline Error ParseAddrFields(const otRadioFrame *aFrame, Mac::Frame::ParseInfo &aFrameInfo) +{ + return aFrameInfo.ParseFrom(*static_cast(aFrame), Mac::Frame::kParseAddrFields); +} + +static inline Error ParseSecurityHeader(const otRadioFrame *aFrame, Mac::TxFrame::ParseInfo &aFrameInfo) +{ + return aFrameInfo.ParseFrom(*static_cast(aFrame), Mac::Frame::kParseSecurityHeader); +} + +static inline Error ParseFully(const otRadioFrame *aFrame, Mac::Frame::ParseInfo &aFrameInfo) +{ + return aFrameInfo.ParseFrom(*static_cast(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(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(aExtAddress), rval = false); + VerifyOrExit(frameInfo.mAddrs.mDestination.GetExtended() == *static_cast(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(aFrame)->GetType() == Mac::Frame::kTypeAck; -} +bool otMacFrameIsAck(const otRadioFrame *aFrame) { return IsFrameOfType(aFrame, Mac::Frame::kTypeAck); } -bool otMacFrameIsData(const otRadioFrame *aFrame) -{ - return static_cast(aFrame)->GetType() == Mac::Frame::kTypeData; -} +bool otMacFrameIsData(const otRadioFrame *aFrame) { return IsFrameOfType(aFrame, Mac::Frame::kTypeData); } -bool otMacFrameIsCommand(const otRadioFrame *aFrame) -{ - return static_cast(aFrame)->GetType() == Mac::Frame::kTypeMacCmd; -} +bool otMacFrameIsCommand(const otRadioFrame *aFrame) { return IsFrameOfType(aFrame, Mac::Frame::kTypeMacCmd); } bool otMacFrameIsDataRequest(const otRadioFrame *aFrame) { - return static_cast(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(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(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(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(aFrame)->IsSequencePresent()) - { - *aSequence = static_cast(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(aFrame)->ProcessTransmitAesCcm(*static_cast(aExtAddress)); + Mac::TxFrame::ParseInfo frameInfo; + + IgnoreError(ParseFully(aFrame, frameInfo)); + frameInfo.ProcessTransmitAesCcm(AsCoreType(aExtAddress)); } bool otMacFrameIsVersion2015(const otRadioFrame *aFrame) { - return static_cast(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(aFrame)->UpdateCslIe(aCslPeriod, aCslPhase); } -#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE +#endif bool otMacFrameIsSecurityEnabled(otRadioFrame *aFrame) { - return static_cast(aFrame)->GetSecurityEnabled(); + Mac::Frame::ParseInfo frameInfo; + + IgnoreError(ParseAddrFields(aFrame, frameInfo)); + return frameInfo.mIsSecurityEnabled; } -bool otMacFrameIsKeyIdMode1(otRadioFrame *aFrame) -{ - return static_cast(aFrame)->HasKeyIdMode(Mac::Frame::kKeyIdMode1); -} +bool otMacFrameIsKeyIdMode1(otRadioFrame *aFrame) { return HasFrameKeyIdMode(aFrame, Mac::Frame::kKeyIdMode1); } -bool otMacFrameIsKeyIdMode2(otRadioFrame *aFrame) -{ - return static_cast(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(aFrame)->GetKeyIndex(keyIndex)); + SuccessOrExit(ParseSecurityHeader(aFrame, frameInfo)); + keyIndex = frameInfo.mKeyIndex; +exit: return keyIndex; } void otMacFrameSetKeyId(otRadioFrame *aFrame, uint8_t aKeyId) { - static_cast(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(aFrame)->GetFrameCounter(frameCounter)); + SuccessOrExit(ParseSecurityHeader(aFrame, frameInfo)); + frameCounter = frameInfo.mFrameCounter; +exit: return frameCounter; } void otMacFrameSetFrameCounter(otRadioFrame *aFrame, uint32_t aFrameCounter) { - static_cast(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(aFrame)->Has()) // CSL IE should be filled for every transmit attempt { - otMacFrameSetCslIe(aFrame, aRadioContext->mCslPeriod, - ComputeCslPhase(static_cast(aRadioTime), aRadioContext)); + Mac::Frame::ParseInfo frameInfo; + + if ((ParseFully(aFrame, frameInfo) == kErrorNone) && frameInfo.Has()) + { + otMacFrameSetCslIe(aFrame, aRadioContext->mCslPeriod, + ComputeCslPhase(static_cast(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(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(&aRadioContext->mCslExtAddress)); + VerifyOrExit(frameInfo.mAddrs.mSource.GetExtended() == AsCoreType(&aRadioContext->mCslExtAddress)); matches = true; break; diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index 9394cee58..9bd3627a4 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -967,12 +967,11 @@ exit: bool Diags::ShouldHandleReceivedFrame(const otRadioFrame &aFrame) const { - bool ret = false; - const Mac::RxFrame &frame = static_cast(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(aFrame), Mac::Frame::kParseAddrFields)); + VerifyOrExit(frameInfo.mAddrs.mDestination == mReceiveConfig.mFilterAddress); ret = true; exit: diff --git a/src/core/mac/data_poll_handler.cpp b/src/core/mac/data_poll_handler.cpp index f1781a356..3b1729c6c 100644 --- a/src/core/mac/data_poll_handler.cpp +++ b/src/core/mac/data_poll_handler.cpp @@ -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().IsDetached()); - SuccessOrExit(aFrame.GetSrcAddr(macSource)); - child = Get().FindChild(macSource, Child::kInStateValidOrRestoring); + child = Get().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().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().HandleSentFrameToChild(aFrame, mFrameContext, aError, aChild); + Get().HandleSentFrameToChild(aFrameInfo, mFrameContext, aError, aChild); exit: return; diff --git a/src/core/mac/data_poll_handler.hpp b/src/core/mac/data_poll_handler.hpp index b0355ab76..1ed8f512b 100644 --- a/src/core/mac/data_poll_handler.hpp +++ b/src/core/mac/data_poll_handler.hpp @@ -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); diff --git a/src/core/mac/data_poll_sender.cpp b/src/core/mac/data_poll_sender.cpp index 4c3382ac5..5b9bd05a4 100644 --- a/src/core/mac/data_poll_sender.cpp +++ b/src/core/mac/data_poll_sender.cpp @@ -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().UpdateNeighborOnSentFrame(aFrame, aError, macDest, /* aIsDataPoll */ true); + Get().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() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts; + maxRetxAttempts = aFrameInfo.Has() ? 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().GetParent().IsEnhancedKeepAliveSupported()); - VerifyOrExit(aFrame.GetSecurityEnabled()); + VerifyOrExit(aFrameInfo.mIsSecurityEnabled); #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (aFrame.IsARetransmission() && aFrame.Has()) + if (aFrameInfo.GetTxFrame()->IsARetransmission() && aFrameInfo.Has()) { // 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().PrepareMacHeaders(*frame, buildInfo); #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (frame->Has()) + if (buildInfo.mAppendCslIe) { // Disable frame retransmission when the data poll has CSL IE included aTxFrames.SetMaxFrameRetries(0); diff --git a/src/core/mac/data_poll_sender.hpp b/src/core/mac/data_poll_sender.hpp index 67536fc82..537843acb 100644 --- a/src/core/mac/data_poll_sender.hpp +++ b/src/core/mac/data_poll_sender.hpp @@ -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 /** diff --git a/src/core/mac/link_raw.cpp b/src/core/mac/link_raw.cpp index bd994e18d..945ff1f91 100644 --- a/src/core/mac/link_raw.cpp +++ b/src/core/mac/link_raw.cpp @@ -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()); } } diff --git a/src/core/mac/link_raw.hpp b/src/core/mac/link_raw.hpp index 7d077c261..3ed85bdf7 100644 --- a/src/core/mac/link_raw.hpp +++ b/src/core/mac/link_raw.hpp @@ -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; diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index cb7e0be9f..8fd81992a 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -276,11 +276,11 @@ void Mac::PerformActiveScan(void) } } -void Mac::ReportActiveScanResult(const RxFrame *aBeaconFrame) +void Mac::ReportActiveScanResult(const RxFrame::ParseInfo *aBeaconFrameInfo) { VerifyOrExit(mActiveScanCallback.IsSet()); - if (aBeaconFrame == nullptr) + if (aBeaconFrameInfo == nullptr) { mActiveScanCallback.Invoke(nullptr); } @@ -288,7 +288,7 @@ void Mac::ReportActiveScanResult(const RxFrame *aBeaconFrame) { ScanResult result; - SuccessOrExit(result.PopulateFromBeacon(aBeaconFrame)); + SuccessOrExit(result.PopulateFromBeacon(*aBeaconFrameInfo)); LogBeacon("Received"); mActiveScanCallback.Invoke(&result); @@ -804,25 +804,31 @@ bool Mac::IsJoinable(void) const } void Mac::ProcessTransmitSecurity(TxFrame &aFrame) +{ + TxFrame::ParseInfo frameInfo; + + IgnoreError(frameInfo.ParseFrom(aFrame, Frame::kParseFully)); + ProcessTransmitSecurity(frameInfo); +} + +void Mac::ProcessTransmitSecurity(TxFrame::ParseInfo &aFrameInfo) { KeyManager &keyManager = Get(); - Frame::KeyIdMode keyIdMode; const ExtAddress *extAddress = nullptr; - VerifyOrExit(aFrame.GetSecurityEnabled()); + VerifyOrExit(aFrameInfo.mParsedFully); + VerifyOrExit(aFrameInfo.mIsSecurityEnabled); - IgnoreError(aFrame.GetKeyIdMode(keyIdMode)); - - switch (keyIdMode) + switch (aFrameInfo.mKeyIdMode) { //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case Frame::kKeyIdMode0: - aFrame.SetAesKey(keyManager.GetKek()); + aFrameInfo.GetTxFrame()->SetAesKey(keyManager.GetKek()); extAddress = &GetExtAddress(); - if (!aFrame.IsHeaderUpdated()) + if (!aFrameInfo.GetTxFrame()->IsHeaderUpdated()) { - aFrame.SetFrameCounter(keyManager.GetKekFrameCounter()); + aFrameInfo.WriteFrameCounter(keyManager.GetKekFrameCounter()); keyManager.IncrementKekFrameCounter(); } @@ -833,7 +839,7 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame) #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeIeee802154) + if (aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeIeee802154) #endif { // For 15.4 radio link, the AES CCM* and frame security @@ -845,7 +851,7 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame) #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeTrel) + if (aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeTrel) #endif { const KeyMaterial *macKey; @@ -856,15 +862,15 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame) // not updated), we get a new frame counter and key id from the key // manager. - if (!aFrame.IsHeaderUpdated()) + if (!aFrameInfo.GetTxFrame()->IsHeaderUpdated()) { - mLinks.SetMacFrameCounter(aFrame); - aFrame.SetKeyIndex(DetermineKeyIndexFor(keyManager.GetCurrentKeySequence())); + mLinks.SetMacFrameCounter(aFrameInfo); + aFrameInfo.WriteKeyIndex(DetermineKeyIndexFor(keyManager.GetCurrentKeySequence())); } - macKey = DetermineMode1Key(aFrame); + macKey = DetermineMode1Key(aFrameInfo); VerifyOrExit(macKey != nullptr); - aFrame.SetAesKey(*macKey); + aFrameInfo.GetTxFrame()->SetAesKey(*macKey); extAddress = &GetExtAddress(); } #endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE @@ -872,12 +878,12 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case Frame::kKeyIdMode2: - aFrame.SetAesKey(mMode2KeyMaterial); + aFrameInfo.GetTxFrame()->SetAesKey(mMode2KeyMaterial); mKeyIdMode2FrameCounter++; - aFrame.SetFrameCounter(mKeyIdMode2FrameCounter); - aFrame.SetKeySource(kMode2KeySource); - aFrame.SetKeyIndex(0xff); + aFrameInfo.WriteFrameCounter(mKeyIdMode2FrameCounter); + aFrameInfo.WriteKeySource(kMode2KeySource); + aFrameInfo.WriteKeyIndex(0xff); extAddress = &AsCoreType(&kMode2ExtAddress); break; @@ -887,15 +893,15 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame) #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE // Transmit security will be processed after time IE content is updated. - VerifyOrExit(!aFrame.Has()); + VerifyOrExit(!aFrameInfo.Has()); #endif #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE // Transmit security will be processed after time IE content is updated. - VerifyOrExit(!aFrame.IsCslIePresent()); + VerifyOrExit(!aFrameInfo.GetTxFrame()->IsCslIePresent()); #endif - aFrame.ProcessTransmitAesCcm(*extAddress); + aFrameInfo.ProcessTransmitAesCcm(*extAddress); exit: return; @@ -903,9 +909,11 @@ exit: void Mac::BeginTransmit(void) { - TxFrame *frame = nullptr; - TxFrames &txFrames = mLinks.InitTxFrames(); - Address dstAddr; + TxFrame *frame = nullptr; + TxFrames &txFrames = mLinks.InitTxFrames(); + bool shouldWriteSeqNum = true; + uint8_t seqNum = 0; + TxFrame::ParseInfo frameInfo; #if OPENTHREAD_CONFIG_MULTI_RADIO mTxPendingRadioLinks.Clear(); @@ -921,18 +929,18 @@ void Mac::BeginTransmit(void) frame = PrepareBeaconRequest(txFrames); VerifyOrExit(frame != nullptr); frame->SetChannel(mScanChannel); - frame->SetSequence(0); frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect); frame->SetMaxFrameRetries(mMaxFrameRetriesDirect); + seqNum = 0; break; case kOperationTransmitBeacon: frame = PrepareBeacon(txFrames); VerifyOrExit(frame != nullptr); frame->SetChannel(mRadioChannel); - frame->SetSequence(mBeaconSequence++); frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect); frame->SetMaxFrameRetries(mMaxFrameRetriesDirect); + seqNum = mBeaconSequence++; break; case kOperationTransmitPoll: @@ -941,7 +949,7 @@ void Mac::BeginTransmit(void) txFrames.SetMaxFrameRetries(mMaxFrameRetriesDirect); frame = Get().PrepareDataRequest(txFrames); VerifyOrExit(frame != nullptr); - frame->SetSequence(mDataSequence++); + seqNum = mDataSequence++; break; case kOperationTransmitDataDirect: @@ -953,7 +961,7 @@ void Mac::BeginTransmit(void) txFrames.SetMaxFrameRetries(mMaxFrameRetriesDirect); frame = Get().HandleFrameRequest(txFrames); VerifyOrExit(frame != nullptr); - frame->SetSequence(mDataSequence++); + seqNum = mDataSequence++; break; #if OPENTHREAD_FTD @@ -963,12 +971,9 @@ void Mac::BeginTransmit(void) txFrames.SetMaxFrameRetries(mMaxFrameRetriesIndirect); frame = Get().HandleFrameRequest(txFrames); VerifyOrExit(frame != nullptr); - // If the frame is marked as retransmission, then data sequence number is already set. - if (!frame->IsARetransmission()) - { - frame->SetSequence(mDataSequence++); - } + shouldWriteSeqNum = !frame->IsARetransmission(); + seqNum = shouldWriteSeqNum ? mDataSequence++ : 0; break; #endif @@ -978,13 +983,9 @@ void Mac::BeginTransmit(void) txFrames.SetMaxFrameRetries(kMaxFrameRetriesCsl); frame = Get().HandleFrameRequest(txFrames); VerifyOrExit(frame != nullptr); - // If the frame is marked as retransmission, then data sequence number is already set. - if (!frame->IsARetransmission()) - { - frame->SetSequence(mDataSequence++); - } - + shouldWriteSeqNum = !frame->IsARetransmission(); + seqNum = shouldWriteSeqNum ? mDataSequence++ : 0; break; #endif @@ -995,6 +996,7 @@ void Mac::BeginTransmit(void) VerifyOrExit(frame != nullptr); frame->SetChannel(mWakeupChannel); frame->SetRxChannelAfterTxDone(mRadioChannel); + shouldWriteSeqNum = false; break; #endif @@ -1002,9 +1004,17 @@ void Mac::BeginTransmit(void) OT_ASSERT(false); } + VerifyOrExit(frame != nullptr); + IgnoreError(frameInfo.ParseFrom(*frame, Frame::kParseFully)); + + if (shouldWriteSeqNum) + { + frameInfo.WriteSequenceNum(seqNum); + } + #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE { - TimeIe *timeIe = frame->Find(); + TimeIe *timeIe = frameInfo.Find(); if (timeIe == nullptr) { @@ -1021,7 +1031,7 @@ void Mac::BeginTransmit(void) } #endif - if (!frame->IsSecurityProcessed()) + if (!frameInfo.GetTxFrame()->IsSecurityProcessed()) { #if OPENTHREAD_CONFIG_MULTI_RADIO // Go through all selected radio link types for this tx and @@ -1053,7 +1063,7 @@ void Mac::BeginTransmit(void) } } #else - ProcessTransmitSecurity(*frame); + ProcessTransmitSecurity(frameInfo); #endif } @@ -1078,7 +1088,7 @@ void Mac::BeginTransmit(void) #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS if (!mRxOnWhenIdle && !mPromiscuous) { - mShouldDelaySleep = frame->GetFramePending(); + mShouldDelaySleep = frameInfo.mIsFramePending; LogDebg("Delay sleep for pending tx"); } #endif @@ -1093,15 +1103,7 @@ exit: if (frame == nullptr) { - // If the frame could not be prepared and the tx is being - // aborted, we set the frame length to zero to mark it as empty. - // The empty frame helps differentiate between an aborted tx due - // to OpenThread itself not being able to prepare the frame, versus - // the radio platform aborting the tx operation. - - frame = &txFrames.GetBroadcastTxFrame(); - frame->SetLength(0); - HandleTransmitDone(*frame, nullptr, kErrorAbort); + HandleTxFramePrepFailed(txFrames); } } @@ -1130,20 +1132,23 @@ void Mac::RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel) } } -void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) +void Mac::RecordFrameTransmitStatus(const TxFrame::ParseInfo &aFrameInfo, + Error aError, + uint8_t aRetryCount, + bool aWillRetx) { - bool ackRequested = aFrame.GetAckRequest(); - Address dstAddr; - Neighbor *neighbor; + Neighbor *neighbor = nullptr; - VerifyOrExit(!aFrame.IsEmpty()); + VerifyOrExit(aFrameInfo.mParsedFully); - IgnoreError(aFrame.GetDstAddr(dstAddr)); - neighbor = Get().FindNeighbor(dstAddr); + if (!aFrameInfo.mAddrs.mDestination.IsNone()) + { + neighbor = Get().FindNeighbor(aFrameInfo.mAddrs.mDestination); + } // Record frame transmission success/failure state (for a neighbor). - if ((neighbor != nullptr) && ackRequested) + if ((neighbor != nullptr) && aFrameInfo.mIsAckRequest) { bool frameTxSuccess = true; @@ -1171,8 +1176,8 @@ void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t if (aError != kErrorNone) { - LogFrameTxFailure(aFrame, aError, aRetryCount, aWillRetx); - DumpDebg("TX ERR", aFrame.GetPsdu(), 16); + LogFrameTxFailure(aFrameInfo, aError, aRetryCount, aWillRetx); + DumpDebg("TX ERR", aFrameInfo.GetTxFrame()->GetPsdu(), 16); if (aWillRetx) { @@ -1200,7 +1205,7 @@ void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t mCounters.mTxErrBusyChannel++; } - if (ackRequested) + if (aFrameInfo.mIsAckRequest) { mCounters.mTxAckRequested++; @@ -1214,7 +1219,7 @@ void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t mCounters.mTxNoAckRequested++; } - if (dstAddr.IsBroadcast()) + if (aFrameInfo.mAddrs.mDestination.IsBroadcast()) { mCounters.mTxBroadcast++; } @@ -1229,7 +1234,7 @@ exit: #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE -Error Mac::ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError) +Error Mac::ProcessTxDone(TxFrame::ParseInfo &aFrameInfo, RxFrame::ParseInfo &aAckFrameInfo, Error &aError) { // Process post-transmission actions on IEEE 802.15.4 link // (handling broadcast retransmissions and ACK processing). @@ -1241,29 +1246,27 @@ Error Mac::ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError) // May update `aError` (e.g., setting it to `kErrorNoAck` if Enh-ACK // security or MAC filter checks fail). - Error error = kErrorNone; - Address dstAddr; - Neighbor *neighbor; + Error error = kErrorNone; + Neighbor *neighbor = nullptr; - VerifyOrExit(!aFrame.IsEmpty()); + VerifyOrExit(aFrameInfo.GetTxFrame() != nullptr); + VerifyOrExit(!aFrameInfo.GetTxFrame()->IsEmpty()); #if OPENTHREAD_CONFIG_MULTI_RADIO - VerifyOrExit(aFrame.GetRadioType() == Radio::kTypeIeee802154); + VerifyOrExit(aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeIeee802154); // Set the radio type on `AckFrame`, so we can determine the // proper (15.4 based) key in `ProcessEnhAckSecurity()`. - if (aAckFrame != nullptr) + if (aAckFrameInfo.GetRxFrame() != nullptr) { - aAckFrame->SetRadioType(Radio::kTypeIeee802154); + aAckFrameInfo.GetRxFrame()->SetRadioType(Radio::kTypeIeee802154); } #endif - IgnoreError(aFrame.GetDstAddr(dstAddr)); - // Determine whether to re-transmit a broadcast frame. - if (dstAddr.IsBroadcast()) + if (aFrameInfo.mAddrs.mDestination.IsBroadcast()) { mBroadcastTransmitCount++; @@ -1274,7 +1277,7 @@ Error Mac::ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError) Radio::Types radioTypes; radioTypes.Add(Radio::kTypeIeee802154); - mLinks.Send(aFrame, radioTypes); + mLinks.Send(*aFrameInfo.GetTxFrame(), radioTypes); } #else mLinks.Send(); @@ -1289,14 +1292,19 @@ Error Mac::ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError) // (verifying MAC filter, Enh-ACK security, and updating // neighbor link info and CSL). - VerifyOrExit(aFrame.GetAckRequest() && (aAckFrame != nullptr)); + VerifyOrExit(aFrameInfo.mIsAckRequest); + VerifyOrExit(aAckFrameInfo.GetRxFrame() != nullptr); SuccessOrExit(aError); - neighbor = Get().FindNeighbor(dstAddr); + if (!aFrameInfo.mAddrs.mDestination.IsNone()) + { + neighbor = Get().FindNeighbor(aFrameInfo.mAddrs.mDestination); + } #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE - if ((neighbor != nullptr) && mFilter.ApplyToRxFrame(*aAckFrame, neighbor->GetExtAddress(), neighbor) != kErrorNone) + if ((neighbor != nullptr) && + mFilter.ApplyToRxFrame(*aAckFrameInfo.GetRxFrame(), neighbor->GetExtAddress(), neighbor) != kErrorNone) { aError = kErrorNoAck; ExitNow(); @@ -1304,7 +1312,7 @@ Error Mac::ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError) #endif #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 - if (ProcessEnhAckSecurity(aFrame, *aAckFrame) != kErrorNone) + if (ProcessEnhAckSecurity(aFrameInfo, aAckFrameInfo) != kErrorNone) { aError = kErrorNoAck; ExitNow(); @@ -1313,16 +1321,16 @@ Error Mac::ProcessTxDone(TxFrame &aFrame, RxFrame *aAckFrame, Error &aError) VerifyOrExit(neighbor != nullptr); - UpdateNeighborLinkInfo(*neighbor, *aAckFrame); + UpdateNeighborLinkInfo(*neighbor, aAckFrameInfo); #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE - ProcessEnhAckProbing(*aAckFrame, *neighbor); + ProcessEnhAckProbing(aAckFrameInfo, *neighbor); #endif #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE - ProcessCsl(*aAckFrame, dstAddr); + ProcessCsl(aAckFrameInfo, aFrameInfo.mAddrs.mDestination); #endif #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (!mRxOnWhenIdle && aFrame.Has()) + if (!mRxOnWhenIdle && aFrameInfo.mParsedFully && aFrameInfo.Has()) { Get().ResetKeepAliveTimer(); } @@ -1336,7 +1344,7 @@ exit: #if OPENTHREAD_CONFIG_MULTI_RADIO -Error Mac::ProcessMultiRadioTxDone(TxFrame &aFrame, Error &aError) +Error Mac::ProcessMultiRadioTxDone(TxFrame::ParseInfo &aFrameInfo, Error &aError) { // Process post-transmission actions under multi-radio config // (updating radio selector and tracking transmission across @@ -1351,12 +1359,13 @@ Error Mac::ProcessMultiRadioTxDone(TxFrame &aFrame, Error &aError) Radio::Type radio; Radio::Types requiredRadios; - VerifyOrExit(!aFrame.IsEmpty()); + VerifyOrExit(aFrameInfo.GetTxFrame() != nullptr); + VerifyOrExit(!aFrameInfo.GetTxFrame()->IsEmpty()); - radio = aFrame.GetRadioType(); + radio = aFrameInfo.GetTxFrame()->GetRadioType(); requiredRadios = mLinks.GetTxFramesRequiredRadioTypes(); - Get().UpdateOnSendDone(aFrame, aError); + Get().UpdateOnSendDone(aFrameInfo, aError); if (requiredRadios.IsEmpty()) { @@ -1403,14 +1412,38 @@ exit: #endif // OPENTHREAD_CONFIG_MULTI_RADIO -void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError) +void Mac::HandleTxFramePrepFailed(TxFrames &aTxFrames) { + // If the frame could not be prepared, TX done is called with + // an aborted error. We set the frame length to zero to mark it as empty. + // The empty frame helps differentiate between an aborted tx due + // to OpenThread itself not being able to prepare the frame, versus + // the radio platform aborting the tx operation. + + TxFrame &frame = aTxFrames.GetBroadcastTxFrame(); + TxFrame::ParseInfo frameInfo; + + frame.SetLength(0); + frameInfo.mFrame = &frame; + + HandleTransmitDone(frameInfo, nullptr, kErrorAbort); +} + +void Mac::HandleTransmitDone(TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame, Error aError) +{ + RxFrame::ParseInfo ackFrameInfo; + + if (aAckFrame != nullptr) + { + IgnoreError(ackFrameInfo.ParseFrom(*aAckFrame, Frame::kParseFully)); + } + #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE - SuccessOrExit(ProcessTxDone(aFrame, aAckFrame, aError)); + SuccessOrExit(ProcessTxDone(aFrameInfo, ackFrameInfo, aError)); #endif #if OPENTHREAD_CONFIG_MULTI_RADIO - SuccessOrExit(ProcessMultiRadioTxDone(aFrame, aError)); + SuccessOrExit(ProcessMultiRadioTxDone(aFrameInfo, aError)); #endif // Determine next action based on current operation. @@ -1429,23 +1462,21 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError) break; case kOperationTransmitPoll: - OT_ASSERT(aFrame.IsEmpty() || aFrame.GetAckRequest()); + OT_ASSERT(aFrameInfo.GetTxFrame()->IsEmpty() || aFrameInfo.mIsAckRequest); if ((aError == kErrorNone) && (aAckFrame != nullptr)) { - bool framePending = aAckFrame->GetFramePending(); - - if (IsEnabled() && framePending) + if (IsEnabled() && ackFrameInfo.mIsFramePending) { StartOperation(kOperationWaitingForData); } - LogInfo("Sent data poll, fp:%s", ToYesNo(framePending)); + LogInfo("Sent data poll, fp:%s", ToYesNo(ackFrameInfo.mIsFramePending)); } mCounters.mTxDataPoll++; FinishOperation(); - Get().HandlePollSent(aFrame, aError); + Get().HandlePollSent(aFrameInfo, aError); PerformNextOperation(); break; @@ -1463,11 +1494,11 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError) } #endif - DumpDebg("TX", aFrame.GetPsdu(), aFrame.GetLength()); + DumpDebg("TX", aFrameInfo.GetTxFrame()->GetPsdu(), aFrameInfo.GetTxFrame()->GetLength()); FinishOperation(); - Get().HandleSentFrame(aFrame, aError); + Get().HandleSentFrame(aFrameInfo, aError); #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 - Get().ProcessTxDone(aFrame, aAckFrame, aError); + Get().ProcessTxDone(aFrameInfo, ackFrameInfo, aError); #endif PerformNextOperation(); break; @@ -1476,9 +1507,9 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError) case kOperationTransmitDataCsl: mCounters.mTxData++; - DumpDebg("TX", aFrame.GetPsdu(), aFrame.GetLength()); + DumpDebg("TX", aFrameInfo.GetTxFrame()->GetPsdu(), aFrameInfo.GetTxFrame()->GetLength()); FinishOperation(); - Get().HandleSentFrame(aFrame, aError); + Get().HandleSentFrame(aFrameInfo, aError); PerformNextOperation(); break; @@ -1499,9 +1530,9 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError) } #endif - DumpDebg("TX", aFrame.GetPsdu(), aFrame.GetLength()); + DumpDebg("TX", aFrameInfo.GetTxFrame()->GetPsdu(), aFrameInfo.GetTxFrame()->GetLength()); FinishOperation(); - Get().HandleSentFrame(aFrame, aError); + Get().HandleSentFrame(aFrameInfo, aError); PerformNextOperation(); break; #endif // OPENTHREAD_FTD @@ -1563,36 +1594,34 @@ void Mac::HandleTimer(void) } } -const KeyMaterial *Mac::DetermineMode1Key(const Frame &aFrame) const +const KeyMaterial *Mac::DetermineMode1Key(const Frame::ParseInfo &aFrameInfo) const { uint32_t keySequence; - return DetermineMode1KeyAndSequence(aFrame, keySequence); + return DetermineMode1KeyAndSequence(aFrameInfo, keySequence); } -const KeyMaterial *Mac::DetermineMode1KeyAndSequence(const Frame &aFrame, uint32_t &aKeySequence) const +const KeyMaterial *Mac::DetermineMode1KeyAndSequence(const Frame::ParseInfo &aFrameInfo, uint32_t &aKeySequence) const { - // Determines the MAC key and key sequence for given `aFrame`. + // Determines the MAC key and key sequence for given `aFrameInfo`. // The caller MUST already ensure that the frame's Key ID Mode // is Mode 1. const KeyMaterial *key = nullptr; - uint8_t keyIndex; KeyTrio::Type keyType; - SuccessOrExit(aFrame.GetKeyIndex(keyIndex)); aKeySequence = Get().GetCurrentKeySequence(); - if (keyIndex == DetermineKeyIndexFor(aKeySequence)) + if (aFrameInfo.mKeyIndex == DetermineKeyIndexFor(aKeySequence)) { keyType = KeyTrio::kCur; } - else if (keyIndex == DetermineKeyIndexFor(aKeySequence + 1)) + else if (aFrameInfo.mKeyIndex == DetermineKeyIndexFor(aKeySequence + 1)) { aKeySequence++; keyType = KeyTrio::kNext; } - else if (keyIndex == DetermineKeyIndexFor(aKeySequence - 1)) + else if (aFrameInfo.mKeyIndex == DetermineKeyIndexFor(aKeySequence - 1)) { aKeySequence--; keyType = KeyTrio::kPrev; @@ -1604,7 +1633,7 @@ const KeyMaterial *Mac::DetermineMode1KeyAndSequence(const Frame &aFrame, uint32 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeIeee802154) + if (aFrameInfo.mFrame->GetRadioType() == Radio::kTypeIeee802154) #endif { ExitNow(key = &Get().GetMacKey(keyType)); @@ -1613,7 +1642,7 @@ const KeyMaterial *Mac::DetermineMode1KeyAndSequence(const Frame &aFrame, uint32 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeTrel) + if (aFrameInfo.mFrame->GetRadioType() == Radio::kTypeTrel) #endif { switch (keyType) @@ -1635,26 +1664,21 @@ exit: return key; } -Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neighbor *aNeighbor) +Error Mac::ProcessReceiveSecurity(RxFrame::ParseInfo &aFrameInfo, const Address &aSrcAddr, Neighbor *aNeighbor) { - KeyManager &keyManager = Get(); - Error error = kErrorSecurity; - Frame::KeyIdMode keyIdMode; - uint32_t frameCounter; + KeyManager &keyManager = Get(); + Error error = kErrorSecurity; uint32_t keySequence = 0; const KeyMaterial *macKey; const ExtAddress *extAddress; - VerifyOrExit(aFrame.GetSecurityEnabled(), error = kErrorNone); + VerifyOrExit(aFrameInfo.mIsSecurityEnabled, error = kErrorNone); - VerifyOrExit(aFrame.HasSecurityLevel(Frame::kSecurityEncMic32)); + VerifyOrExit(aFrameInfo.mSecurityLevel == Frame::kSecurityEncMic32); - IgnoreError(aFrame.GetFrameCounter(frameCounter)); - LogDebg("Rx security - frame counter %lu", ToUlong(frameCounter)); + LogDebg("Rx security - frame counter %lu", ToUlong(aFrameInfo.mFrameCounter)); - SuccessOrExit(aFrame.GetKeyIdMode(keyIdMode)); - - switch (keyIdMode) + switch (aFrameInfo.mKeyIdMode) { case Frame::kKeyIdMode0: VerifyOrExit(keyManager.IsKekSet()); @@ -1666,7 +1690,7 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig case Frame::kKeyIdMode1: VerifyOrExit(aNeighbor != nullptr); - macKey = DetermineMode1KeyAndSequence(aFrame, keySequence); + macKey = DetermineMode1KeyAndSequence(aFrameInfo, keySequence); VerifyOrExit(macKey != nullptr); // If the frame is from a neighbor not in valid state (e.g., it is from a child being @@ -1683,15 +1707,15 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig uint32_t neighborFrameCounter; #if OPENTHREAD_CONFIG_MULTI_RADIO - neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get(aFrame.GetRadioType()); + neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get(aFrameInfo.GetRxFrame()->GetRadioType()); #else neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get(); #endif // If frame counter is one off, then frame is a duplicate. - VerifyOrExit((frameCounter + 1) != neighborFrameCounter, error = kErrorDuplicated); + VerifyOrExit((aFrameInfo.mFrameCounter + 1) != neighborFrameCounter, error = kErrorDuplicated); - VerifyOrExit(frameCounter >= neighborFrameCounter); + VerifyOrExit(aFrameInfo.mFrameCounter >= neighborFrameCounter); } } @@ -1709,9 +1733,9 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig ExitNow(); } - SuccessOrExit(aFrame.ProcessReceiveAesCcm(*extAddress, *macKey)); + SuccessOrExit(aFrameInfo.ProcessReceiveAesCcm(*extAddress, *macKey)); - if ((keyIdMode == Frame::kKeyIdMode1) && aNeighbor->IsStateValid()) + if ((aFrameInfo.mKeyIdMode == Frame::kKeyIdMode1) && (aNeighbor != nullptr) && aNeighbor->IsStateValid()) { if (aNeighbor->GetKeySequence() != keySequence) { @@ -1721,19 +1745,19 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig } #if OPENTHREAD_CONFIG_MULTI_RADIO - aNeighbor->GetLinkFrameCounters().Set(aFrame.GetRadioType(), frameCounter + 1); + aNeighbor->GetLinkFrameCounters().Set(aFrameInfo.mFrame->GetRadioType(), aFrameInfo.mFrameCounter + 1); #else - aNeighbor->GetLinkFrameCounters().Set(frameCounter + 1); + aNeighbor->GetLinkFrameCounters().Set(aFrameInfo.mFrameCounter + 1); #endif #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeIeee802154) + if (aFrameInfo.mFrame->GetRadioType() == Radio::kTypeIeee802154) #endif { - if ((frameCounter + 1) > aNeighbor->GetLinkAckFrameCounter()) + if ((aFrameInfo.mFrameCounter + 1) > aNeighbor->GetLinkAckFrameCounter()) { - aNeighbor->SetLinkAckFrameCounter(frameCounter + 1); + aNeighbor->SetLinkAckFrameCounter(aFrameInfo.mFrameCounter + 1); } } #endif @@ -1751,60 +1775,48 @@ exit: } #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 -Error Mac::ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame) +Error Mac::ProcessEnhAckSecurity(TxFrame::ParseInfo &aTxFrameInfo, RxFrame::ParseInfo &aAckFrameInfo) { - Error error = kErrorSecurity; - uint8_t txKeyIndex; - uint8_t ackKeyIndex; - uint32_t frameCounter; - Address srcAddr; - Address dstAddr; + Error error = kErrorSecurity; Neighbor *neighbor = nullptr; const KeyMaterial *macKey; + Address srcAddr; - if (!aAckFrame.GetSecurityEnabled()) + VerifyOrExit(aTxFrameInfo.mParsedFully, error = kErrorParse); + VerifyOrExit(aAckFrameInfo.mParsedFully, error = kErrorParse); + + if (!aAckFrameInfo.mIsSecurityEnabled) { // Reject an unsecured ACK carrying IEs in response to a secured 2015 frame. - if (aTxFrame.GetSecurityEnabled() && aTxFrame.IsVersion2015() && aAckFrame.IsIePresent()) + if (aTxFrameInfo.mIsSecurityEnabled && (aTxFrameInfo.mVersion == Frame::kVersion2015) && + aAckFrameInfo.mIsIePresent) { - ExitNow(error = kErrorSecurity); + ExitNow(); } ExitNow(error = kErrorNone); } - VerifyOrExit(aAckFrame.IsVersion2015()); + VerifyOrExit(aAckFrameInfo.mVersion == Frame::kVersion2015); + VerifyOrExit(aAckFrameInfo.mSecurityLevel == Frame::kSecurityEncMic32); + VerifyOrExit(aAckFrameInfo.mKeyIdMode == Frame::kKeyIdMode1); - SuccessOrExit(aAckFrame.ValidatePsdu()); + VerifyOrExit(aTxFrameInfo.mIsSecurityEnabled); + VerifyOrExit(aTxFrameInfo.mKeyIndex == aAckFrameInfo.mKeyIndex); - VerifyOrExit(aAckFrame.HasSecurityLevel(Frame::kSecurityEncMic32)); + LogDebg("Rx security - Ack frame counter %lu", ToUlong(aAckFrameInfo.mFrameCounter)); - VerifyOrExit(aAckFrame.HasKeyIdMode(Frame::kKeyIdMode1)); - - IgnoreError(aTxFrame.GetKeyIndex(txKeyIndex)); - IgnoreError(aAckFrame.GetKeyIndex(ackKeyIndex)); - - VerifyOrExit(txKeyIndex == ackKeyIndex); - - IgnoreError(aAckFrame.GetFrameCounter(frameCounter)); - LogDebg("Rx security - Ack frame counter %lu", ToUlong(frameCounter)); - - IgnoreError(aAckFrame.GetSrcAddr(srcAddr)); + srcAddr = aAckFrameInfo.mAddrs.mSource; if (!srcAddr.IsNone()) { neighbor = Get().FindNeighbor(srcAddr); } - else + else if (!aTxFrameInfo.mAddrs.mDestination.IsNone()) { - IgnoreError(aTxFrame.GetDstAddr(dstAddr)); - - if (!dstAddr.IsNone()) - { - // Get neighbor from destination address of transmitted frame - neighbor = Get().FindNeighbor(dstAddr); - } + // Get neighbor from destination address of transmitted frame + neighbor = Get().FindNeighbor(aTxFrameInfo.mAddrs.mDestination); } if (!srcAddr.IsExtended() && neighbor != nullptr) @@ -1814,20 +1826,19 @@ Error Mac::ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame) VerifyOrExit(srcAddr.IsExtended() && neighbor != nullptr); - macKey = DetermineMode1Key(aAckFrame); + macKey = DetermineMode1Key(aAckFrameInfo); VerifyOrExit(macKey != nullptr); if (neighbor->IsStateValid()) { - VerifyOrExit(frameCounter >= neighbor->GetLinkAckFrameCounter()); + VerifyOrExit(aAckFrameInfo.mFrameCounter >= neighbor->GetLinkAckFrameCounter()); } - error = aAckFrame.ProcessReceiveAesCcm(srcAddr.GetExtended(), *macKey); - SuccessOrExit(error); + SuccessOrExit(error = aAckFrameInfo.ProcessReceiveAesCcm(srcAddr.GetExtended(), *macKey)); if (neighbor->IsStateValid()) { - neighbor->SetLinkAckFrameCounter(frameCounter + 1); + neighbor->SetLinkAckFrameCounter(aAckFrameInfo.mFrameCounter + 1); } exit: @@ -1869,47 +1880,55 @@ exit: void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) { - Error error = aError; - Neighbor *neighbor = nullptr; - Address srcAddr; - Address dstAddr; - PanId panId; + Error error = aError; + Neighbor *neighbor = nullptr; + RxFrame::ParseInfo frameInfo; + Address srcAddr; mCounters.mRxTotal++; + frameInfo.mFrame = aFrame; + SuccessOrExit(error); VerifyOrExit(aFrame != nullptr, error = kErrorNoFrameReceived); VerifyOrExit(IsEnabled(), error = kErrorInvalidState); // Ensure we have a valid frame before attempting to read any contents of // the buffer received from the radio. - SuccessOrExit(error = aFrame->ValidatePsdu()); - - IgnoreError(aFrame->GetSrcAddr(srcAddr)); - IgnoreError(aFrame->GetDstAddr(dstAddr)); + SuccessOrExit(error = frameInfo.ParseFrom(*aFrame, Frame::kParseFully)); // Destination Address Filtering - switch (dstAddr.GetType()) + switch (frameInfo.mAddrs.mDestination.GetType()) { case Address::kTypeNone: break; case Address::kTypeShort: - SuccessOrExit(error = FilterDestShortAddress(dstAddr.GetShort())); + SuccessOrExit(error = FilterDestShortAddress(frameInfo.mAddrs.mDestination.GetShort())); break; case Address::kTypeExtended: - VerifyOrExit(dstAddr.GetExtended() == GetExtAddress(), error = kErrorDestinationAddressFiltered); + VerifyOrExit(frameInfo.mAddrs.mDestination.GetExtended() == GetExtAddress(), + error = kErrorDestinationAddressFiltered); break; } // Verify destination PAN ID if present - if (kErrorNone == aFrame->GetDstPanId(panId)) + if (frameInfo.mPanIds.IsDestinationPresent()) { + PanId panId = frameInfo.mPanIds.GetDestination(); + VerifyOrExit(panId == kPanIdBroadcast || panId == mPanId, error = kErrorDestinationAddressFiltered); } // Source Address Filtering + // + // If the`srcAddr` is associated with a known neighbor, a short + // `srcAddr` is replaced with the `ExtAddress` of the neighbor. The + // Extended Address is then used for nonce calculation during RX + // security processing. + + srcAddr = frameInfo.mAddrs.mSource; if (!srcAddr.IsNone()) { @@ -1917,7 +1936,8 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) #if OPENTHREAD_FTD // Allow multicasts from neighbor routers if FTD - if ((neighbor == nullptr) && dstAddr.IsBroadcast() && Get().IsFullThreadDevice()) + if ((neighbor == nullptr) && frameInfo.mAddrs.mDestination.IsBroadcast() && + Get().IsFullThreadDevice()) { neighbor = Get().FindRxOnlyNeighborRouter(srcAddr); } @@ -1937,7 +1957,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) #endif } - if (dstAddr.IsBroadcast()) + if (frameInfo.mAddrs.mDestination.IsBroadcast()) { mCounters.mRxBroadcast++; } @@ -1946,7 +1966,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) mCounters.mRxUnicast++; } - error = ProcessReceiveSecurity(*aFrame, srcAddr, neighbor); + error = ProcessReceiveSecurity(frameInfo, srcAddr, neighbor); switch (error) { @@ -1977,18 +1997,18 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) } #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE - ProcessCsl(*aFrame, srcAddr); + ProcessCsl(frameInfo, srcAddr); #endif - Get().ProcessRxFrame(*aFrame); + Get().ProcessRxFrame(frameInfo); if (neighbor != nullptr) { - UpdateNeighborLinkInfo(*neighbor, *aFrame); + UpdateNeighborLinkInfo(*neighbor, frameInfo); - if (aFrame->GetSecurityEnabled()) + if (frameInfo.mIsSecurityEnabled) { - if (aFrame->HasKeyIdMode(Frame::kKeyIdMode1)) + if (frameInfo.mKeyIdMode == Frame::kKeyIdMode1) { switch (neighbor->GetState()) { @@ -1999,7 +2019,9 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) case Neighbor::kStateChildUpdateRequest: // Only accept a "MAC Data Request" frame from a child being restored. - VerifyOrExit(aFrame->IsDataRequestCommand(), error = kErrorDrop); + VerifyOrExit((frameInfo.mType == Frame::kTypeMacCmd) && + (frameInfo.mCommandId == Frame::kMacCmdDataRequest), + error = kErrorDrop); break; default: @@ -2008,7 +2030,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 && OPENTHREAD_FTD // From Thread 1.2, MAC Data Frame can also act as keep-alive message if child supports - if (aFrame->GetType() == Frame::kTypeData && !neighbor->IsRxOnWhenIdle() && + if (frameInfo.mType == Frame::kTypeData && !neighbor->IsRxOnWhenIdle() && neighbor->IsEnhancedKeepAliveSupported()) { neighbor->SetLastHeard(TimerMilli::GetNow()); @@ -2026,10 +2048,10 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) { case kOperationActiveScan: - if (aFrame->GetType() == Frame::kTypeBeacon) + if (frameInfo.mType == Frame::kTypeBeacon) { mCounters.mRxBeacon++; - ReportActiveScanResult(aFrame); + ReportActiveScanResult(&frameInfo); ExitNow(); } @@ -2046,12 +2068,12 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) case kOperationWaitingForData: - if (!dstAddr.IsNone()) + if (!frameInfo.mAddrs.mDestination.IsNone()) { mTimer.Stop(); #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS - if (!mRxOnWhenIdle && !mPromiscuous && aFrame->GetFramePending()) + if (!mRxOnWhenIdle && !mPromiscuous && frameInfo.mIsFramePending) { mShouldDelaySleep = true; LogDebg("Delay sleep for pending rx"); @@ -2069,10 +2091,10 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) break; } - switch (aFrame->GetType()) + switch (frameInfo.mType) { case Frame::kTypeMacCmd: - HandleMacCommand(*aFrame); + HandleMacCommand(frameInfo); break; case Frame::kTypeBeacon: @@ -2082,7 +2104,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) case Frame::kTypeData: mCounters.mRxData++; DumpDebg("RX", aFrame->GetPsdu(), aFrame->GetLength()); - Get().HandleReceivedFrame(*aFrame); + Get().HandleReceivedFrame(frameInfo); UpdateIdleMode(); break; @@ -2095,7 +2117,7 @@ exit: if (error != kErrorNone) { - LogFrameRxFailure(aFrame, error); + LogFrameRxFailure(frameInfo, error); switch (error) { @@ -2139,7 +2161,7 @@ exit: #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame->GetRadioType() == Radio::kTypeTrel) + if ((aFrame != nullptr) && aFrame->GetRadioType() == Radio::kTypeTrel) #endif { if (error == kErrorNone) @@ -2159,23 +2181,38 @@ exit: // update (matching the policy in // `ThreadLinkInfo::SetFrom()`). - Get().CheckPeerAddrOnRxSuccess( - aFrame->IsSecuredWith(RxFrame::kAllowKeyIdMode0 | RxFrame::kAllowKeyIdMode1) - ? Trel::Link::kAllowPeerSockAddrUpdate - : Trel::Link::kDisallowPeerSockAddrUpdate); + Trel::Link::PeerSockAddrUpdateMode peerSockAddrUpdateMode = Trel::Link::kDisallowPeerSockAddrUpdate; + + if (frameInfo.mIsSecurityEnabled) + { + switch (frameInfo.mKeyIdMode) + { + case Frame::kKeyIdMode0: + case Frame::kKeyIdMode1: + peerSockAddrUpdateMode = Trel::Link::kAllowPeerSockAddrUpdate; + break; + default: + break; + } + } + + Get().CheckPeerAddrOnRxSuccess(peerSockAddrUpdateMode); } } #endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE } -void Mac::UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame &aRxFrame) +void Mac::UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame::ParseInfo &aRxFrameInfo) { LinkQuality oldLinkQuality = aNeighbor.GetLinkInfo().GetLinkQualityIn(); - aNeighbor.GetLinkInfo().AddRss(aRxFrame.GetRssi()); + VerifyOrExit(aRxFrameInfo.mParsedFully); + + aNeighbor.GetLinkInfo().AddRss(aRxFrameInfo.GetRxFrame()->GetRssi()); #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE - aNeighbor.AggregateLinkMetrics(/* aSeriesId */ 0, aRxFrame.GetType(), aRxFrame.GetLqi(), aRxFrame.GetRssi()); + aNeighbor.AggregateLinkMetrics(/* aSeriesId */ 0, aRxFrameInfo.mType, aRxFrameInfo.GetRxFrame()->GetLqi(), + aRxFrameInfo.GetRxFrame()->GetRssi()); #endif // Signal when `aNeighbor` is the current parent and its link @@ -2189,13 +2226,9 @@ exit: return; } -void Mac::HandleMacCommand(RxFrame &aFrame) +void Mac::HandleMacCommand(RxFrame::ParseInfo &aFrameInfo) { - uint8_t commandId; - - IgnoreError(aFrame.GetCommandId(commandId)); - - switch (commandId) + switch (aFrameInfo.mCommandId) { case Frame::kMacCmdBeaconRequest: mCounters.mRxBeaconRequest++; @@ -2204,7 +2237,7 @@ void Mac::HandleMacCommand(RxFrame &aFrame) if (ShouldSendBeacon()) { #if OPENTHREAD_CONFIG_MULTI_RADIO - mTxBeaconRadioLinks.Add(aFrame.GetRadioType()); + mTxBeaconRadioLinks.Add(aFrameInfo.GetRxFrame()->GetRadioType()); #endif StartOperation(kOperationTransmitBeacon); } @@ -2214,7 +2247,7 @@ void Mac::HandleMacCommand(RxFrame &aFrame) case Frame::kMacCmdDataRequest: mCounters.mRxDataPoll++; #if OPENTHREAD_FTD - Get().HandleDataPoll(aFrame); + Get().HandleDataPoll(aFrameInfo); #endif break; @@ -2335,7 +2368,7 @@ void Mac::LogOperation(OperationAction, Operation) const {} #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) -void Mac::LogFrameRxFailure(const RxFrame *aFrame, Error aError) const +void Mac::LogFrameRxFailure(const RxFrame::ParseInfo &aFrameInfo, Error aError) const { LogLevel logLevel; @@ -2353,22 +2386,24 @@ void Mac::LogFrameRxFailure(const RxFrame *aFrame, Error aError) const break; } - LogAt(logLevel, "Frame rx failed, error:%s, %s", ErrorToString(aError), - (aFrame == nullptr) ? "no-frame" : aFrame->ToInfoString().AsCString()); + LogAt(logLevel, "Frame rx failed, error:%s, %s", ErrorToString(aError), aFrameInfo.ToInfoString().AsCString()); } -void Mac::LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) const +void Mac::LogFrameTxFailure(const TxFrame::ParseInfo &aFrameInfo, + Error aError, + uint8_t aRetryCount, + bool aWillRetx) const { #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeIeee802154) + if (aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeIeee802154) #endif { - uint8_t maxAttempts = aFrame.GetMaxFrameRetries() + 1; + uint8_t maxAttempts = aFrameInfo.GetTxFrame()->GetMaxFrameRetries() + 1; uint8_t curAttempt = aWillRetx ? (aRetryCount + 1) : maxAttempts; LogInfo("Frame tx attempt %u/%u failed, error:%s, %s", curAttempt, maxAttempts, ErrorToString(aError), - aFrame.ToInfoString().AsCString()); + aFrameInfo.ToInfoString().AsCString()); } #else OT_UNUSED_VARIABLE(aRetryCount); @@ -2377,12 +2412,12 @@ void Mac::LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryC #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO - if (aFrame.GetRadioType() == Radio::kTypeTrel) + if (aFrameInfo.GetTxFrame()->GetRadioType() == Radio::kTypeTrel) #endif { if (Get().IsEnabled()) { - LogInfo("Frame tx failed, error:%s, %s", ErrorToString(aError), aFrame.ToInfoString().AsCString()); + LogInfo("Frame tx failed, error:%s, %s", ErrorToString(aError), aFrameInfo.ToInfoString().AsCString()); } } #endif @@ -2392,11 +2427,11 @@ void Mac::LogBeacon(const char *aActionText) const { LogInfo("%s Beacon", aActio #else // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) -void Mac::LogFrameRxFailure(const RxFrame *, Error) const {} +void Mac::LogFrameRxFailure(const RxFrame::ParseInfo &, Error) const {} void Mac::LogBeacon(const char *) const {} -void Mac::LogFrameTxFailure(const TxFrame &, Error, uint8_t, bool) const {} +void Mac::LogFrameTxFailure(const TxFrame::ParseInfo &, Error, uint8_t, bool) const {} #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) @@ -2511,17 +2546,18 @@ uint32_t Mac::GetCslPeriodInMsec(void) const #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE -void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr) +void Mac::ProcessCsl(const RxFrame::ParseInfo &aFrameInfo, const Address &aSrcAddr) { CslNeighbor *neighbor = nullptr; const CslIe *csl; VerifyOrExit(!aSrcAddr.IsNone()); - VerifyOrExit(aFrame.IsVersion2015()); - VerifyOrExit(aFrame.IsSecuredWith(RxFrame::kAllowKeyIdMode1)); + VerifyOrExit(aFrameInfo.mVersion == Frame::kVersion2015); + VerifyOrExit(aFrameInfo.mIsSecurityEnabled); + VerifyOrExit(aFrameInfo.mKeyIdMode == Frame::kKeyIdMode1); - csl = aFrame.Find(); + csl = aFrameInfo.Find(); VerifyOrExit(csl != nullptr); #if OPENTHREAD_FTD @@ -2538,10 +2574,10 @@ void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr) neighbor->SetCslPhase(csl->GetPhase()); neighbor->SetCslSynchronized(true); neighbor->SetCslLastHeard(TimerMilli::GetNow()); - neighbor->SetLastRxTimestamp(aFrame.GetTimestamp()); + neighbor->SetLastRxTimestamp(aFrameInfo.GetRxFrame()->GetTimestamp()); LogDebg("Timestamp=%lu Sequence=%u CslPeriod=%u CslPhase=%u TransmitPhase=%u", - ToUlong(Radio::ConvertTime64To32(aFrame.GetTimestamp())), aFrame.GetSequence(), csl->GetPeriod(), - csl->GetPhase(), neighbor->GetCslPhase()); + ToUlong(Radio::ConvertTime64To32(aFrameInfo.GetRxFrame()->GetTimestamp())), aFrameInfo.mSequenceNum, + csl->GetPeriod(), csl->GetPhase(), neighbor->GetCslPhase()); #if OPENTHREAD_FTD Get().Update(); @@ -2550,14 +2586,18 @@ void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr) exit: return; } + #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE -void Mac::ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor) +void Mac::ProcessEnhAckProbing(const RxFrame::ParseInfo &aFrameInfo, const Neighbor &aNeighbor) { - const LinkMetricsProbingIe *probingIe = aFrame.Find(); + const LinkMetricsProbingIe *probingIe; uint8_t dataLen; + VerifyOrExit(aFrameInfo.mParsedFully); + + probingIe = aFrameInfo.Find(); VerifyOrExit(probingIe != nullptr); dataLen = probingIe->GetMetricsDataLen(); diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index e30bf20e0..d539badcf 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -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); diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index 643be8951..25f539228 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -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(kEncrypt) == Crypto::AesCcm::kEncrypt, "kEncrypt enum value is incorrect"); + static_assert(static_cast(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(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(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(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(); + const HeaderIe *ie = ieData.Read(); 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(); + ParseInfo info; + CslIe *csl; + SuccessOrExit(info.ParseFrom(*this, kParseFully)); + + csl = info.Find(); 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(); + ParseInfo info; + LinkMetricsProbingIe *probingIe; + SuccessOrExit(info.ParseFrom(*this, kParseFully)); + + probingIe = info.Find(); 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(kEncrypt) == Crypto::AesCcm::kEncrypt, "kEncrypt enum value is incorrect"); - static_assert(static_cast(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(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; diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index 39cfbc07b..752586f0c 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -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 + { + 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 const IeType *Find(void) const + { + return static_cast(FindHeaderIe(HeaderIe::ValidateAs)); + } - /** - * 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 IeType *Find(void) { return AsNonConst(AsConst(this)->Find()); } - /** - * 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 bool Has(void) const { return Find() != 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 const IeType *Find(void) const - { - return static_cast(FindHeaderIe(HeaderIe::ValidateAs)); - } - - /** - * 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 IeType *Find(void) { return AsNonConst(AsConst(this)->Find()); } - - /** - * 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 bool Has(void) const { return Find() != 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(ReadBits(aFcf)); } static AddrMode ReadDstAddrMode(uint16_t aFcf) { return As(ReadBits(aFcf)); } @@ -693,13 +492,6 @@ protected: private: template static EnumType As(uint16_t aValue) { return static_cast(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 { -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(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 { 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(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. * diff --git a/src/core/mac/mac_links.cpp b/src/core/mac/mac_links.cpp index 6cebb9eb3..ee54f1e5b 100644 --- a/src/core/mac/mac_links.cpp +++ b/src/core/mac/mac_links.cpp @@ -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().GetTrelMacFrameCounter()); + aFrameInfo.WriteFrameCounter(Get().GetTrelMacFrameCounter()); Get().IncrementTrelMacFrameCounter(); - ExitNow(); } -#endif - -exit: - return; } -#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE +#endif } // namespace Mac } // namespace ot diff --git a/src/core/mac/mac_links.hpp b/src/core/mac/mac_links.hpp index 7c6c0b795..4943670c3 100644 --- a/src/core/mac/mac_links.hpp +++ b/src/core/mac/mac_links.hpp @@ -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: diff --git a/src/core/mac/scan_result.cpp b/src/core/mac/scan_result.cpp index 5534175d7..3789e7442 100644 --- a/src/core/mac/scan_result.cpp +++ b/src/core/mac/scan_result.cpp @@ -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(); VerifyOrExit((beaconHeader != nullptr) && beaconHeader->IsValid()); diff --git a/src/core/mac/scan_result.hpp b/src/core/mac/scan_result.hpp index e7487613f..ab01b60e3 100644 --- a/src/core/mac/scan_result.hpp +++ b/src/core/mac/scan_result.hpp @@ -169,7 +169,7 @@ public: private: typedef Callback ScanCallback; - Error PopulateFromBeacon(const Mac::RxFrame *aBeaconFrame); + Error PopulateFromBeacon(const Mac::RxFrame::ParseInfo &aFrameInfo); }; /** diff --git a/src/core/mac/sub_mac.cpp b/src/core/mac/sub_mac.cpp index a1a06292e..5ac72bdfe 100644 --- a/src/core/mac/sub_mac.cpp +++ b/src/core/mac/sub_mac.cpp @@ -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()); + VerifyOrExit(!aFrameInfo.Has()); #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().IsEnabled(); + VerifyOrExit(!Get().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; diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index 1779a8e2b..623b514b1 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -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); diff --git a/src/core/mac/sub_mac_callbacks.cpp b/src/core/mac/sub_mac_callbacks.cpp index 4bde853bb..187d145d2 100644 --- a/src/core/mac/sub_mac_callbacks.cpp +++ b/src/core/mac/sub_mac_callbacks.cpp @@ -64,25 +64,25 @@ void SubMac::Callbacks::RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel) Get().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().RecordFrameTransmitStatus(aFrame, aError, aRetryCount, aWillRetx); + Get().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().IsEnabled()) { - Get().InvokeTransmitDone(aFrame, aAckFrame, aError); + Get().InvokeTransmitDone(aFrameInfo, aAckFrame, aError); } else #endif { - Get().HandleTransmitDone(aFrame, aAckFrame, aError); + Get().HandleTransmitDone(aFrameInfo, aAckFrame, aError); } } @@ -111,17 +111,17 @@ void SubMac::Callbacks::ReceiveDone(RxFrame *aFrame, Error aError) { Get().RecordFrameTransmitStatus(aFrame, aError, aRetryCount, aWillRetx); + Get().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().InvokeTransmitDone(aFrame, aAckFrame, aError); + Get().InvokeTransmitDone(aFrameInfo, aAckFrame, aError); } void SubMac::Callbacks::EnergyScanDone(int8_t aMaxRssi) { Get().InvokeEnergyScanDone(aMaxRssi); } diff --git a/src/core/mac/sub_mac_csl_receiver.cpp b/src/core/mac/sub_mac_csl_receiver.cpp index c19e7a25a..e2c9308c5 100644 --- a/src/core/mac/sub_mac_csl_receiver.cpp +++ b/src/core/mac/sub_mac_csl_receiver.cpp @@ -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()) - { - SetCslLastSyncToNow(); - RestartCslTimerAfterSyncUpdate(); - } + + VerifyOrExit(aAckFrame != nullptr); + VerifyOrExit(aFrameInfo.mParsedFully); + VerifyOrExit(aFrameInfo.Has()); + + 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 logString; - Address dst; - int32_t deviation; - uint32_t sampleTime, ahead, after; + String 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()))); diff --git a/src/core/mac/wakeup_tx_scheduler.cpp b/src/core/mac/wakeup_tx_scheduler.cpp index 99becb1f1..ff6e803d8 100644 --- a/src/core/mac/wakeup_tx_scheduler.cpp +++ b/src/core/mac/wakeup_tx_scheduler.cpp @@ -79,13 +79,15 @@ void WakeupTxScheduler::RequestWakeupFrameTransmission(void) { Get().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().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().GetNow(); + Mac::RendezvousTimeIe *rendezvousTimeIe; + Mac::ConnectionIe *connectionIe; VerifyOrExit(mIsRunning); @@ -102,6 +104,11 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames) VerifyOrExit(frame->GenerateWakeupFrame(Get().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()->SetRendezvousTime( - ClampToUint16(rendezvousTimeUs / Radio::kTenSymbolsDuration)); + rendezvousTimeIe = txFrameInfo.Find(); + VerifyOrExit(rendezvousTimeIe != nullptr, frame = nullptr); + rendezvousTimeIe->SetRendezvousTime(ClampToUint16(rendezvousTimeUs / Radio::kTenSymbolsDuration)); - connectionIe = frame->Find(); + connectionIe = txFrameInfo.Find(); + VerifyOrExit(connectionIe != nullptr, frame = nullptr); connectionIe->SetRetryInterval(kConnectionRetryInterval); connectionIe->SetRetryCount(kConnectionRetryCount); diff --git a/src/core/radio/trel_link.cpp b/src/core/radio/trel_link.cpp index 94e32d285..db4d3cec0 100644 --- a/src/core/radio/trel_link.cpp +++ b/src/core/radio/trel_link.cpp @@ -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().RecordFrameTransmitStatus(mTxFrame, aError, /* aRetryCount */ 0, /* aWillRetx */ false); - Get().HandleTransmitDone(mTxFrame, aAckFrame, aError); + IgnoreError(frameInfo.ParseFrom(mTxFrame, Mac::Frame::kParseFully)); + + Get().RecordFrameTransmitStatus(frameInfo, aError, /* aRetryCount */ 0, /* aWillRetx */ false); + Get().HandleTransmitDone(frameInfo, aAckFrame, aError); } void Link::HandleTimer(void) diff --git a/src/core/thread/csl_tx_scheduler.cpp b/src/core/thread/csl_tx_scheduler.cpp index 33261bc54..2f8ca3e12 100644 --- a/src/core/thread/csl_tx_scheduler.cpp +++ b/src/core/thread/csl_tx_scheduler.cpp @@ -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().HandleSentFrameToCslNeighbor(aFrame, mFrameContext, aError, *mCslTxNeighbor); + Get().HandleSentFrameToCslNeighbor(aFrameInfo, mFrameContext, aError, *mCslTxNeighbor); exit: mCslTxMessage = nullptr; diff --git a/src/core/thread/csl_tx_scheduler.hpp b/src/core/thread/csl_tx_scheduler.hpp index c01d33bdd..6f91c2435 100644 --- a/src/core/thread/csl_tx_scheduler.hpp +++ b/src/core/thread/csl_tx_scheduler.hpp @@ -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` diff --git a/src/core/thread/indirect_sender.cpp b/src/core/thread/indirect_sender.cpp index 05bbfb6f9..2e9034d2a 100644 --- a/src/core/thread/indirect_sender.cpp +++ b/src/core/thread/indirect_sender.cpp @@ -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().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(aCslNeighbor)); + HandleSentFrameToChild(aFrameInfo, aContext, aError, static_cast(aCslNeighbor)); #else - OT_UNUSED_VARIABLE(aFrame); + OT_UNUSED_VARIABLE(aFrameInfo); OT_UNUSED_VARIABLE(aContext); OT_UNUSED_VARIABLE(aError); OT_UNUSED_VARIABLE(aCslNeighbor); diff --git a/src/core/thread/indirect_sender.hpp b/src/core/thread/indirect_sender.hpp index 011a580f9..579ffd3d7 100644 --- a/src/core/thread/indirect_sender.hpp +++ b/src/core/thread/indirect_sender.hpp @@ -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); diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index dc3b29692..44b600b70 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -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().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() && aIsDataPoll) + if (aFrameInfo.Has() && 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().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 &) {} diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index c89107865..7f8c20e49 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -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); diff --git a/src/core/thread/radio_selector.cpp b/src/core/thread/radio_selector.cpp index f352afebc..e84769728 100644 --- a/src/core/thread/radio_selector.cpp +++ b/src/core/thread/radio_selector.cpp @@ -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().FindNeighbor(macDest, Neighbor::kInStateAnyExceptInvalid); + neighbor = Get().FindNeighbor(aFrameInfo.mAddrs.mDestination, Neighbor::kInStateAnyExceptInvalid); VerifyOrExit(neighbor != nullptr); if (neighbor->GetSupportedRadioTypes().Contains(radioType)) diff --git a/src/core/thread/radio_selector.hpp b/src/core/thread/radio_selector.hpp index 7b52c959f..df68541ce 100644 --- a/src/core/thread/radio_selector.hpp +++ b/src/core/thread/radio_selector.hpp @@ -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 /** diff --git a/src/core/thread/thread_link_info.cpp b/src/core/thread/thread_link_info.cpp index 2e7ecd81d..e5c002892 100644 --- a/src/core/thread/thread_link_info.cpp +++ b/src/core/thread/thread_link_info.cpp @@ -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(); + const Mac::TimeIe *timeIe = aFrameInfo.Find(); if (timeIe != nullptr) { - mNetworkTimeOffset = static_cast(timeIe->GetTime() - aFrame.GetTimestamp()); + mNetworkTimeOffset = static_cast(timeIe->GetTime() - aFrameInfo.GetRxFrame()->GetTimestamp()); mTimeSyncSeq = timeIe->GetSequence(); } } #endif #if OPENTHREAD_CONFIG_MULTI_RADIO - mRadioType = static_cast(aFrame.GetRadioType()); + mRadioType = static_cast(aFrameInfo.GetRxFrame()->GetRadioType()); #endif } diff --git a/src/core/thread/thread_link_info.hpp b/src/core/thread/thread_link_info.hpp index a028b0f67..f3ea6890d 100644 --- a/src/core/thread/thread_link_info.hpp +++ b/src/core/thread/thread_link_info.hpp @@ -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); diff --git a/src/core/utils/otns.cpp b/src/core/utils/otns.cpp index 395231bfe..4dbf9a280 100644 --- a/src/core/utils/otns.cpp +++ b/src/core/utils/otns.cpp @@ -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); diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index a9a406717..695932d7f 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -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(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(mTransmitFrame)->SetKeyIndex(keyIndex); - static_cast(mTransmitFrame)->SetFrameCounter(frameCounter); + IgnoreError(frameInfo.ParseFrom(*static_cast(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(mTransmitFrame)->SetIsHeaderUpdated(headerUpdated); diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp index 151c56baf..072ec58f4 100644 --- a/src/ncp/ncp_base_radio.cpp +++ b/src/ncp/ncp_base_radio.cpp @@ -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(aAckFrame)->GetFramePending()); - bool headerUpdated = static_cast(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(aFrame), Mac::Frame::kParseFully)); + headerUpdated = txFrameInfo.GetTxFrame()->IsHeaderUpdated(); + + if (aAckFrame != nullptr) + { + Mac::RxFrame::ParseInfo ackFrameInfo; + + IgnoreError(ackFrameInfo.ParseFrom(*static_cast(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(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(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(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()); diff --git a/tests/nexus/platform/nexus_core.cpp b/tests/nexus/platform/nexus_core.cpp index 1116b2051..c87dc2c9d 100644 --- a/tests/nexus/platform/nexus_core.cpp +++ b/tests/nexus/platform/nexus_core.cpp @@ -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(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(static_cast(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) { diff --git a/tests/nexus/platform/nexus_grpc.cpp b/tests/nexus/platform/nexus_grpc.cpp index ddceedae5..2a71631cc 100644 --- a/tests/nexus/platform/nexus_grpc.cpp +++ b/tests/nexus/platform/nexus_grpc.cpp @@ -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; } diff --git a/tests/unit/test_mac_frame.cpp b/tests/unit/test_mac_frame.cpp index 211e526a4..af5e208e3 100644 --- a/tests/unit/test_mac_frame.cpp +++ b/tests/unit/test_mac_frame.cpp @@ -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(); 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(); + 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(); + SuccessOrQuit(ackInfo.ParseFrom(ackFrame, Mac::Frame::kParseFully)); + csl = ackInfo.Find(); + 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