From e219fe92f15097b40f04e846ff4d56dea3643395 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Sat, 3 Aug 2024 00:50:45 +0800 Subject: [PATCH] [mac] support frames without sequence number (#10544) This commit adds the capability to support frames without sequence number. --- examples/platforms/simulation/radio.c | 6 ++- examples/platforms/utils/mac_frame.cpp | 16 ++++++- examples/platforms/utils/mac_frame.h | 6 ++- src/core/mac/mac_frame.cpp | 55 +++++++++++++++++++---- src/core/mac/mac_frame.hpp | 62 ++++++++++++++++++-------- tests/fuzz/fuzzer_platform.cpp | 21 +++++++-- tests/unit/test_mac_frame.cpp | 30 ++++++++++--- 7 files changed, 155 insertions(+), 41 deletions(-) diff --git a/examples/platforms/simulation/radio.c b/examples/platforms/simulation/radio.c index 960d8c66c..9e547e1c2 100644 --- a/examples/platforms/simulation/radio.c +++ b/examples/platforms/simulation/radio.c @@ -606,7 +606,11 @@ static void radioReceive(otInstance *aInstance) { if (otMacFrameIsAckRequested(&sTransmitFrame)) { - isTxDone = isAck && otMacFrameGetSequence(&sReceiveFrame) == otMacFrameGetSequence(&sTransmitFrame); + uint8_t rxSeq; + uint8_t txSeq; + + isTxDone = isAck && otMacFrameGetSequence(&sReceiveFrame, &rxSeq) == OT_ERROR_NONE && + otMacFrameGetSequence(&sTransmitFrame, &txSeq) == OT_ERROR_NONE && rxSeq == txSeq; } #if OPENTHREAD_SIMULATION_VIRTUAL_TIME // Simulate tx done when receiving the echo frame. diff --git a/examples/platforms/utils/mac_frame.cpp b/examples/platforms/utils/mac_frame.cpp index 36a1c975c..98ea21736 100644 --- a/examples/platforms/utils/mac_frame.cpp +++ b/examples/platforms/utils/mac_frame.cpp @@ -139,9 +139,21 @@ exit: return error; } -uint8_t otMacFrameGetSequence(const otRadioFrame *aFrame) +otError otMacFrameGetSequence(const otRadioFrame *aFrame, uint8_t *aSequence) { - return static_cast(aFrame)->GetSequence(); + otError error; + + if (static_cast(aFrame)->IsSequencePresent()) + { + *aSequence = static_cast(aFrame)->GetSequence(); + error = kErrorNone; + } + else + { + error = kErrorParse; + } + + return error; } void otMacFrameProcessTransmitAesCcm(otRadioFrame *aFrame, const otExtAddress *aExtAddress) diff --git a/examples/platforms/utils/mac_frame.h b/examples/platforms/utils/mac_frame.h index 5fba6ecea..adbed43f2 100644 --- a/examples/platforms/utils/mac_frame.h +++ b/examples/platforms/utils/mac_frame.h @@ -169,11 +169,13 @@ otError otMacFrameGetDstAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddre * Get the sequence of @p aFrame. * * @param[in] aFrame A pointer to the frame. + * @param[out] aSequence A pointer to the sequence. * - * @returns The sequence of the frame. + * @retval OT_ERROR_NONE Successfully got the sequence. + * @retval OT_ERROR_PARSE Failed to parse the sequence. * */ -uint8_t otMacFrameGetSequence(const otRadioFrame *aFrame); +otError otMacFrameGetSequence(const otRadioFrame *aFrame, uint8_t *aSequence); /** * Performs AES CCM on the frame which is going to be sent. diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index 9946bb2c7..035319b27 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -59,7 +59,8 @@ void Frame::InitMacHeader(Type aType, const Addresses &aAddrs, const PanIds &aPanIds, SecurityLevel aSecurityLevel, - KeyIdMode aKeyIdMode) + KeyIdMode aKeyIdMode, + bool aSuppressSequence) { uint16_t fcf; FrameBuilder builder; @@ -124,6 +125,9 @@ void Frame::InitMacHeader(Type aType, { fcf |= kFcfPanidCompression; } + + // Sequence Number Suppression bit was reserved, and must not be set on initialization. + OT_ASSERT(!aSuppressSequence); break; case kVersion2015: @@ -194,9 +198,18 @@ void Frame::InitMacHeader(Type aType, break; } + if (aSuppressSequence) + { + fcf |= kFcfSequenceSupression; + } + builder.Init(mPsdu, GetMtu()); IgnoreError(builder.AppendLittleEndianUint16(fcf)); - IgnoreError(builder.AppendUint8(0)); // Seq number + + if (!IsSequenceSuppressed(fcf)) + { + IgnoreError(builder.AppendUint8(0)); // Seq number + } if (IsDstPanIdPresent(fcf)) { @@ -294,7 +307,7 @@ uint8_t Frame::FindDstPanIdIndex(void) const VerifyOrExit(IsDstPanIdPresent(), index = kInvalidIndex); - index = kFcfSize + kDsnSize; + index = kFcfSize + GetSeqNumSize(); exit: return index; @@ -373,7 +386,22 @@ void Frame::SetDstPanId(PanId aPanId) LittleEndian::WriteUint16(aPanId, &mPsdu[index]); } -uint8_t Frame::FindDstAddrIndex(void) const { return kFcfSize + kDsnSize + (IsDstPanIdPresent() ? sizeof(PanId) : 0); } +uint8_t Frame::GetSequence(void) const +{ + OT_ASSERT(IsSequencePresent()); + return GetPsdu()[kSequenceIndex]; +} + +void Frame::SetSequence(uint8_t aSequence) +{ + OT_ASSERT(IsSequencePresent()); + GetPsdu()[kSequenceIndex] = aSequence; +} + +uint8_t Frame::FindDstAddrIndex(void) const +{ + return kFcfSize + GetSeqNumSize() + (IsDstPanIdPresent() ? sizeof(PanId) : 0); +} Error Frame::GetDstAddr(Address &aAddress) const { @@ -442,7 +470,7 @@ uint8_t Frame::FindSrcPanIdIndex(void) const VerifyOrExit(IsSrcPanIdPresent(), index = kInvalidIndex); - index += kFcfSize + kDsnSize; + index += kFcfSize + GetSeqNumSize(); if (IsDstPanIdPresent(fcf)) { @@ -533,7 +561,7 @@ uint8_t Frame::FindSrcAddrIndex(void) const uint8_t index = 0; uint16_t fcf = GetFrameControlField(); - index += kFcfSize + kDsnSize; + index += kFcfSize + GetSeqNumSize(); if (IsDstPanIdPresent(fcf)) { @@ -941,7 +969,9 @@ uint8_t Frame::SkipAddrFieldIndex(void) const { uint8_t index; - VerifyOrExit(kFcfSize + kDsnSize + GetFcsSize() <= mLength, index = kInvalidIndex); + VerifyOrExit(kFcfSize + GetFcsSize() <= mLength, index = kInvalidIndex); + + VerifyOrExit(!IsSequencePresent() || kFcfSize + kDsnSize + GetFcsSize() <= mLength, index = kInvalidIndex); index = CalculateAddrFieldSize(GetFrameControlField()); @@ -951,7 +981,7 @@ exit: uint8_t Frame::CalculateAddrFieldSize(uint16_t aFcf) { - uint8_t size = kFcfSize + kDsnSize; + uint8_t size = kFcfSize + GetSeqNumSize(aFcf); // This static method calculates the size (number of bytes) of // Address header field for a given Frame Control `aFcf` value. @@ -1538,7 +1568,14 @@ Frame::InfoString Frame::ToInfoString(void) const uint8_t commandId, type; Address src, dst; - string.Append("len:%d, seqnum:%d, type:", mLength, GetSequence()); + if (IsSequencePresent()) + { + string.Append("len:%d, seqnum:%d, type:", mLength, GetSequence()); + } + else + { + string.Append("len:%d, type:", mLength); + } type = GetType(); diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index a515ddc13..eef63aae4 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -386,6 +386,7 @@ public: * @param[in] aPanIds Source and destination PAN IDs. * @param[in] aSecurityLevel Frame security level. * @param[in] aKeyIdMode Frame security key ID mode. + * @param[in] aSuppressSequence Whether to suppress sequence number. * */ void InitMacHeader(Type aType, @@ -393,7 +394,8 @@ public: const Addresses &aAddrs, const PanIds &aPanIds, SecurityLevel aSecurityLevel, - KeyIdMode aKeyIdMode = kKeyIdMode0); + KeyIdMode aKeyIdMode = kKeyIdMode0, + bool aSuppressSequence = false); /** * Validates the frame. @@ -512,7 +514,7 @@ public: * @returns The Sequence Number value. * */ - uint8_t GetSequence(void) const { return GetPsdu()[kSequenceIndex]; } + uint8_t GetSequence(void) const; /** * Sets the Sequence Number value. @@ -520,7 +522,24 @@ public: * @param[in] aSequence The Sequence Number value. * */ - void SetSequence(uint8_t aSequence) { GetPsdu()[kSequenceIndex] = aSequence; } + void SetSequence(uint8_t aSequence); + + /** + * Indicates whether or not the Sequence Number is present. + * + * @returns TRUE if the Sequence Number is present, FALSE otherwise. + * + */ + uint8_t IsSequencePresent(void) const { return !IsSequenceSuppressed(GetFrameControlField()); } + + /** + * Get the size of the sequence number. + * + * @retval 0 The size of sequence number is 0, indicating it's not present. + * @retval 1 The size of sequence number is 1, indicating it's present. + * + */ + uint8_t GetSeqNumSize(void) const { return GetSeqNumSize(GetFrameControlField()); } /** * Indicates whether or not the Destination PAN ID is present. @@ -1089,21 +1108,22 @@ protected: static constexpr uint8_t kCommandIdSize = sizeof(uint8_t); static constexpr uint8_t kKeyIndexSize = sizeof(uint8_t); - static constexpr uint16_t kFcfFrameTypeMask = 7 << 0; - static constexpr uint16_t kFcfSecurityEnabled = 1 << 3; - static constexpr uint16_t kFcfFramePending = 1 << 4; - static constexpr uint16_t kFcfAckRequest = 1 << 5; - static constexpr uint16_t kFcfPanidCompression = 1 << 6; - static constexpr uint16_t kFcfIePresent = 1 << 9; - static constexpr uint16_t kFcfDstAddrNone = 0 << 10; - static constexpr uint16_t kFcfDstAddrShort = 2 << 10; - static constexpr uint16_t kFcfDstAddrExt = 3 << 10; - static constexpr uint16_t kFcfDstAddrMask = 3 << 10; - static constexpr uint16_t kFcfFrameVersionMask = 3 << 12; - static constexpr uint16_t kFcfSrcAddrNone = 0 << 14; - static constexpr uint16_t kFcfSrcAddrShort = 2 << 14; - static constexpr uint16_t kFcfSrcAddrExt = 3 << 14; - static constexpr uint16_t kFcfSrcAddrMask = 3 << 14; + static constexpr uint16_t kFcfFrameTypeMask = 7 << 0; + static constexpr uint16_t kFcfSecurityEnabled = 1 << 3; + static constexpr uint16_t kFcfFramePending = 1 << 4; + static constexpr uint16_t kFcfAckRequest = 1 << 5; + static constexpr uint16_t kFcfPanidCompression = 1 << 6; + static constexpr uint16_t kFcfSequenceSupression = 1 << 8; + static constexpr uint16_t kFcfIePresent = 1 << 9; + static constexpr uint16_t kFcfDstAddrNone = 0 << 10; + static constexpr uint16_t kFcfDstAddrShort = 2 << 10; + static constexpr uint16_t kFcfDstAddrExt = 3 << 10; + static constexpr uint16_t kFcfDstAddrMask = 3 << 10; + static constexpr uint16_t kFcfFrameVersionMask = 3 << 12; + static constexpr uint16_t kFcfSrcAddrNone = 0 << 14; + static constexpr uint16_t kFcfSrcAddrShort = 2 << 14; + static constexpr uint16_t kFcfSrcAddrExt = 3 << 14; + static constexpr uint16_t kFcfSrcAddrMask = 3 << 14; static constexpr uint8_t kSecLevelMask = 7 << 0; static constexpr uint8_t kKeyIdModeMask = 3 << 3; @@ -1144,6 +1164,12 @@ protected: static bool IsDstAddrPresent(uint16_t aFcf) { return (aFcf & kFcfDstAddrMask) != kFcfDstAddrNone; } static bool IsDstPanIdPresent(uint16_t aFcf); + static bool IsSequenceSuppressed(uint16_t aFcf) + { + return (aFcf & (kFcfSequenceSupression | kFcfFrameVersionMask)) == (kFcfSequenceSupression | kVersion2015); + } + static uint8_t GetSeqNumSize(uint16_t aFcf) { return !IsSequenceSuppressed(aFcf) ? kDsnSize : 0; } + static bool IsSrcAddrPresent(uint16_t aFcf) { return (aFcf & kFcfSrcAddrMask) != kFcfSrcAddrNone; } static bool IsSrcPanIdPresent(uint16_t aFcf); static bool IsVersion2015(uint16_t aFcf) { return (aFcf & kFcfFrameVersionMask) == kVersion2015; } diff --git a/tests/fuzz/fuzzer_platform.cpp b/tests/fuzz/fuzzer_platform.cpp index 524760954..906f86b09 100644 --- a/tests/fuzz/fuzzer_platform.cpp +++ b/tests/fuzz/fuzzer_platform.cpp @@ -77,9 +77,21 @@ bool otMacFrameIsAckRequested(const otRadioFrame *aFrame) return static_cast(aFrame)->GetAckRequest(); } -uint8_t otMacFrameGetSequence(const otRadioFrame *aFrame) +otError otMacFrameGetSequence(const otRadioFrame *aFrame, uint8_t *aSequence) { - return static_cast(aFrame)->GetSequence(); + otError error; + + if (static_cast(aFrame)->IsSequencePresent()) + { + *aSequence = static_cast(aFrame)->GetSequence(); + error = kErrorNone; + } + else + { + error = kErrorParse; + } + + return error; } void FuzzerPlatformInit(void) @@ -101,10 +113,13 @@ void FuzzerPlatformProcess(otInstance *aInstance) if (otMacFrameIsAckRequested(&sRadioTransmitFrame)) { + otError error; + sRadioAckFrame.mLength = IEEE802154_ACK_LENGTH; sRadioAckFrame.mPsdu[0] = IEEE802154_FRAME_TYPE_ACK; sRadioAckFrame.mPsdu[1] = 0; - sRadioAckFrame.mPsdu[2] = otMacFrameGetSequence(&sRadioTransmitFrame); + error = otMacFrameGetSequence(&sRadioTransmitFrame, &sRadioAckFrame.mPsdu[2]); + OT_ASSERT(error == OT_ERROR_NONE); sRadioAckFrame.mChannel = sRadioTransmitFrame.mChannel; otPlatRadioTxDone(aInstance, &sRadioTransmitFrame, &sRadioAckFrame, OT_ERROR_NONE); diff --git a/tests/unit/test_mac_frame.cpp b/tests/unit/test_mac_frame.cpp index 722b41aa4..cf7e29603 100644 --- a/tests/unit/test_mac_frame.cpp +++ b/tests/unit/test_mac_frame.cpp @@ -205,6 +205,7 @@ void TestMacHeader(void) Mac::Frame::KeyIdMode mKeyIdMode; uint8_t mHeaderLength; uint8_t mFooterLength; + bool mSuppressSequence; }; static constexpr Mac::Frame::Version kVer2006 = Mac::Frame::kVersion2006; @@ -265,6 +266,7 @@ void TestMacHeader(void) {kVer2015, kExtdAddr, kNoPanId, kNoneAddr, kNoPanId, kMic32, kModeId1, 17, 6}, {kVer2015, kExtdAddr, kNoPanId, kExtdAddr, kNoPanId, kNoSec, kModeId1, 19, 2}, {kVer2015, kExtdAddr, kNoPanId, kExtdAddr, kNoPanId, kMic32, kModeId1, 25, 6}, + {kVer2015, kExtdAddr, kNoPanId, kExtdAddr, kNoPanId, kMic32, kModeId1, 24, 6, true}, }; const uint16_t kPanId1 = 0xbaba; @@ -285,7 +287,9 @@ void TestMacHeader(void) for (const TestCase &testCase : kTestCases) { - uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE]; + uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE]; + uint8_t offset; + Mac::TxFrame frame; Mac::Addresses addresses; Mac::Address address; @@ -352,7 +356,7 @@ void TestMacHeader(void) } frame.InitMacHeader(Mac::Frame::kTypeData, testCase.mVersion, addresses, panIds, testCase.mSecurity, - testCase.mKeyIdMode); + testCase.mKeyIdMode, testCase.mSuppressSequence); VerifyOrQuit(frame.GetHeaderLength() == testCase.mHeaderLength); VerifyOrQuit(frame.GetFooterLength() == testCase.mFooterLength); @@ -401,11 +405,20 @@ void TestMacHeader(void) VerifyOrQuit(keyIdMode == testCase.mKeyIdMode); } - snprintf(string, sizeof(string), "\nver:%s, src[addr:%s, pan:%s], dst[addr:%s, pan:%s], sec:%s", - (testCase.mVersion == kVer2006) ? "2006" : "2015", kAddrTypeStrings[testCase.mSrcAddrType], - kPanIdModeStrings[testCase.mSrcPanIdMode], kAddrTypeStrings[testCase.mDstAddrType], - kPanIdModeStrings[testCase.mDstPanIdMode], testCase.mSecurity == kNoSec ? "no" : "mic32"); + offset = snprintf(string, sizeof(string), "\nver:%s, src[addr:%s, pan:%s], dst[addr:%s, pan:%s], sec:%s", + (testCase.mVersion == kVer2006) ? "2006" : "2015", kAddrTypeStrings[testCase.mSrcAddrType], + kPanIdModeStrings[testCase.mSrcPanIdMode], kAddrTypeStrings[testCase.mDstAddrType], + kPanIdModeStrings[testCase.mDstPanIdMode], testCase.mSecurity == kNoSec ? "no" : "mic32"); + if (!testCase.mSuppressSequence) + { + VerifyOrQuit(frame.IsSequencePresent()); + offset += snprintf(string + offset, sizeof(string) - offset, ", seq:%u", frame.GetSequence()); + } + else + { + VerifyOrQuit(!frame.IsSequencePresent()); + } DumpBuffer(string, frame.GetPsdu(), frame.GetLength()); } } @@ -590,6 +603,7 @@ void TestMacFrameApi(void) VerifyOrQuit(!frame.IsDstAddrPresent()); VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006); VerifyOrQuit(!frame.IsSrcAddrPresent()); + VerifyOrQuit(frame.IsSequencePresent()); VerifyOrQuit(frame.GetSequence() == 94); #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) @@ -619,6 +633,7 @@ void TestMacFrameApi(void) 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); @@ -637,6 +652,7 @@ 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); @@ -700,6 +716,7 @@ void TestMacFrameAckGeneration(void) VerifyOrQuit(!ackFrame.IsDstAddrPresent()); VerifyOrQuit(!ackFrame.IsSrcAddrPresent()); VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2006); + VerifyOrQuit(ackFrame.IsSequencePresent()); VerifyOrQuit(ackFrame.GetSequence() == 189); #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) @@ -758,6 +775,7 @@ void TestMacFrameAckGeneration(void) VerifyOrQuit(ackFrame.IsDstAddrPresent()); VerifyOrQuit(!ackFrame.IsSrcAddrPresent()); VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2015); + VerifyOrQuit(ackFrame.IsSequencePresent()); VerifyOrQuit(ackFrame.GetSequence() == 142); VerifyOrQuit(csl->GetPeriod() == 3125 && csl->GetPhase() == 3105);