diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index 7c54f288f..3e26a6ba8 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -239,6 +239,8 @@ void Frame::InitMacHeader(Type aType, uint16_t Frame::GetFrameControlField(void) const { return ReadUint16(mPsdu); } +void Frame::SetFrameControlField(uint16_t aFcf) { WriteUint16(aFcf, mPsdu); } + Error Frame::ValidatePsdu(void) const { Error error = kErrorNone; @@ -275,6 +277,22 @@ void Frame::SetFramePending(bool aFramePending) } } +void Frame::SetIePresent(bool aIePresent) +{ + uint16_t fcf = GetFrameControlField(); + + if (aIePresent) + { + fcf |= kFcfIePresent; + } + else + { + fcf &= ~kFcfIePresent; + } + + SetFrameControlField(fcf); +} + uint8_t Frame::FindDstPanIdIndex(void) const { uint8_t index; @@ -1090,7 +1108,7 @@ Error Frame::InitIeHeaderAt(uint8_t &aIndex, uint8_t ieId, uint8_t ieContentSize { Error error = kErrorNone; - WriteUint16(GetFrameControlField() | kFcfIePresent, mPsdu); + SetIePresent(true); if (aIndex == 0) { @@ -1386,115 +1404,80 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending) } #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 -Error TxFrame::GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength) +Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength) { - Error error = kErrorNone; + Error error = kErrorNone; + Address address; + PanId panId; + Addresses addrs; + PanIds panIds; + uint8_t securityLevel = kSecurityNone; + uint8_t keyIdMode = kKeyIdMode0; - uint16_t fcf; - Address address; - PanId panId; - uint8_t footerLength; - uint8_t securityControlField; - uint8_t keyId; + // Validate the received frame. - fcf = static_cast(kTypeAck) | static_cast(kVersion2015) | kFcfSrcAddrNone; + VerifyOrExit(aRxFrame.IsVersion2015(), error = kErrorParse); + VerifyOrExit(aRxFrame.GetAckRequest(), error = kErrorParse); - mChannel = aFrame.mChannel; + // Check `aRxFrame` has a valid destination address. The ack frame + // will not use this as its source though and will always use no + // source address. + + SuccessOrExit(error = aRxFrame.GetDstAddr(address)); + VerifyOrExit(!address.IsNone() && !address.IsBroadcast(), error = kErrorParse); + + // Check `aRxFrame` has a valid source, which is then used as + // ack frames destination. + + SuccessOrExit(error = aRxFrame.GetSrcAddr(addrs.mDestination)); + VerifyOrExit(!addrs.mDestination.IsNone(), error = kErrorParse); + + if (aRxFrame.GetSecurityEnabled()) + { + SuccessOrExit(error = aRxFrame.GetSecurityLevel(securityLevel)); + VerifyOrExit(securityLevel == kSecurityEncMic32, error = kErrorParse); + + SuccessOrExit(error = aRxFrame.GetKeyIdMode(keyIdMode)); + } + + if (aRxFrame.IsSrcPanIdPresent()) + { + SuccessOrExit(error = aRxFrame.GetSrcPanId(panId)); + panIds.SetDestination(panId); + } + else if (aRxFrame.IsDstPanIdPresent()) + { + SuccessOrExit(error = aRxFrame.GetDstPanId(panId)); + panIds.SetDestination(panId); + } + + // Prepare the ack frame + + mChannel = aRxFrame.mChannel; memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo)); - // Set frame control field - if (aIsFramePending) + InitMacHeader(kTypeAck, kVersion2015, addrs, panIds, static_cast(securityLevel), + static_cast(keyIdMode)); + + SetFramePending(aIsFramePending); + SetIePresent(aIeLength != 0); + SetSequence(aRxFrame.GetSequence()); + + if (aRxFrame.GetSecurityEnabled()) { - fcf |= kFcfFramePending; - } + uint8_t keyId; - if (aFrame.GetSecurityEnabled()) - { - fcf |= kFcfSecurityEnabled; - } - - if (aFrame.IsPanIdCompressed()) - { - fcf |= kFcfPanidCompression; - } - - // Destination address mode - if ((aFrame.GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrExt) - { - fcf |= kFcfDstAddrExt; - } - else if ((aFrame.GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrShort) - { - fcf |= kFcfDstAddrShort; - } - else - { - fcf |= kFcfDstAddrNone; - } - - if (aIeLength > 0) - { - fcf |= kFcfIePresent; - } - - WriteUint16(fcf, mPsdu); - - // Set sequence number - mPsdu[kSequenceIndex] = aFrame.GetSequence(); - - if (IsDstPanIdPresent()) - { - // Set address field - if (aFrame.IsSrcPanIdPresent()) - { - SuccessOrExit(error = aFrame.GetSrcPanId(panId)); - } - else if (aFrame.IsDstPanIdPresent()) - { - SuccessOrExit(error = aFrame.GetDstPanId(panId)); - } - else - { - ExitNow(error = kErrorParse); - } - - SetDstPanId(panId); - } - - if (aFrame.IsSrcAddrPresent()) - { - SuccessOrExit(error = aFrame.GetSrcAddr(address)); - SetDstAddr(address); - } - - // At this time the length of ACK hasn't been determined, set it to - // `kMaxPsduSize` to call methods that check frame length - mLength = kMaxPsduSize; - - // Set security header - if (aFrame.GetSecurityEnabled()) - { - SuccessOrExit(error = aFrame.GetSecurityControlField(securityControlField)); - SuccessOrExit(error = aFrame.GetKeyId(keyId)); - - VerifyOrExit((securityControlField & kSecLevelMask) == kSecurityEncMic32, error = kErrorParse); - - SetSecurityControlField(securityControlField); + SuccessOrExit(error = aRxFrame.GetKeyId(keyId)); SetKeyId(keyId); } - // Set header IE if (aIeLength > 0) { OT_ASSERT(aIeData != nullptr); memcpy(&mPsdu[FindHeaderIeIndex()], aIeData, aIeLength); + mLength += aIeLength; } - // Set frame length - footerLength = GetFooterLength(); - OT_ASSERT(footerLength != kInvalidIndex); - mLength = SkipSecurityHeaderIndex() + aIeLength + footerLength; - exit: return error; } diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index 4b3eb81f2..247d11409 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -504,6 +504,14 @@ public: */ bool IsIePresent(void) const { return (GetFrameControlField() & kFcfIePresent) != 0; } + /** + * Sets the IE Present bit. + * + * @param[in] aIePresent The IE Present bit. + * + */ + void SetIePresent(bool aIePresent); + /** * Returns the Sequence Number value. * @@ -1122,6 +1130,7 @@ protected: static constexpr uint8_t kMaxPsduSize = kInvalidSize - 1; static constexpr uint8_t kSequenceIndex = kFcfSize; + void SetFrameControlField(uint16_t aFcf); uint8_t FindDstPanIdIndex(void) const; uint8_t FindDstAddrIndex(void) const; uint8_t FindSrcPanIdIndex(void) const; @@ -1148,8 +1157,6 @@ protected: static uint8_t CalculateAddrFieldSize(uint16_t aFcf); static uint8_t CalculateSecurityHeaderSize(uint8_t aSecurityControl); static uint8_t CalculateMicSize(uint8_t aSecurityControl); - -public: }; /** @@ -1502,16 +1509,16 @@ public: /** * Generate Enh-Ack in this frame object. * - * @param[in] aFrame A reference to the frame received. + * @param[in] aRxFrame A reference to the received frame. * @param[in] aIsFramePending Value of the ACK's frame pending bit. * @param[in] aIeData A pointer to the IE data portion of the ACK to be sent. * @param[in] aIeLength The length of IE data portion of the ACK to be sent. * * @retval kErrorNone Successfully generated Enh Ack. - * @retval kErrorParse @p aFrame has incorrect format. + * @retval kErrorParse @p aRxFrame has incorrect format. * */ - Error GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength); + Error GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength); #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 /** diff --git a/tests/unit/test_mac_frame.cpp b/tests/unit/test_mac_frame.cpp index 714371af7..db6ebb1b9 100644 --- a/tests/unit/test_mac_frame.cpp +++ b/tests/unit/test_mac_frame.cpp @@ -747,13 +747,14 @@ void TestMacFrameAckGeneration(void) uint8_t ie_data[6] = {0x04, 0x0d, 0x21, 0x0c, 0x35, 0x0c}; Mac::CslIe *csl; - IgnoreError(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data))); + SuccessOrQuit(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data))); + csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe)); - VerifyOrQuit(ackFrame.mLength == 23); + VerifyOrQuit(ackFrame.mLength == 25); VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck); VerifyOrQuit(ackFrame.GetSecurityEnabled()); VerifyOrQuit(ackFrame.IsIePresent()); - VerifyOrQuit(!ackFrame.IsDstPanIdPresent()); + VerifyOrQuit(ackFrame.IsDstPanIdPresent()); VerifyOrQuit(ackFrame.IsDstAddrPresent()); VerifyOrQuit(!ackFrame.IsSrcAddrPresent()); VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2015);