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