[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.
This commit is contained in:
Abtin Keshavarzian
2022-08-02 12:43:51 -07:00
committed by Jonathan Hui
parent e3f157402c
commit c096c0e9ca
5 changed files with 207 additions and 220 deletions
+1 -1
View File
@@ -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;
+21 -48
View File
@@ -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<uint16_t>(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<uint16_t>(kDispatch) << 8) + mSize, cur);
cur += sizeof(uint16_t);
WriteUint16(mTag, cur);
cur += sizeof(uint16_t);
if (mOffset != 0)
{
*aFrame |= kOffsetFlag;
*cur++ = static_cast<uint8_t>(mOffset >> 3);
}
return static_cast<uint16_t>(cur - aFrame);
}
} // namespace Lowpan
} // namespace ot
+69 -54
View File
@@ -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<uint8_t>(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;
+66 -77
View File
@@ -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<Mle::MleRouter>();
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<Lowpan::Lowpan>().Compress(aMessage, meshSource, meshDest, frameBuilder));
hcLength = static_cast<uint8_t>(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<uint16_t>(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<uint16_t>(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<uint16_t>(aMessage.GetDatagramTag()),
aMessage.GetOffset());
SuccessOrAssert(frameBuilder.Append(nextFragHeader));
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
// Write Fragment header
fragmentHeader.Init(aMessage.GetLength(), static_cast<uint16_t>(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;
}
+50 -40
View File
@@ -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);