From 75ac125771c59b3709730e02dc2d12abe88944e5 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Fri, 26 Feb 2021 00:02:52 +0800 Subject: [PATCH] [mac] refactor code to add frame version and header IE in TX frames (#6189) This commit refactors the code to set frame version, IE present field in frame control field and to append Header IE. - Split UpdateFrameControlField into two methods: CalcIePresent and CalcFrameVersion. Currently UpdateFrameControlField` is not easy-to-read and hard to extend the method to handle more cases. - Move this code from Mac to MeshForwarder. I think it should be MeshForwarder's responsibility (PrepareDataFrame) to prepare the frame (though Mac sometimes prepare data frames itself). Since when preparing the frame, most information comes from the Message which is only in MeshForwarder, we can put this code for preparing frame in MeshForwarder. - Enhance the way to append Header IEs to the frame. Currently in Mac::AppendHeaderIe, it generates a list of HeaderIe first and then call Frame::AppendHeaderIe. There are two problems here: 1. it uses another copy (copy HeaderIe to the frame's buffer). 2. it has to initialize Vendor IE (e.g. TimeSync IE) after Vendor IE header has been copied to the buffer. Currently it directly finds the first Vendor IE in the buffer and initialize it as TimeSync IE, which is not extensible. This commit shifts the responsibility of 'how to append the IE' to Frame, by providing AppendHeaderIeAt method. And MeshForwarder can decide which IEs to append and directly call the method to append IEs to the frame. --- examples/platforms/utils/mac_frame.cpp | 4 +- src/core/mac/mac.cpp | 120 +++---------------------- src/core/mac/mac.hpp | 29 ------ src/core/mac/mac_frame.cpp | 82 +++++++++++++---- src/core/mac/mac_frame.hpp | 74 ++++++++++++--- src/core/thread/mesh_forwarder.cpp | 103 +++++++++++++++++++-- src/core/thread/mesh_forwarder.hpp | 7 ++ src/core/thread/mesh_forwarder_ftd.cpp | 23 +++-- tests/unit/test_mac_frame.cpp | 4 +- 9 files changed, 263 insertions(+), 183 deletions(-) diff --git a/examples/platforms/utils/mac_frame.cpp b/examples/platforms/utils/mac_frame.cpp index 353e02481..eab13986c 100644 --- a/examples/platforms/utils/mac_frame.cpp +++ b/examples/platforms/utils/mac_frame.cpp @@ -230,7 +230,7 @@ uint8_t otMacFrameGenerateCslIeTemplate(uint8_t *aDest) { assert(aDest != nullptr); - reinterpret_cast(aDest)->SetId(Mac::Frame::kHeaderIeCsl); + reinterpret_cast(aDest)->SetId(Mac::CslIe::kHeaderIeId); reinterpret_cast(aDest)->SetLength(sizeof(Mac::CslIe)); return sizeof(Mac::HeaderIe) + sizeof(Mac::CslIe); @@ -244,7 +244,7 @@ uint8_t otMacFrameGenerateEnhAckProbingIe(uint8_t *aDest, const uint8_t *aIeData assert(aDest != nullptr); - reinterpret_cast(aDest)->SetId(Mac::Frame::kHeaderIeVendor); + reinterpret_cast(aDest)->SetId(Mac::ThreadIe::kHeaderIeId); reinterpret_cast(aDest)->SetLength(len); aDest += sizeof(Mac::HeaderIe); diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index d401891d8..2d1fdd484 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -903,6 +903,7 @@ TxFrame *Mac::PrepareDataRequest(void) TxFrame *frame = nullptr; Address src, dst; uint16_t fcf; + bool iePresent = Get().CalcIePresent(nullptr); #if OPENTHREAD_CONFIG_MULTI_RADIO RadioType radio; @@ -915,7 +916,13 @@ TxFrame *Mac::PrepareDataRequest(void) #endif fcf = Frame::kFcfFrameMacCmd | Frame::kFcfPanidCompression | Frame::kFcfAckRequest | Frame::kFcfSecurityEnabled; - UpdateFrameControlField(nullptr, /* aIsTimeSync */ false, fcf); + + if (iePresent) + { + fcf |= Frame::kFcfIePresent; + } + + fcf |= Get().CalcFrameVersion(Get().FindNeighbor(dst), iePresent); if (dst.IsExtended()) { @@ -938,7 +945,10 @@ TxFrame *Mac::PrepareDataRequest(void) frame->SetSrcAddr(src); frame->SetDstAddr(dst); #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - IgnoreError(AppendHeaderIe(false, *frame)); + if (iePresent) + { + Get().AppendHeaderIe(nullptr, *frame); + } #endif IgnoreError(frame->SetCommandId(Frame::kMacCmdDataRequest)); @@ -2565,7 +2575,7 @@ bool Mac::IsCslEnabled(void) const #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr) { - const uint8_t *cur = aFrame.GetHeaderIe(Frame::kHeaderIeCsl); + const uint8_t *cur = aFrame.GetHeaderIe(CslIe::kHeaderIeId); Child * child = Get().FindChild(aSrcAddr, Child::kInStateAnyExceptInvalid); const CslIe * csl; @@ -2615,109 +2625,5 @@ exit: } #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE -#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT -otError Mac::AppendHeaderIe(bool aIsTimeSync, TxFrame &aFrame) const -{ - OT_UNUSED_VARIABLE(aIsTimeSync); - - const size_t kMaxNumHeaderIe = 3; // TimeSync + CSL + Termination2 - HeaderIe ieList[kMaxNumHeaderIe]; - otError error = OT_ERROR_NONE; - uint8_t ieCount = 0; - - VerifyOrExit(aFrame.IsVersion2015() && aFrame.IsIePresent()); - -#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE - if (aIsTimeSync) - { - ieList[ieCount].Init(); - ieList[ieCount].SetId(Frame::kHeaderIeVendor); - ieList[ieCount].SetLength(sizeof(TimeIe)); - ieCount++; - } -#endif - -#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (IsCslEnabled()) - { - OT_ASSERT(aFrame.GetSecurityEnabled()); - - aFrame.mInfo.mTxInfo.mCslPresent = true; - ieList[ieCount].Init(); - ieList[ieCount].SetId(Frame::kHeaderIeCsl); - ieList[ieCount].SetLength(sizeof(CslIe)); - ieCount++; - } - else -#endif - { - aFrame.mInfo.mTxInfo.mCslPresent = false; - } - - if (ieCount > 0) - { - ieList[ieCount].Init(); - ieList[ieCount].SetId(Frame::kHeaderIeTermination2); - ieList[ieCount].SetLength(0); - - SuccessOrExit(error = aFrame.AppendHeaderIe(ieList, ++ieCount)); - } - -#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE - if (aIsTimeSync) - { - uint8_t *cur = aFrame.GetHeaderIe(Frame::kHeaderIeVendor); - TimeIe * ie = reinterpret_cast(cur + sizeof(HeaderIe)); - - ie->Init(); - } -#endif - -exit: - return error; -} -#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - -void Mac::UpdateFrameControlField(const Neighbor *aNeighbor, bool aIsTimeSync, uint16_t &aFcf) const -{ - OT_UNUSED_VARIABLE(aIsTimeSync); - OT_UNUSED_VARIABLE(aNeighbor); - -#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT -#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE - if (aIsTimeSync) - { - aFcf |= Frame::kFcfFrameVersion2015 | Frame::kFcfIePresent; - } - else -#endif -#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (IsCslEnabled()) - { - aFcf |= Frame::kFcfFrameVersion2015 | Frame::kFcfIePresent; - } - else -#endif -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE - if (aNeighbor != nullptr && !Mle::MleRouter::IsActiveRouter(aNeighbor->GetRloc16()) && - static_cast(aNeighbor)->IsCslSynchronized()) - { - aFcf |= Frame::kFcfFrameVersion2015; - } - else -#endif -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE - if (aNeighbor != nullptr && aNeighbor->IsEnhAckProbingActive()) - { - aFcf |= Frame::kFcfFrameVersion2015; ///< Set version to 2015 to fetch Link Metrics data in Enh-ACK. - } - else -#endif -#endif - { - aFcf |= Frame::kFcfFrameVersion2006; - } -} - } // namespace Mac } // namespace ot diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 9ab8926b7..a169eecce 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -746,35 +746,6 @@ public: #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE -#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - /** - * This method appends header IEs to a TX-frame according to its - * frame control field and if time sync is enabled. - * - * @param[in] aIsTimeSync A boolean indicates if time sync is being used. - * @param[in,out] aFrame A reference to the TX-frame to which the IEs will be appended. - * - * @retval OT_ERROR_NONE If append header IEs successfully. - * @retval OT_ERROR_NOT_FOUND If cannot find header IE position in the frame. - * - */ - otError AppendHeaderIe(bool aIsTimeSync, TxFrame &aFrame) const; -#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - - /** - * This method updates frame control field. - * - * If the frame would contain header IEs, IE present field would be set. - * If this is a CSL transmission frame or header IE is present in this frame, - * the version should be set to 2015. Otherwise, the version would be set to 2006. - * - * @param[in] aNeighbor A pointer to the destination device, could be `nullptr`. - * @param[in] aIsTimeSync A boolean indicates if time sync is being used. - * @param[out] aFcf A reference to the frame control field to set. - * - */ - void UpdateFrameControlField(const Neighbor *aNeighbor, bool aIsTimeSync, uint16_t &aFcf) const; - private: enum { diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index bdbb03016..eb3f0ab10 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -50,6 +50,13 @@ using ot::Encoding::LittleEndian::ReadUint32; using ot::Encoding::LittleEndian::WriteUint16; using ot::Encoding::LittleEndian::WriteUint32; +void HeaderIe::Init(uint16_t aId, uint8_t aLen) +{ + Init(); + SetId(aId); + SetLength(aLen); +} + void Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl) { mLength = CalculateAddrFieldSize(aFcf); @@ -829,7 +836,7 @@ uint8_t Frame::FindPayloadIndex(void) const index += ie->GetLength(); VerifyOrExit(index + footerLength <= mLength, index = kInvalidIndex); - if (ie->GetId() == kHeaderIeTermination2) + if (ie->GetId() == Termination2Ie::kHeaderIeId) { break; } @@ -886,25 +893,59 @@ exit: return index; } -otError Frame::AppendHeaderIe(HeaderIe *aIeList, uint8_t aIeCount) +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +template otError Frame::AppendHeaderIeAt(uint8_t &aIndex) { - otError error = OT_ERROR_NONE; - uint16_t index = FindHeaderIeIndex(); + otError error = OT_ERROR_NONE; - VerifyOrExit(index != kInvalidIndex, error = OT_ERROR_NOT_FOUND); + SuccessOrExit(error = InitIeHeaderAt(aIndex, IeType::kHeaderIeId, IeType::kIeContentSize)); - for (uint8_t i = 0; i < aIeCount; i++) - { - memcpy(&mPsdu[index], &aIeList[i], sizeof(HeaderIe)); - - index += sizeof(HeaderIe) + aIeList[i].GetLength(); - mLength += sizeof(HeaderIe) + aIeList[i].GetLength(); - } + InitIeContentAt(aIndex); exit: return error; } +otError Frame::InitIeHeaderAt(uint8_t &aIndex, uint8_t ieId, uint8_t ieContentSize) +{ + otError error = OT_ERROR_NONE; + + if (aIndex == 0) + { + aIndex = FindHeaderIeIndex(); + } + + VerifyOrExit(aIndex != kInvalidIndex, error = OT_ERROR_NOT_FOUND); + + reinterpret_cast(mPsdu + aIndex)->Init(ieId, ieContentSize); + aIndex += sizeof(HeaderIe); + + mLength += sizeof(HeaderIe) + ieContentSize; +exit: + return error; +} + +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE +template <> void Frame::InitIeContentAt(uint8_t &aIndex) +{ + reinterpret_cast(mPsdu + aIndex)->Init(); + aIndex += sizeof(TimeIe); +} +#endif + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE +template <> void Frame::InitIeContentAt(uint8_t &aIndex) +{ + aIndex += sizeof(CslIe); +} +#endif + +template <> void Frame::InitIeContentAt(uint8_t &aIndex) +{ + OT_UNUSED_VARIABLE(aIndex); +} +#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT + const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const { uint8_t index = FindHeaderIeIndex(); @@ -948,7 +989,7 @@ const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const { const HeaderIe *ie = reinterpret_cast(&mPsdu[index]); - if (ie->GetId() == kHeaderIeVendor) + if (ie->GetId() == VendorIeHeader::kHeaderIeId) { const VendorIeHeader *vendorIe = reinterpret_cast(reinterpret_cast(ie) + sizeof(HeaderIe)); @@ -972,7 +1013,7 @@ exit: #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE void Frame::SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase) { - uint8_t *cur = GetHeaderIe(Frame::kHeaderIeCsl); + uint8_t *cur = GetHeaderIe(CslIe::kHeaderIeId); CslIe * csl; VerifyOrExit(cur != nullptr); @@ -1002,7 +1043,7 @@ const TimeIe *Frame::GetTimeIe(void) const const TimeIe * timeIe = nullptr; const uint8_t *cur = nullptr; - cur = GetHeaderIe(kHeaderIeVendor); + cur = GetHeaderIe(VendorIeHeader::kHeaderIeId); VerifyOrExit(cur != nullptr); cur += sizeof(HeaderIe); @@ -1079,6 +1120,17 @@ uint8_t Frame::GetFcsSize(void) const } #endif +// Explicit instantiation +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE +template otError Frame::AppendHeaderIeAt(uint8_t &aIndex); +#endif +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE +template otError Frame::AppendHeaderIeAt(uint8_t &aIndex); +#endif +template otError Frame::AppendHeaderIeAt(uint8_t &aIndex); +#endif + void TxFrame::CopyFrom(const TxFrame &aFromFrame) { uint8_t * psduBuffer = mPsdu; diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index c8e0672b9..0ed4636b3 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -71,6 +71,15 @@ public: */ void Init(void) { mFields.m16 = 0; } + /** + * This method initializes the Header IE with Id and Length. + * + * @param[in] aId The IE Element Id. + * @param[in] aLen The IE content length. + * + */ + void Init(uint16_t aId, uint8_t aLen); + /** * This method returns the IE Element Id. * @@ -144,6 +153,12 @@ OT_TOOL_PACKED_BEGIN class VendorIeHeader { public: + enum : uint8_t + { + kHeaderIeId = 0x00, + kIeContentSize = sizeof(uint8_t) * 4, + }; + /** * This method returns the Vendor OUI. * @@ -205,6 +220,12 @@ public: kVendorIeTime = 0x01, }; + enum + { + kHeaderIeId = VendorIeHeader::kHeaderIeId, + kIeContentSize = VendorIeHeader::kIeContentSize + sizeof(uint8_t) + sizeof(uint64_t), + }; + /** * This method initializes the time IE. * @@ -257,6 +278,12 @@ private: class ThreadIe { public: + enum : uint8_t + { + kHeaderIeId = VendorIeHeader::kHeaderIeId, + kIeContentSize = VendorIeHeader::kIeContentSize, + }; + enum : uint32_t { kVendorOuiThreadCompanyId = 0xeab89b, @@ -348,10 +375,6 @@ public: kMacCmdCoordinatorRealignment = 8, kMacCmdGtsRequest = 9, - kHeaderIeVendor = 0x00, - kHeaderIeCsl = 0x1a, - kHeaderIeTermination2 = 0x7f, - kImmAckLength = kFcfSize + kDsnSize + k154FcsSize, kInfoStringSize = 128, ///< Max chars needed for the info string representation (@sa ToInfoString()). @@ -923,16 +946,22 @@ public: #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT /** - * This method appends Header IEs to MAC header. + * This template method appends an Header IE at specified index in this frame. * - * @param[in] aIeList The pointer to the Header IEs array. - * @param[in] aIeCount The number of Header IEs in the array. + * @param[in,out] aIndex The index to append IE. If `aIndex` is `0` on input, this method finds the index + * for the first IE and appends the IE at that position. If the position is not found + * successfully, `aIndex` will be set to `kInvalidIndex`. Otherwise the IE will be + * appended at `aIndex` on input. And on output, `aIndex` will be set to the end of the + * IE just appended. * - * @retval OT_ERROR_NONE Successfully appended the Header IEs. - * @retval OT_ERROR_FAILED If IE Present bit is not set. + * @tparam IeType The Header IE type, it MUST contain an enum `kHeaderIeId` equal to the IE's Id + * and an enum `kIeContentSize` indicating the IE body's size. + * + * @retval OT_ERROR_NONE Successfully appended the Header IE. + * @retval OT_ERROR_NOT_FOUND The position for first IE is not found. * */ - otError AppendHeaderIe(HeaderIe *aIeList, uint8_t aIeCount); + template otError AppendHeaderIeAt(uint8_t &aIndex); /** * This method returns a pointer to the Header IE. @@ -1091,6 +1120,9 @@ protected: uint8_t FindPayloadIndex(void) const; #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT uint8_t FindHeaderIeIndex(void) const; + + otError InitIeHeaderAt(uint8_t &aIndex, uint8_t ieId, uint8_t ieContentSize); + template void InitIeContentAt(uint8_t &aIndex); #endif static uint8_t GetKeySourceLength(uint8_t aKeyIdMode); @@ -1642,6 +1674,12 @@ OT_TOOL_PACKED_BEGIN class CslIe { public: + enum : uint8_t + { + kHeaderIeId = 0x1a, + kIeContentSize = sizeof(uint16_t) * 2, + }; + /** * This method returns the CSL Period. * @@ -1679,6 +1717,22 @@ private: uint16_t mPeriod; } OT_TOOL_PACKED_END; +/** + * This class implements Termination2 IE. + * + * This class is empty for template specialization. + * + */ +class Termination2Ie +{ +public: + enum : uint8_t + { + kHeaderIeId = 0x7f, + kIeContentSize = 0, + }; +}; + /** * @} * diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index fe66949cb..cf88b6fc5 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -154,7 +154,8 @@ exit: void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &aMacDest, bool aAckRequest) { - uint16_t fcf = 0; + uint16_t fcf = 0; + bool iePresent = CalcIePresent(nullptr); Mac::Address macSource; macSource.SetShort(Get().GetShortAddress()); @@ -166,6 +167,13 @@ void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address & fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfSecurityEnabled; + if (iePresent) + { + fcf |= Mac::Frame::kFcfIePresent; + } + + fcf |= CalcFrameVersion(Get().FindNeighbor(aMacDest), iePresent); + if (aAckRequest) { fcf |= Mac::Frame::kFcfAckRequest; @@ -173,7 +181,6 @@ void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address & fcf |= (aMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt; fcf |= (macSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt; - Get().UpdateFrameControlField(Get().FindNeighbor(aMacDest), false, fcf); aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32); @@ -187,7 +194,10 @@ void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address & aFrame.SetSrcAddr(macSource); aFrame.SetFramePending(false); #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - IgnoreError(Get().AppendHeaderIe(false, aFrame)); + if (iePresent) + { + AppendHeaderIe(nullptr, aFrame); + } #endif aFrame.SetPayloadLength(0); } @@ -585,17 +595,23 @@ uint16_t MeshForwarder::PrepareDataFrame(Mac::TxFrame & aFrame, uint16_t dstpan; uint8_t secCtl; uint16_t nextOffset; + bool iePresent = CalcIePresent(&aMessage); start: // Initialize MAC header fcf = Mac::Frame::kFcfFrameData; - Get().UpdateFrameControlField(Get().FindNeighbor(aMacDest), aMessage.IsTimeSync(), fcf); - fcf |= (aMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt; fcf |= (aMacSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt; + if (iePresent) + { + fcf |= Mac::Frame::kFcfIePresent; + } + + fcf |= CalcFrameVersion(Get().FindNeighbor(aMacDest), iePresent); + // All unicast frames request ACK if (aMacDest.IsExtended() || !aMacDest.IsBroadcast()) { @@ -663,7 +679,10 @@ start: aFrame.SetSrcAddr(aMacSource); #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - IgnoreError(Get().AppendHeaderIe(aMessage.IsTimeSync(), aFrame)); + if (iePresent) + { + AppendHeaderIe(&aMessage, aFrame); + } #endif payload = aFrame.GetPayload(); @@ -1491,6 +1510,78 @@ exit: } #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +bool MeshForwarder::CalcIePresent(const Message *aMessage) +{ + bool iePresent = false; + + OT_UNUSED_VARIABLE(aMessage); + +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + iePresent |= (aMessage != nullptr && aMessage->IsTimeSync()); +#endif +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + iePresent |= Get().IsCslEnabled(); +#endif + + return iePresent; +} + +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +void MeshForwarder::AppendHeaderIe(const Message *aMessage, Mac::Frame &aFrame) +{ + uint8_t index = 0; + bool iePresent = false; + + OT_UNUSED_VARIABLE(aMessage); + +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + if (aMessage != nullptr && aMessage->IsTimeSync()) + { + IgnoreError(aFrame.AppendHeaderIeAt(index)); + iePresent = true; + } +#endif +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + if (Get().IsCslEnabled()) + { + IgnoreError(aFrame.AppendHeaderIeAt(index)); + iePresent = true; + } +#endif + + if (iePresent) + { + IgnoreError(aFrame.AppendHeaderIeAt(index)); + } +} +#endif + +uint16_t MeshForwarder::CalcFrameVersion(const Neighbor *aNeighbor, bool aIePresent) +{ + uint16_t version = Mac::Frame::kFcfFrameVersion2006; + OT_UNUSED_VARIABLE(aNeighbor); + + if (aIePresent) + { + version = Mac::Frame::kFcfFrameVersion2015; + } +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE + else if (aNeighbor != nullptr && !Mle::MleRouter::IsActiveRouter(aNeighbor->GetRloc16()) && + static_cast(aNeighbor)->IsCslSynchronized()) + { + version = Mac::Frame::kFcfFrameVersion2015; + } +#endif +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE + else if (aNeighbor != nullptr && aNeighbor->IsEnhAckProbingActive()) + { + version = Mac::Frame::kFcfFrameVersion2015; ///< Set version to 2015 to fetch Link Metrics data in Enh-ACK. + } +#endif + + return version; +} + // LCOV_EXCL_START #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 5a85bb9e1..152d1b8c4 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -44,6 +44,7 @@ #include "mac/channel_mask.hpp" #include "mac/data_poll_sender.hpp" #include "mac/mac.hpp" +#include "mac/mac_frame.hpp" #include "net/ip6.hpp" #include "thread/address_resolver.hpp" #include "thread/indirect_sender.hpp" @@ -475,6 +476,12 @@ private: otError GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest); + bool CalcIePresent(const Message *aMessage); + uint16_t CalcFrameVersion(const Neighbor *aNeighbor, bool aIePresent); +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT + void AppendHeaderIe(const Message *aMessage, Mac::Frame &aFrame); +#endif + void PauseMessageTransmissions(void) { mTxPaused = true; } void ResumeMessageTransmissions(void); diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 4d873165b..fa1b335b8 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -342,29 +342,28 @@ void MeshForwarder::RemoveDataResponseMessages(void) void MeshForwarder::SendMesh(Message &aMessage, Mac::TxFrame &aFrame) { uint16_t fcf; + bool iePresent = CalcIePresent(&aMessage); // initialize MAC header fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfAckRequest | Mac::Frame::kFcfSecurityEnabled; - Get().UpdateFrameControlField(nullptr, aMessage.IsTimeSync(), fcf); + + if (iePresent) + { + fcf |= Mac::Frame::kFcfIePresent; + } + + fcf |= CalcFrameVersion(Get().FindNeighbor(mMacDest), iePresent); aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32); aFrame.SetDstPanId(Get().GetPanId()); aFrame.SetDstAddr(mMacDest.GetShort()); aFrame.SetSrcAddr(mMacSource.GetShort()); -#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (Get().IsCslEnabled()) +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT + if (iePresent) { - Mac::HeaderIe ieList[2]; // CSL + Termination - - ieList[0].Init(); - ieList[0].SetId(Mac::Frame::kHeaderIeCsl); - ieList[0].SetLength(sizeof(Mac::CslIe)); - ieList[1].Init(); - ieList[1].SetId(Mac::Frame::kHeaderIeTermination2); - ieList[1].SetLength(0); - IgnoreError(aFrame.AppendHeaderIe(ieList, 2)); + AppendHeaderIe(&aMessage, aFrame); } #endif diff --git a/tests/unit/test_mac_frame.cpp b/tests/unit/test_mac_frame.cpp index ef6102bb0..12609e873 100644 --- a/tests/unit/test_mac_frame.cpp +++ b/tests/unit/test_mac_frame.cpp @@ -620,7 +620,7 @@ void TestMacFrameAckGeneration(void) Mac::CslIe *csl; IgnoreError(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data))); - csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::Frame::kHeaderIeCsl) + sizeof(Mac::HeaderIe)); + csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe)); VerifyOrQuit(ackFrame.mLength == 23, "Mac::Frame::GenerateEnhAck() failed, length incorrect\n"); // 23 is the length of the correct ack VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kFcfFrameAck, @@ -642,7 +642,7 @@ void TestMacFrameAckGeneration(void) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE ackFrame.SetCslIe(123, 456); - csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::Frame::kHeaderIeCsl) + sizeof(Mac::HeaderIe)); + csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe)); VerifyOrQuit(csl->GetPeriod() == 123 && csl->GetPhase() == 456, "Mac::Frame::SetCslIe failed, CslIe incorrect\n"); #endif #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)