From c096c0e9ca232923f89af3f48aa77a9d9b5f630d Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 1 Aug 2022 10:54:04 -0700 Subject: [PATCH] [mesh-forwarder] use `FrameBuidler` in `PrepareDataFrame()` (#7964) This commit updates `MeshForwarder::PrepareDataFrame()` to use `FrameBuilder` to prepare the frame. It also updates `Lowpan` fragment header definitions and adds `FirstFrag` and `NextFrag` nested types. The unit test `test_lowpan` is also updated to use the new types. --- src/core/net/ip6.cpp | 2 +- src/core/thread/lowpan.cpp | 69 +++++--------- src/core/thread/lowpan.hpp | 123 ++++++++++++++----------- src/core/thread/mesh_forwarder.cpp | 143 +++++++++++++---------------- tests/unit/test_lowpan.cpp | 90 ++++++++++-------- 5 files changed, 207 insertions(+), 220 deletions(-) diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index bb3096fd6..ce8d31ccc 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -1532,7 +1532,7 @@ Error Headers::DecompressFrom(const Message & aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest) { - static constexpr uint16_t kReadLength = Lowpan::FragmentHeader::kSubsequentFragmentHeaderSize + sizeof(Headers); + static constexpr uint16_t kReadLength = sizeof(Lowpan::FragmentHeader::NextFrag) + sizeof(Headers); uint8_t frameBuffer[kReadLength]; uint16_t frameLength; diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index d373fbe1c..67d0570eb 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -45,7 +45,6 @@ using ot::Encoding::BigEndian::HostSwap16; using ot::Encoding::BigEndian::ReadUint16; -using ot::Encoding::BigEndian::WriteUint16; namespace ot { namespace Lowpan { @@ -1232,50 +1231,43 @@ void MeshHeader::DecrementHopsLeft(void) } } -uint16_t MeshHeader::WriteTo(uint8_t *aFrame) const +Error MeshHeader::AppendTo(FrameBuilder &aFrameBuilder) const { - uint8_t *cur = aFrame; - uint8_t dispatch = (kDispatch | kSourceShort | kDestShort); + Error error; + uint8_t dispatch = (kDispatch | kSourceShort | kDestShort); if (mHopsLeft < kDeepHopsLeft) { - *cur++ = (dispatch | mHopsLeft); + SuccessOrExit(error = aFrameBuilder.AppendUint8(dispatch | mHopsLeft)); } else { - *cur++ = (dispatch | kDeepHopsLeft); - *cur++ = mHopsLeft; + SuccessOrExit(error = aFrameBuilder.AppendUint8(dispatch | kDeepHopsLeft)); + SuccessOrExit(error = aFrameBuilder.AppendUint8(mHopsLeft)); } - WriteUint16(mSource, cur); - cur += sizeof(uint16_t); + SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(mSource)); + SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(mDestination)); - WriteUint16(mDestination, cur); - cur += sizeof(uint16_t); - - return static_cast(cur - aFrame); +exit: + return error; } Error MeshHeader::AppendTo(Message &aMessage) const { - uint8_t frame[kDeepHopsHeaderLength]; - uint16_t headerLength; + uint8_t frame[kDeepHopsHeaderLength]; + FrameBuilder frameBuilder; - headerLength = WriteTo(frame); + frameBuilder.Init(frame, sizeof(frame)); - return aMessage.AppendBytes(frame, headerLength); + IgnoreError(AppendTo(frameBuilder)); + + return aMessage.AppendBytes(frameBuilder.GetBytes(), frameBuilder.GetLength()); } //--------------------------------------------------------------------------------------------------------------------- // FragmentHeader -void FragmentHeader::Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset) -{ - mSize = (aSize & kSizeMask); - mTag = aTag; - mOffset = (aOffset & kOffsetMask); -} - bool FragmentHeader::IsFragmentHeader(const FrameData &aFrameData) { return IsFragmentHeader(aFrameData.GetBytes(), aFrameData.GetLength()); @@ -1283,7 +1275,7 @@ bool FragmentHeader::IsFragmentHeader(const FrameData &aFrameData) bool FragmentHeader::IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength) { - return (aFrameLength >= kFirstFragmentHeaderSize) && ((*aFrame & kDispatchMask) == kDispatch); + return (aFrameLength >= sizeof(FirstFrag)) && ((*aFrame & kDispatchMask) == kDispatch); } Error FragmentHeader::ParseFrom(FrameData &aFrameData) @@ -1309,14 +1301,14 @@ Error FragmentHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, ui if ((*aFrame & kOffsetFlag) == kOffsetFlag) { - VerifyOrExit(aFrameLength >= kSubsequentFragmentHeaderSize); + VerifyOrExit(aFrameLength >= sizeof(NextFrag)); mOffset = aFrame[kOffsetIndex] * 8; - aHeaderLength = kSubsequentFragmentHeaderSize; + aHeaderLength = sizeof(NextFrag); } else { mOffset = 0; - aHeaderLength = kFirstFragmentHeaderSize; + aHeaderLength = sizeof(FirstFrag); } error = kErrorNone; @@ -1327,7 +1319,7 @@ exit: Error FragmentHeader::ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength) { - uint8_t frame[kSubsequentFragmentHeaderSize]; + uint8_t frame[sizeof(NextFrag)]; uint16_t frameLength; frameLength = aMessage.ReadBytes(aOffset, frame, sizeof(frame)); @@ -1335,24 +1327,5 @@ Error FragmentHeader::ParseFrom(const Message &aMessage, uint16_t aOffset, uint1 return ParseFrom(frame, frameLength, aHeaderLength); } -uint16_t FragmentHeader::WriteTo(uint8_t *aFrame) const -{ - uint8_t *cur = aFrame; - - WriteUint16((static_cast(kDispatch) << 8) + mSize, cur); - cur += sizeof(uint16_t); - - WriteUint16(mTag, cur); - cur += sizeof(uint16_t); - - if (mOffset != 0) - { - *aFrame |= kOffsetFlag; - *cur++ = static_cast(mOffset >> 3); - } - - return static_cast(cur - aFrame); -} - } // namespace Lowpan } // namespace ot diff --git a/src/core/thread/lowpan.hpp b/src/core/thread/lowpan.hpp index 719360790..b49e225cb 100644 --- a/src/core/thread/lowpan.hpp +++ b/src/core/thread/lowpan.hpp @@ -428,16 +428,15 @@ public: uint16_t GetDestination(void) const { return mDestination; } /** - * This method writes the Mesh Header into a given frame. + * This method appends the Mesh Header into a given frame. * - * @note This method expects the frame buffer to have enough space for the entire Mesh Header. + * @param[out] aFrameBuilder The `FrameBuidler` to append to. * - * @param[out] aFrame The pointer to the frame buffer to write to. - * - * @returns The header length (number of bytes written). + * @retval kErrorNone Successfully appended the MeshHeader to @p aFrameBuildr. + * @retval kErrorNoBufs Insufficient available buffers. * */ - uint16_t WriteTo(uint8_t *aFrame) const; + Error AppendTo(FrameBuilder &aFrameBuilder) const; /** * This method appends the Mesh Header to a given message. @@ -475,31 +474,70 @@ private: class FragmentHeader { public: - static constexpr uint16_t kFirstFragmentHeaderSize = 4; ///< First fragment header size in octets. - static constexpr uint16_t kSubsequentFragmentHeaderSize = 5; ///< Subsequent fragment header size in octets. + OT_TOOL_PACKED_BEGIN + class FirstFrag + { + public: + /** + * This method initializes the `FirstFrag`. + * + * @param[in] aSize The Datagram Size value. + * @param[in] aTag The Datagram Tag value. + * + */ + void Init(uint16_t aSize, uint16_t aTag) + { + mDispatchSize = HostSwap16(kFirstDispatch | (aSize & kSizeMask)); + mTag = HostSwap16(aTag); + } - /** - * This method initializes the Fragment Header as a first fragment. - * - * A first fragment header starts at offset zero. - * - * @param[in] aSize The Datagram Size value. - * @param[in] aTag The Datagram Tag value. - * - */ - void InitFirstFragment(uint16_t aSize, uint16_t aTag) { Init(aSize, aTag, 0); } + private: + // 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |1 1 0 0 0| datagram_size | datagram_tag | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - /** - * This method initializes the Fragment Header. - * - * The @p aOffset value will be truncated to become a multiple of 8. - * - * @param[in] aSize The Datagram Size value. - * @param[in] aTag The Datagram Tag value. - * @param[in] aOffset The Datagram Offset value. - * - */ - void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset); + static constexpr uint16_t kFirstDispatch = 0xc000; // 0b11000_0000_0000_0000 + + uint16_t mDispatchSize; + uint16_t mTag; + } OT_TOOL_PACKED_END; + + OT_TOOL_PACKED_BEGIN + class NextFrag + { + public: + /** + * This method initializes the `NextFrag`. + * + * @param[in] aSize The Datagram Size value. + * @param[in] aTag The Datagram Tag value. + * @param[in] aOffset The Datagram Offset value. + * + */ + void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset) + { + mDispatchSize = HostSwap16(kNextDispatch | (aSize & kSizeMask)); + mTag = HostSwap16(aTag); + mOffset = static_cast(aOffset >> 3); + } + + private: + // 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |1 1 1 0 0| datagram_size | datagram_tag | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |datagram_offset| + // +-+-+-+-+-+-+-+-+ + + static constexpr uint16_t kNextDispatch = 0xe000; // 0b11100_0000_0000_0000 + + uint16_t mDispatchSize; + uint16_t mTag; + uint8_t mOffset; + } OT_TOOL_PACKED_END; /** * This static method indicates whether or not the header (in a given frame) is a Fragment Header. @@ -516,19 +554,6 @@ public: */ static bool IsFragmentHeader(const FrameData &aFrameData); - /** - * This method parses the Fragment Header from a frame @p aFrame. - * - * @param[in] aFrame The pointer to the frame. - * @param[in] aFrameLength The length of the frame. - * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). - * - * @retval kErrorNone Fragment Header parsed successfully. - * @retval kErrorParse Fragment header could not be parsed from @p aFrame. - * - */ - Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); //~~~ REMOVE OR MAKE PRIVATE - /** * This method parses the Fragment Header from a given frame data. * @@ -581,18 +606,6 @@ public: */ uint16_t GetDatagramOffset(void) const { return mOffset; } - /** - * This method writes the Fragment Header into a given frame. - * - * @note This method expects the frame buffer to have enough space for the entire Fragment Header - * - * @param[out] aFrame The pointer to the frame buffer to write to. - * - * @returns The header length (number of bytes written). - * - */ - uint16_t WriteTo(uint8_t *aFrame) const; - private: static constexpr uint8_t kDispatch = 0xc0; // 0b1100_0000 static constexpr uint8_t kDispatchMask = 0xd8; // 0b1101_1000 accepts first (0b1100_0xxx) and next (0b1110_0xxx). @@ -607,6 +620,8 @@ private: static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength); + Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); + uint16_t mSize; uint16_t mTag; uint16_t mOffset; diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index bd55d74d6..31477b613 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -852,16 +852,14 @@ uint16_t MeshForwarder::PrepareDataFrame(Mac::TxFrame & aFrame, uint16_t aMeshDest, bool aAddFragHeader) { - uint16_t fcf; - uint8_t *payload; - uint8_t headerLength; - uint16_t maxPayloadLength; - uint16_t payloadLength; - uint16_t fragmentLength; - uint16_t dstpan; - uint8_t secCtl; - uint16_t nextOffset; - bool iePresent = CalcIePresent(&aMessage); + uint16_t fcf; + uint16_t payloadLength; + uint16_t dstpan; + uint8_t secCtl; + uint16_t origMsgOffset; + uint16_t nextOffset; + FrameBuilder frameBuilder; + bool iePresent = CalcIePresent(&aMessage); start: @@ -974,10 +972,7 @@ start: } #endif - payload = aFrame.GetPayload(); - maxPayloadLength = aFrame.GetMaxPayloadLength(); - - headerLength = 0; + frameBuilder.Init(aFrame.GetPayload(), aFrame.GetMaxPayloadLength()); #if OPENTHREAD_FTD @@ -986,8 +981,8 @@ start: { Mle::MleRouter & mle = Get(); Lowpan::MeshHeader meshHeader; - uint16_t meshHeaderLength; uint8_t hopsLeft; + uint16_t maxPayloadLength; // Mesh Header frames are forwarded by routers over multiple // hops to reach a final destination. The forwarding path can @@ -1007,6 +1002,8 @@ start: maxPayloadLength = kMeshHeaderFrameMtu - aFrame.GetHeaderLength() - (aFrame.GetFooterLength() - aFrame.GetFcsSize() + kMeshHeaderFrameFcsSize); + frameBuilder.Init(aFrame.GetPayload(), maxPayloadLength); + if (mle.IsChild()) { // REED sets hopsLeft to max (16) + 1. It does not know the route cost. @@ -1036,21 +1033,37 @@ start: } meshHeader.Init(aMeshSource, aMeshDest, hopsLeft + Lowpan::MeshHeader::kAdditionalHopsLeft); - meshHeaderLength = meshHeader.WriteTo(payload); - payload += meshHeaderLength; - headerLength += meshHeaderLength; + + IgnoreError(meshHeader.AppendTo(frameBuilder)); } -#endif +#endif // OPENTHREAD_FTD + + // While performing lowpan compression, the message offset may be + // changed to skip over the compressed IPv6 headers, we save the + // original offset and set it back on `aMessage` at the end + // before returning. + + origMsgOffset = aMessage.GetOffset(); // Compress IPv6 Header if (aMessage.GetOffset() == 0) { - FrameBuilder frameBuilder; - uint8_t hcLength; - Mac::Address meshSource, meshDest; + uint16_t fragHeaderOffset; + uint16_t maxFrameLength; + Mac::Address meshSource; + Mac::Address meshDest; - frameBuilder.Init(payload, maxPayloadLength - headerLength - Lowpan::FragmentHeader::kFirstFragmentHeaderSize); + // Before performing lowpan header compression, we reduce the + // max length on `frameBuilder` to reserve bytes for first + // fragment header. This ensures that lowpan compression will + // leave room for a first fragment header. After the lowpan + // header compression is done, we reclaim the reserved bytes + // by setting the max length back to its original value. + + fragHeaderOffset = frameBuilder.GetLength(); + maxFrameLength = frameBuilder.GetMaxLength(); + frameBuilder.SetMaxLength(maxFrameLength - sizeof(Lowpan::FragmentHeader::FirstFrag)); if (aAddMeshHeader) { @@ -1065,24 +1078,26 @@ start: SuccessOrAssert(Get().Compress(aMessage, meshSource, meshDest, frameBuilder)); - hcLength = static_cast(frameBuilder.GetLength()); - headerLength += hcLength; - payloadLength = aMessage.GetLength() - aMessage.GetOffset(); - fragmentLength = maxPayloadLength - headerLength; + frameBuilder.SetMaxLength(maxFrameLength); - if ((payloadLength > fragmentLength) || aAddFragHeader) + payloadLength = aMessage.GetLength() - aMessage.GetOffset(); + + if (aAddFragHeader || (payloadLength > frameBuilder.GetRemainingLength())) { - Lowpan::FragmentHeader fragmentHeader; + Lowpan::FragmentHeader::FirstFrag firstFragHeader; if ((!aMessage.IsLinkSecurityEnabled()) && aMessage.IsSubTypeMle()) { - // Enable security and try again. + // MLE messages that require fragmentation MUST use + // link-layer security. We enable security and try + // constructing the frame again. + aMessage.SetOffset(0); aMessage.SetLinkSecurityEnabled(true); goto start; } - // Write Fragment header + // Insert Fragment header if (aMessage.GetDatagramTag() == 0) { // Avoid using datagram tag value 0, which indicates the tag has not been set @@ -1094,60 +1109,32 @@ start: aMessage.SetDatagramTag(mFragTag++); } - memmove(payload + Lowpan::FragmentHeader::kFirstFragmentHeaderSize, payload, hcLength); - - fragmentHeader.InitFirstFragment(aMessage.GetLength(), static_cast(aMessage.GetDatagramTag())); - fragmentHeader.WriteTo(payload); - - payload += Lowpan::FragmentHeader::kFirstFragmentHeaderSize; - headerLength += Lowpan::FragmentHeader::kFirstFragmentHeaderSize; - - fragmentLength = maxPayloadLength - headerLength; - - if (payloadLength > fragmentLength) - { - payloadLength = fragmentLength & ~0x7; - } + firstFragHeader.Init(aMessage.GetLength(), static_cast(aMessage.GetDatagramTag())); + SuccessOrAssert(frameBuilder.Insert(fragHeaderOffset, firstFragHeader)); } - - payload += hcLength; - - // copy IPv6 Payload - aMessage.ReadBytes(aMessage.GetOffset(), payload, payloadLength); - aFrame.SetPayloadLength(headerLength + payloadLength); - - nextOffset = aMessage.GetOffset() + payloadLength; - aMessage.SetOffset(0); } else { - Lowpan::FragmentHeader fragmentHeader; - uint16_t fragmentHeaderLength; + Lowpan::FragmentHeader::NextFrag nextFragHeader; + + nextFragHeader.Init(aMessage.GetLength(), static_cast(aMessage.GetDatagramTag()), + aMessage.GetOffset()); + SuccessOrAssert(frameBuilder.Append(nextFragHeader)); payloadLength = aMessage.GetLength() - aMessage.GetOffset(); - - // Write Fragment header - fragmentHeader.Init(aMessage.GetLength(), static_cast(aMessage.GetDatagramTag()), - aMessage.GetOffset()); - fragmentHeaderLength = fragmentHeader.WriteTo(payload); - - payload += fragmentHeaderLength; - headerLength += fragmentHeaderLength; - - fragmentLength = maxPayloadLength - headerLength; - - if (payloadLength > fragmentLength) - { - payloadLength = (fragmentLength & ~0x7); - } - - // Copy IPv6 Payload - aMessage.ReadBytes(aMessage.GetOffset(), payload, payloadLength); - aFrame.SetPayloadLength(headerLength + payloadLength); - - nextOffset = aMessage.GetOffset() + payloadLength; } + if (payloadLength > frameBuilder.GetRemainingLength()) + { + payloadLength = (frameBuilder.GetRemainingLength() & ~0x7); + } + + // Copy IPv6 Payload + SuccessOrAssert(frameBuilder.AppendBytesFromMessage(aMessage, aMessage.GetOffset(), payloadLength)); + aFrame.SetPayloadLength(frameBuilder.GetLength()); + + nextOffset = aMessage.GetOffset() + payloadLength; + if (nextOffset < aMessage.GetLength()) { aFrame.SetFramePending(true); @@ -1156,6 +1143,8 @@ start: #endif } + aMessage.SetOffset(origMsgOffset); + return nextOffset; } diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp index beb6981fc..be63b9d35 100644 --- a/tests/unit/test_lowpan.cpp +++ b/tests/unit/test_lowpan.cpp @@ -1870,6 +1870,7 @@ void TestLowpanMeshHeader(void) uint8_t frame[kMaxFrameSize]; uint16_t length; FrameData frameData; + FrameBuilder frameBuilder; Lowpan::MeshHeader meshHeader; meshHeader.Init(kSourceAddr, kDestAddr, 1); @@ -1877,10 +1878,12 @@ void TestLowpanMeshHeader(void) VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after Init()"); VerifyOrQuit(meshHeader.GetHopsLeft() == 1, "failed after Init()"); - length = meshHeader.WriteTo(frame); + frameBuilder.Init(frame, sizeof(frame)); + SuccessOrQuit(meshHeader.AppendTo(frameBuilder)); + length = frameBuilder.GetLength(); VerifyOrQuit(length == meshHeader.GetHeaderLength()); - VerifyOrQuit(length == sizeof(kMeshHeader1), "MeshHeader::WriteTo() returned length is incorrect"); - VerifyOrQuit(memcmp(frame, kMeshHeader1, length) == 0, "MeshHeader::WriteTo() failed"); + VerifyOrQuit(length == sizeof(kMeshHeader1), "MeshHeader::AppendTo() returned length is incorrect"); + VerifyOrQuit(memcmp(frame, kMeshHeader1, length) == 0, "MeshHeader::AppendTo() failed"); memset(&meshHeader, 0, sizeof(meshHeader)); frameData.Init(frame, length); @@ -1903,10 +1906,12 @@ void TestLowpanMeshHeader(void) VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after Init()"); VerifyOrQuit(meshHeader.GetHopsLeft() == 0x20, "failed after Init()"); - length = meshHeader.WriteTo(frame); - VerifyOrQuit(length == sizeof(kMeshHeader2), "MeshHeader::WriteTo() returned length is incorrect"); + frameBuilder.Init(frame, sizeof(frame)); + SuccessOrQuit(meshHeader.AppendTo(frameBuilder)); + length = frameBuilder.GetLength(); + VerifyOrQuit(length == sizeof(kMeshHeader2), "MeshHeader::AppendTo() returned length is incorrect"); VerifyOrQuit(length == meshHeader.GetHeaderLength()); - VerifyOrQuit(memcmp(frame, kMeshHeader2, length) == 0, "MeshHeader::WriteTo() failed"); + VerifyOrQuit(memcmp(frame, kMeshHeader2, length) == 0, "MeshHeader::AppendTo() failed"); memset(&meshHeader, 0, sizeof(meshHeader)); frameData.Init(frame, length); @@ -1933,7 +1938,9 @@ void TestLowpanMeshHeader(void) VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()"); VerifyOrQuit(meshHeader.GetHopsLeft() == 1, "failed after ParseFrom()"); - VerifyOrQuit(meshHeader.WriteTo(frame) == sizeof(kMeshHeader1)); + frameBuilder.Init(frame, sizeof(frame)); + SuccessOrQuit(meshHeader.AppendTo(frameBuilder)); + VerifyOrQuit(frameBuilder.GetLength() == sizeof(kMeshHeader1)); frameData.Init(kMeshHeader3, sizeof(kMeshHeader3) - 1); VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse, @@ -1942,13 +1949,10 @@ void TestLowpanMeshHeader(void) void TestLowpanFragmentHeader(void) { - enum - { - kMaxFrameSize = 127, - kSize = 0x7ef, - kTag = 0x1234, - kOffset = (100 * 8), - }; + static constexpr uint16_t kMaxFrameSize = 127; + static constexpr uint16_t kSize = 0x7ef; + static constexpr uint16_t kTag = 0x1234; + static constexpr uint16_t kOffset = (100 * 8); const uint8_t kFragHeader1[] = {0xc7, 0xef, 0x12, 0x34}; // size:0x7ef, tag:0x1234, offset:0 (first frag) const uint8_t kFragHeader2[] = {0xe7, 0xef, 0x12, 0x34, 0x64}; // size:0x7ef, tag:0x1234, offset:100 (next frag) @@ -1958,21 +1962,22 @@ void TestLowpanFragmentHeader(void) const uint8_t kInvalidFragHeader2[] = {0xd0, 0xef, 0x12, 0x34, 0x64}; const uint8_t kInvalidFragHeader3[] = {0x90, 0xef, 0x12, 0x34, 0x64}; - uint8_t frame[kMaxFrameSize]; - uint16_t length; - FrameData frameData; - Lowpan::FragmentHeader fragHeader; + uint8_t frame[kMaxFrameSize]; + uint16_t length; + FrameData frameData; + FrameBuilder frameBuilder; + Lowpan::FragmentHeader fragHeader; + Lowpan::FragmentHeader::FirstFrag firstFragHeader; + Lowpan::FragmentHeader::NextFrag nextFragHeader; - fragHeader.InitFirstFragment(kSize, kTag); - VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after Init"); - VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after Init()"); - VerifyOrQuit(fragHeader.GetDatagramOffset() == 0, "failed after Init()"); + frameBuilder.Init(frame, sizeof(frame)); - length = fragHeader.WriteTo(frame); - VerifyOrQuit(length == Lowpan::FragmentHeader::kFirstFragmentHeaderSize, - "FragmentHeader::WriteTo() returned length is incorrect"); - VerifyOrQuit(length == sizeof(kFragHeader1), "FragmentHeader::WriteTo() returned length is incorrect"); - VerifyOrQuit(memcmp(frame, kFragHeader1, length) == 0, "FragmentHeader::WriteTo() failed"); + firstFragHeader.Init(kSize, kTag); + SuccessOrQuit(frameBuilder.Append(firstFragHeader)); + + length = frameBuilder.GetLength(); + VerifyOrQuit(length == sizeof(Lowpan::FragmentHeader::FirstFrag)); + VerifyOrQuit(memcmp(frame, kFragHeader1, length) == 0); memset(&fragHeader, 0, sizeof(fragHeader)); @@ -1993,22 +1998,27 @@ void TestLowpanFragmentHeader(void) //- - - - - - - - - - - - - - - - - - - - - - - - - - - fragHeader.Init(kSize, kTag, kOffset); - VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after Init"); - VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after Init()"); - VerifyOrQuit(fragHeader.GetDatagramOffset() == kOffset, "failed after Init()"); + frameBuilder.Init(frame, sizeof(frame)); + nextFragHeader.Init(kSize, kTag, kOffset); + SuccessOrQuit(frameBuilder.Append(nextFragHeader)); + length = frameBuilder.GetLength(); + VerifyOrQuit(length == sizeof(kFragHeader2)); + VerifyOrQuit(memcmp(frame, kFragHeader2, length) == 0); // Check the truncation of offset (to be multiple of 8). - fragHeader.Init(kSize, kTag, kOffset + 1); - VerifyOrQuit(fragHeader.GetDatagramOffset() == kOffset, "FragmentHeader::GetDatagramOffset() did not truncate"); - fragHeader.Init(kSize, kTag, kOffset + 7); - VerifyOrQuit(fragHeader.GetDatagramOffset() == kOffset, "FragmentHeader::GetDatagramOffset() did not truncate"); + frameBuilder.Init(frame, sizeof(frame)); + nextFragHeader.Init(kSize, kTag, kOffset + 1); + SuccessOrQuit(frameBuilder.Append(nextFragHeader)); + length = frameBuilder.GetLength(); + VerifyOrQuit(length == sizeof(kFragHeader2)); + VerifyOrQuit(memcmp(frame, kFragHeader2, length) == 0); - length = fragHeader.WriteTo(frame); - VerifyOrQuit(length == Lowpan::FragmentHeader::kSubsequentFragmentHeaderSize, - "FragmentHeader::WriteTo() returned length is incorrect"); - VerifyOrQuit(length == sizeof(kFragHeader2), "FragmentHeader::WriteTo() returned length is incorrect"); - VerifyOrQuit(memcmp(frame, kFragHeader2, length) == 0, "FragmentHeader::WriteTo() failed"); + frameBuilder.Init(frame, sizeof(frame)); + nextFragHeader.Init(kSize, kTag, kOffset + 7); + SuccessOrQuit(frameBuilder.Append(nextFragHeader)); + length = frameBuilder.GetLength(); + VerifyOrQuit(length == sizeof(kFragHeader2)); + VerifyOrQuit(memcmp(frame, kFragHeader2, length) == 0); memset(&fragHeader, 0, sizeof(fragHeader)); frameData.Init(frame, length);