From cd9558ca91950dd5af012d6069e8b12cab3d2605 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 13 May 2020 13:20:03 +0800 Subject: [PATCH] [mac-frame] add util functions to generate ack (#4884) This commit adds mac frame util functions to generate acks (both Imm and Enh acks) from a received frame. These funtions are utils APIs for platforms which don't provide ack generation. This commit also introduces compile options for CSL to control the CSL IE related part. --- .github/workflows/simulation.yml | 1 + etc/cmake/options.cmake | 5 + examples/common-switches.mk | 4 + examples/platforms/utils/mac_frame.cpp | 34 ++++ examples/platforms/utils/mac_frame.h | 50 ++++++ script/test | 6 + src/core/config/mac.h | 25 ++- .../config/openthread-core-config-check.h | 15 ++ src/core/mac/mac_frame.cpp | 145 ++++++++++++++++++ src/core/mac/mac_frame.hpp | 105 ++++++++++++- tests/unit/test_mac_frame.cpp | 131 +++++++++++++++- 11 files changed, 518 insertions(+), 3 deletions(-) diff --git a/.github/workflows/simulation.yml b/.github/workflows/simulation.yml index af6a6aa12..5c7b9170a 100644 --- a/.github/workflows/simulation.yml +++ b/.github/workflows/simulation.yml @@ -423,6 +423,7 @@ jobs: ./script/test build - name: Run run: | + ./script/test unit ./script/test cert_suite tests/scripts/thread-cert/v1_2_* - name: Codecov uses: codecov/codecov-action@v1 diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 129386781..6ce127ac0 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -86,6 +86,11 @@ if(OT_COMMISSIONER) list(APPEND OT_PRIVATE_DEFINES "OPENTHREAD_CONFIG_COMMISSIONER_ENABLE=1") endif() +option(OT_CSL_RECEIVER "enable csl receiver") +if(OT_CSL_RECEIVER) + list(APPEND OT_PRIVATE_DEFINES "OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE=1") +endif() + option(OT_DHCP6_CLIENT "enable DHCP6 client support") if(OT_DHCP6_CLIENT) list(APPEND OT_PRIVATE_DEFINES "OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE=1") diff --git a/examples/common-switches.mk b/examples/common-switches.mk index aecc85cfa..51ce69e38 100644 --- a/examples/common-switches.mk +++ b/examples/common-switches.mk @@ -123,6 +123,10 @@ ifeq ($(CHILD_SUPERVISION),1) COMMONCFLAGS += -DOPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE=1 endif +ifeq ($(CSL_RECEIVER),1) +COMMONCFLAGS += -DOPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE=1 +endif + ifeq ($(DEBUG),1) configure_OPTIONS += --enable-debug --disable-optimization endif diff --git a/examples/platforms/utils/mac_frame.cpp b/examples/platforms/utils/mac_frame.cpp index f782143c7..b1a0238fa 100644 --- a/examples/platforms/utils/mac_frame.cpp +++ b/examples/platforms/utils/mac_frame.cpp @@ -28,6 +28,7 @@ #include "mac_frame.h" +#include #include "mac/mac_frame.hpp" using namespace ot; @@ -125,3 +126,36 @@ void otMacFrameProcessTransmitAesCcm(otRadioFrame *aFrame, const otExtAddress *a { static_cast(aFrame)->ProcessTransmitAesCcm(*static_cast(aExtAddress)); } + +bool otMacFrameIsVersion2015(const otRadioFrame *aFrame) +{ + return static_cast(aFrame)->IsVersion2015(); +} + +void otMacFrameGenerateImmAck(const otRadioFrame *aFrame, bool aIsFramePending, otRadioFrame *aAckFrame) +{ + assert(aFrame != NULL && aAckFrame != NULL); + + static_cast(aAckFrame)->GenerateImmAck(*static_cast(aFrame), aIsFramePending); +} + +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +otError otMacFrameGenerateEnhAck(const otRadioFrame *aFrame, + bool aIsFramePending, + const uint8_t * aIeData, + uint8_t aIeLength, + otRadioFrame * aAckFrame) +{ + assert(aFrame != NULL && aAckFrame != NULL); + + return static_cast(aAckFrame)->GenerateEnhAck(*static_cast(aFrame), + aIsFramePending, aIeData, aIeLength); +} + +#if OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE +void otMacFrameSetCslIe(otRadioFrame *aFrame, uint16_t aCslPeriod, uint16_t aCslPhase) +{ + static_cast(aFrame)->SetCslIe(aCslPeriod, aCslPhase); +} +#endif // OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE +#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT diff --git a/examples/platforms/utils/mac_frame.h b/examples/platforms/utils/mac_frame.h index 2f2145ea0..aa53f462e 100644 --- a/examples/platforms/utils/mac_frame.h +++ b/examples/platforms/utils/mac_frame.h @@ -161,6 +161,56 @@ uint8_t otMacFrameGetSequence(const otRadioFrame *aFrame); */ void otMacFrameProcessTransmitAesCcm(otRadioFrame *aFrame, const otExtAddress *aExtAddress); +/** + * Tell if the version of @p aFrame is 2015. + * + * @param[in] aFrame A pointer to the frame. + * + * @retval true It is a version 2015 frame. + * @retval false It is not a version 2015 frame. + * + */ +bool otMacFrameIsVersion2015(const otRadioFrame *aFrame); + +/** + * Generate Imm-Ack for @p aFrame. + * + * @param[in] aFrame A pointer to the frame. + * @param[in] aIsFramePending Value of the ACK's frame pending bit. + * @param[out] aAckFrame A pointer to the ack frame to be generated. + * + */ +void otMacFrameGenerateImmAck(const otRadioFrame *aFrame, bool aIsFramePending, otRadioFrame *aAckFrame); + +/** + * Generate Enh-Ack for @p aFrame. + * + * @param[in] aFrame A pointer to the 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. + * @param[out] aAckFrame A pointer to the ack frame to be generated. + * + * @retval OT_ERROR_NONE Successfully generated Enh Ack in @p aAckFrame. + * @retval OT_ERROR_PARSE @p aFrame has incorrect format. + * + */ +otError otMacFrameGenerateEnhAck(const otRadioFrame *aFrame, + bool aIsFramePending, + const uint8_t * aIeData, + uint8_t aIeLength, + otRadioFrame * aAckFrame); + +/** + * Set CSL IE content into the frame. + * + * @param[inout] aFrame A pointer to the frame to be modified. + * @param[in] aCslPeriod CSL Period in CSL IE. + * @param[in] aCslPhase CSL Phase in CSL IE. + * + */ +void otMacFrameSetCslIe(otRadioFrame *aFrame, uint16_t aCslPeriod, uint16_t aCslPhase); + #ifdef __cplusplus } // extern "C" #endif diff --git a/script/test b/script/test index 2451c23dd..934b0c519 100755 --- a/script/test +++ b/script/test @@ -92,6 +92,12 @@ build_simulation() fi + if [[ "${version}" == "1.2" ]]; then + options+=( + "-DOT_CSL_RECEIVER=ON" + ) + fi + local builddir="${OT_BUILDDIR}/cmake/openthread-simulation-${version}" (mkdir -p "${builddir}" \ && cd "${builddir}" \ diff --git a/src/core/config/mac.h b/src/core/config/mac.h index ae7798b29..9c36a6b80 100644 --- a/src/core/config/mac.h +++ b/src/core/config/mac.h @@ -212,12 +212,13 @@ * Define as 1 to support IEEE 802.15.4-2015 Header IE (Information Element) generation and parsing, it must be set * to support following features: * 1. Time synchronization service feature (i.e., OPENTHREAD_CONFIG_TIME_SYNC_ENABLE is set). + * 2. Thread 1.2. * * @note If it's enabled, platform must support interrupt context and concurrent access AES. * */ #ifndef OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT -#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE || (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #define OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT 1 #else #define OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT 0 @@ -254,4 +255,26 @@ #define OPENTHREAD_CONFIG_MAC_RETX_POLL_PERIOD 1000 #endif +/** + * @def OPENTHREAD_CONFIG_CSL_TRANSMITTER_ENABLE + * + * This setting configures the CSL transmitter feature in Thread 1.2. + * This is compulsory for 1.2 FTD. + * + */ +#define OPENTHREAD_CONFIG_CSL_TRANSMITTER_ENABLE \ + (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_FTD + +/** + * @def OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE + * + * This setting configures the CSL receiver feature in Thread 1.2. + * This is compulsory for 1.2 MTD, optional for 1.2 FTD. + * + */ +#ifndef OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE +#define OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE \ + (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_MTD +#endif + #endif // CONFIG_MAC_H_ diff --git a/src/core/config/openthread-core-config-check.h b/src/core/config/openthread-core-config-check.h index 14a915159..2af9867f4 100644 --- a/src/core/config/openthread-core-config-check.h +++ b/src/core/config/openthread-core-config-check.h @@ -480,6 +480,21 @@ #endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +#if OPENTHREAD_CONFIG_CSL_TRANSMITTER_ENABLE +#if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2) +#error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_CSL_TRANSMITTER_ENABLE" +#endif +#if (!OPENTHREAD_FTD) +#error "FTD is required for OPENTHREAD_CONFIG_CSL_TRANSMITTER_ENABLE" +#endif +#endif // OPENTHREAD_CONFIG_CSL_TRANSMITTER_ENABLE + +#if OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE +#if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2) +#error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE" +#endif +#endif // OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE + #if OPENTHREAD_CONFIG_DUA_ENABLE && (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2) #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_DUA_ENABLE" #endif diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index 12fc6bef3..ad77835f4 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -186,7 +186,11 @@ void Frame::SetDstPanId(PanId aPanId) uint8_t Frame::FindDstAddrIndex(void) const { +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT + return kFcfSize + kDsnSize + (IsDstPanIdPresent() ? sizeof(PanId) : 0); +#else return kFcfSize + kDsnSize + sizeof(PanId); +#endif } otError Frame::GetDstAddr(Address &aAddress) const @@ -970,6 +974,20 @@ exit: } #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +#if OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE +void Frame::SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase) +{ + uint8_t *cur = GetHeaderIe(Frame::kHeaderIeCsl); + CslIe * csl; + + OT_ASSERT(cur != NULL); + + csl = reinterpret_cast(cur + sizeof(HeaderIe)); + csl->SetPeriod(aCslPeriod); + csl->SetPhase(aCslPhase); +} +#endif // OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE + #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE const TimeIe *Frame::GetTimeIe(void) const { @@ -1048,6 +1066,133 @@ exit: #endif // OPENTHREAD_RADIO } +void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending) +{ + uint16_t fcf = kFcfFrameAck | aFrame.GetVersion(); + + mChannel = aFrame.mChannel; + memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo)); + + if (aIsFramePending) + { + fcf |= kFcfFramePending; + } + Encoding::LittleEndian::WriteUint16(fcf, mPsdu); + + mPsdu[kSequenceIndex] = aFrame.GetSequence(); + + mLength = kImmAckLength; +} + +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +otError TxFrame::GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength) +{ + otError error = OT_ERROR_NONE; + + uint16_t fcf = kFcfFrameAck | kFcfFrameVersion2015 | kFcfSrcAddrNone; + Address address; + PanId panId; + uint8_t footerLength; + uint8_t securityControlField; + uint32_t frameCounter; + uint8_t keyId; + + mChannel = aFrame.mChannel; + memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo)); + + // Set frame control field + if (aIsFramePending) + { + fcf |= kFcfFramePending; + } + + 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; + } + + Encoding::LittleEndian::WriteUint16(fcf, mPsdu); + + // Set sequence number + mPsdu[kSequenceIndex] = aFrame.GetSequence(); + + // Set address field + if (aFrame.IsSrcPanIdPresent()) + { + SuccessOrExit(error = aFrame.GetSrcPanId(panId)); + } + else if (aFrame.IsDstPanIdPresent()) + { + SuccessOrExit(error = aFrame.GetDstPanId(panId)); + } + else + { + ExitNow(error = OT_ERROR_PARSE); + } + + if (IsDstPanIdPresent()) + { + SetDstPanId(panId); + } + + if (aFrame.IsSrcAddrPresent()) + { + SuccessOrExit(error = aFrame.GetSrcAddr(address)); + SetDstAddr(address); + } + + // Set security header + SuccessOrExit(error = aFrame.GetSecurityControlField(securityControlField)); + SuccessOrExit(error = aFrame.GetFrameCounter(frameCounter)); + SuccessOrExit(error = aFrame.GetKeyId(keyId)); + + SetPsduLength(kMaxPsduSize); // At this time the length of ACK hasn't been determined, set it to + // `kMaxPsduSize` to call methods that check frame length. + SetSecurityControlField(securityControlField); + SetFrameCounter(frameCounter); + SetKeyId(keyId); + + // Set header IE + if (aIeLength > 0) + { + OT_ASSERT(aIeData != NULL); + memcpy(GetPsdu() + FindHeaderIeIndex(), aIeData, aIeLength); + } + + // Set frame length + footerLength = GetFooterLength(); + OT_ASSERT(footerLength != kInvalidIndex); + mLength = FindHeaderIeIndex() + aIeLength + GetFooterLength(); + +exit: + return error; +} +#endif + // LCOV_EXCL_START #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1) diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index 427b3c60a..cc9f16083 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -314,9 +314,12 @@ public: kMacCmdGtsRequest = 9, kHeaderIeVendor = 0x00, + kHeaderIeCsl = 0x1a, kHeaderIeTermination2 = 0x7f, kInfoStringSize = 110, ///< Max chars needed for the info string representation (@sa ToInfoString()). + + kImmAckLength = kFcfSize + kDsnSize + kFcsSize, }; /** @@ -428,6 +431,15 @@ public: */ void SetAckRequest(bool aAckRequest); + /** + * This method indicates whether or not the PanId Compression bit is set. + * + * @retval TRUE If the PanId Compression bit is set. + * @retval FALSE If the PanId Compression bit is not set. + * + */ + bool IsPanIdCompressed(void) const { return (GetFrameControlField() & kFcfPanidCompression) != 0; } + /** * This method indicates whether or not IEs present. * @@ -522,6 +534,14 @@ public: */ void SetDstAddr(const Address &aAddress); + /** + * This method indicates whether or not the Source Address is present for this object. + * + * @retval TRUE if the Source Address is present, FALSE otherwise. + * + */ + bool IsSrcPanIdPresent(void) const { return IsSrcPanIdPresent(GetFrameControlField()); }; + /** * This method gets the Source PAN Identifier. * @@ -907,6 +927,18 @@ public: * */ const uint8_t *GetHeaderIe(uint8_t aIeId) const; + +#if OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE + /** + * This method finds CSL IE in the frame and modify its content. + * + * @param[in] aCslPeriod CSL Period in CSL IE. + * @param[in] aCslPhase CSL Phase in CSL IE. + * + */ + void SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase); +#endif // OPENTHREAD_CONFIG_CSL_RECEIVER_ENABLE + #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT /** @@ -933,11 +965,12 @@ public: */ InfoString ToInfoString(void) const; -private: +protected: enum { kInvalidIndex = 0xff, kInvalidSize = kInvalidIndex, + kMaxPsduSize = kInvalidSize - 1, kSequenceIndex = kFcfSize, }; @@ -974,6 +1007,8 @@ private: class RxFrame : public Frame { public: + friend class TxFrame; + /** * This method returns the RSSI in dBm used for reception. * @@ -1193,6 +1228,29 @@ public: */ void SetTimeSyncSeq(uint8_t aTimeSyncSeq) { mInfo.mTxInfo.mIeInfo->mTimeSyncSeq = aTimeSyncSeq; } #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + + /** + * Generate Imm-Ack in this frame object. + * + * @param[in] aFrame A reference to the frame received. + * @param[in] aIsFramePending Value of the ACK's frame pending bit. + * + */ + void GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending); + + /** + * Generate Enh-Ack in this frame object. + * + * @param[in] aFrame A reference to the frame received. + * @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 OT_ERROR_NONE Successfully generated Enh Ack. + * @retval OT_ERROR_PARSE @p aFrame has incorrect format. + * + */ + otError GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength); }; OT_TOOL_PACKED_BEGIN @@ -1411,6 +1469,51 @@ private: ExtendedPanId mExtendedPanId; } OT_TOOL_PACKED_END; +/** + * This class implements CSL IE data structure. + * + */ +OT_TOOL_PACKED_BEGIN +class CslIe +{ +public: + /** + * This method returns the CSL Period. + * + * @returns the CSL Period. + * + */ + uint16_t GetPeriod(void) const { return Encoding::LittleEndian::HostSwap16(mPeriod); } + + /** + * This method sets the CSL Period. + * + * @param[in] aPeriod The CSL Period. + * + */ + void SetPeriod(uint16_t aPeriod) { mPeriod = Encoding::LittleEndian::HostSwap16(aPeriod); } + + /** + * This method returns the CSL Phase. + * + * @returns the CSL Phase. + * + */ + uint16_t GetPhase(void) const { return Encoding::LittleEndian::HostSwap16(mPhase); } + + /** + * This method sets the CSL Phase. + * + * @param[in] aPhase The CSL Phase. + * + */ + void SetPhase(uint16_t aPhase) { mPhase = Encoding::LittleEndian::HostSwap16(aPhase); } + +private: + uint16_t mPhase; + uint16_t mPeriod; +} OT_TOOL_PACKED_END; + /** * @} * diff --git a/tests/unit/test_mac_frame.cpp b/tests/unit/test_mac_frame.cpp index 88e3fa0b0..aa17e1294 100644 --- a/tests/unit/test_mac_frame.cpp +++ b/tests/unit/test_mac_frame.cpp @@ -279,7 +279,6 @@ void TestMacHeader(void) frame.mLength = 0; frame.InitMacHeader(tests[i].fcf, tests[i].secCtl); - VerifyOrQuit(frame.GetHeaderLength() == tests[i].headerLength, "MacHeader test failed"); VerifyOrQuit(frame.GetFooterLength() == tests[i].footerLength, "MacHeader test failed"); VerifyOrQuit(frame.GetLength() == tests[i].headerLength + tests[i].footerLength, "MacHeader test failed"); @@ -473,6 +472,135 @@ void TestMacFrameApi(void) #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 } +void TestMacFrameAckGeneration(void) +{ + Mac::RxFrame receivedFrame; + Mac::TxFrame ackFrame; + uint8_t ackFrameBuffer[100]; + + ackFrame.mPsdu = ackFrameBuffer; + ackFrame.mLength = sizeof(ackFrameBuffer); + + // Received Frame 1 + // IEEE 802.15.4 Data + // Frame Control Field: 0xdc61 + // .... .... .... .001 = Frame Type: Data (0x1) + // .... .... .... 0... = Security Enabled: False + // .... .... ...0 .... = Frame Pending: False + // .... .... ..1. .... = Acknowledge Request: True + // .... .... .1.. .... = PAN ID Compression: True + // .... ...0 .... .... = Sequence Number Suppression: False + // .... ..0. .... .... = Information Elements Present: False + // .... 11.. .... .... = Destination Addressing Mode: Long/64-bit (0x3) + // ..01 .... .... .... = Frame Version: IEEE Std 802.15.4-2006 (1) + // 11.. .... .... .... = Source Addressing Mode: Long/64-bit (0x3) + // Sequence Number: 189 + // 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::kImmAckLength, + "Mac::Frame::GenerateImmAck() failed, length incorrect\n"); + VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kFcfFrameAck, + "Mac::Frame::GenerateImmAck() failed, GetType() incorrect\n"); + VerifyOrQuit(ackFrame.GetSecurityEnabled() == false, + "Mac::Frame::GenerateImmAck failed, GetSecurityEnabled() incorrect\n"); + VerifyOrQuit(ackFrame.GetFramePending() == false, + "Mac::Frame::GenerateImmAck failed, GetFramePending() incorrect\n"); + VerifyOrQuit(ackFrame.GetAckRequest() == false, "Mac::Frame::GenerateImmAck failed, GetAckRequest() incorrect\n"); + VerifyOrQuit(ackFrame.IsIePresent() == false, "Mac::Frame::GenerateImmAck failed, IsIePresent() incorrect\n"); + VerifyOrQuit(ackFrame.IsDstPanIdPresent() == false, + "Mac::Frame::GenerateImmAck failed, IsDstPanIdPresent() incorrect\n"); + VerifyOrQuit(ackFrame.IsDstAddrPresent() == false, + "Mac::Frame::GenerateImmAck failed, IsDstAddrPresent() incorrect\n"); + VerifyOrQuit(ackFrame.IsSrcAddrPresent() == false, + "Mac::Frame::GenerateImmAck failed, IsSrcAddrPresent() incorrect\n"); + VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kFcfFrameVersion2006, + "Mac::Frame::GenerateImmAck failed, GetVersion() incorrect\n"); + VerifyOrQuit(ackFrame.GetSequence() == 189, "Mac::Frame::GenerateImmAck failed, GetSequence() incorrect\n"); + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + // Received Frame 2 + // IEEE 802.15.4 Data + // Frame Control Field: 0xa869, Frame Type: Data, Security Enabled, Acknowledge Request, PAN ID Compression, + // Destination Addressing Mode: Short/16-bit, Frame Version: IEEE Std 802.15.4-2015, Source Addressing Mode: + // Short/16-bit + // .... .... .... .001 = Frame Type: Data (0x1) + // .... .... .... 1... = Security Enabled: True + // .... .... ...0 .... = Frame Pending: False + // .... .... ..1. .... = Acknowledge Request: True + // .... .... .1.. .... = PAN ID Compression: True + // .... ...0 .... .... = Sequence Number Suppression: False + // .... ..0. .... .... = Information Elements Present: False + // .... 10.. .... .... = Destination Addressing Mode: Short/16-bit (0x2) + // ..10 .... .... .... = Frame Version: IEEE Std 802.15.4-2015 (2) + // 10.. .... .... .... = Source Addressing Mode: Short/16-bit (0x2) + // Sequence Number: 142 + // Destination PAN: 0xface + // Destination: 0x2402 + // Source: 0x2400 + // [Extended Source: 16:6e:0a:00:00:00:00:01 (16:6e:0a:00:00:00:00:01)] + // [Origin: 2] + // Auxiliary Security Header + // Security Control Field: 0x0d, Security Level: Encryption with 32-bit Message Integrity Code, Key Identifier + // Mode: Indexed Key using the Default Key Source + // .... .101 = Security Level: Encryption with 32-bit Message Integrity Code (0x5) + // ...0 1... = Key Identifier Mode: Indexed Key using the Default Key Source (0x1) + // ..0. .... = Frame Counter Suppression: False + // .0.. .... = ASN in Nonce: False + // 0... .... = Reserved: 0x0 + // Frame Counter: 2 + // Key Identifier Field + // Key Index: 0x01 + // 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; + + ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)); + csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::Frame::kHeaderIeCsl) + 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, + "Mac::Frame::GenerateEnhAck() failed, GetType() incorrect\n"); + VerifyOrQuit(ackFrame.GetSecurityEnabled() == true, + "Mac::Frame::GenerateEnhAck failed, GetSecurityEnabled() incorrect\n"); + VerifyOrQuit(ackFrame.IsIePresent() == true, "Mac::Frame::GenerateEnhAck failed, IsIePresent() incorrect\n"); + VerifyOrQuit(ackFrame.IsDstPanIdPresent() == false, + "Mac::Frame::GenerateEnhAck failed, IsDstPanIdPresent() incorrect\n"); + VerifyOrQuit(ackFrame.IsDstAddrPresent() == true, + "Mac::Frame::GenerateEnhAck failed, IsDstAddrPresent() incorrect\n"); + VerifyOrQuit(ackFrame.IsSrcAddrPresent() == false, + "Mac::Frame::GenerateEnhAck failed, IsSrcAddrPresent() incorrect\n"); + VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kFcfFrameVersion2015, + "Mac::Frame::GenerateEnhAck failed, GetVersion() incorrect\n"); + VerifyOrQuit(ackFrame.GetSequence() == 142, "Mac::Frame::GenerateEnhAck failed, GetSequence() incorrect\n"); + VerifyOrQuit(csl->GetPeriod() == 3125 && csl->GetPhase() == 3105, + "Mac::Frame::GenerateEnhAck failed, CslIe incorrect\n"); + + ackFrame.SetCslIe(123, 456); + csl = reinterpret_cast(ackFrame.GetHeaderIe(Mac::Frame::kHeaderIeCsl) + sizeof(Mac::HeaderIe)); + VerifyOrQuit(csl->GetPeriod() == 123 && csl->GetPhase() == 456, "Mac::Frame::SetCslIe failed, CslIe incorrect\n"); +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +} + } // namespace ot int main(void) @@ -482,6 +610,7 @@ int main(void) ot::TestMacHeader(); ot::TestMacChannelMask(); ot::TestMacFrameApi(); + ot::TestMacFrameAckGeneration(); printf("All tests passed\n"); return 0; }