[lowpan] simplify FragmentHeader and its use in MeshForwarder (#4453)

This commit updates the `Lowpan::FragmentHeader` class to provide
methods to parse/write the Fragment Header from/to a given frame or
message.
This commit is contained in:
Abtin Keshavarzian
2020-01-13 10:57:42 -08:00
committed by Jonathan Hui
parent 2ec0d2f8d4
commit 17168e9ba1
5 changed files with 142 additions and 165 deletions
+48 -23
View File
@@ -1319,19 +1319,40 @@ uint16_t MeshHeader::WriteTo(Message &aMessage, uint16_t aOffset) const
return headerLength;
}
otError FragmentHeader::Init(const uint8_t *aFrame, uint16_t aFrameLength)
//---------------------------------------------------------------------------------------------------------------------
// 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 uint8_t *aFrame, uint16_t aFrameLength)
{
return (aFrameLength >= kFirstFragmentHeaderSize) && ((*aFrame & kDispatchMask) == kDispatch);
}
otError FragmentHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
{
otError error = OT_ERROR_PARSE;
VerifyOrExit(aFrameLength >= sizeof(mDispatchSize) + sizeof(mTag));
memcpy(reinterpret_cast<uint8_t *>(&mDispatchSize), aFrame, sizeof(mDispatchSize) + sizeof(mTag));
aFrame += sizeof(mDispatchSize) + sizeof(mTag);
aFrameLength -= sizeof(mDispatchSize) + sizeof(mTag);
VerifyOrExit(IsFragmentHeader(aFrame, aFrameLength));
if (IsOffsetPresent())
mSize = ReadUint16(aFrame + kSizeIndex) & kSizeMask;
mTag = ReadUint16(aFrame + kTagIndex);
if ((*aFrame & kOffsetFlag) == kOffsetFlag)
{
VerifyOrExit(aFrameLength >= sizeof(mOffset));
mOffset = *aFrame++;
VerifyOrExit(aFrameLength >= kSubsequentFragmentHeaderSize);
mOffset = aFrame[kOffsetIndex] * 8;
aHeaderLength = kSubsequentFragmentHeaderSize;
}
else
{
mOffset = 0;
aHeaderLength = kFirstFragmentHeaderSize;
}
error = OT_ERROR_NONE;
@@ -1340,29 +1361,33 @@ exit:
return error;
}
otError FragmentHeader::Init(const Message &aMessage, uint16_t aOffset)
otError FragmentHeader::ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength)
{
otError error = OT_ERROR_NONE;
uint16_t bytesRead;
uint8_t frame[kSubsequentFragmentHeaderSize];
uint16_t frameLength;
bytesRead = aMessage.Read(aOffset, sizeof(mDispatchSize), reinterpret_cast<void *>(&mDispatchSize));
VerifyOrExit(bytesRead == sizeof(mDispatchSize), error = OT_ERROR_PARSE);
aOffset += bytesRead;
frameLength = aMessage.Read(aOffset, sizeof(frame), frame);
VerifyOrExit(IsFragmentHeader(), error = OT_ERROR_PARSE);
return ParseFrom(frame, frameLength, aHeaderLength);
}
bytesRead = aMessage.Read(aOffset, sizeof(mTag), reinterpret_cast<void *>(&mTag));
VerifyOrExit(bytesRead == sizeof(mTag), error = OT_ERROR_PARSE);
aOffset += bytesRead;
uint16_t FragmentHeader::WriteTo(uint8_t *aFrame) const
{
uint8_t *cur = aFrame;
if (IsOffsetPresent())
WriteUint16((kDispatch << 8) + mSize, cur);
cur += sizeof(uint16_t);
WriteUint16(mTag, cur);
cur += sizeof(uint16_t);
if (mOffset != 0)
{
bytesRead = aMessage.Read(aOffset, sizeof(mOffset), &mOffset);
VerifyOrExit(bytesRead == sizeof(mOffset), error = OT_ERROR_PARSE);
*aFrame |= kOffsetFlag;
*cur++ = static_cast<uint8_t>(mOffset >> 3);
}
exit:
return error;
return static_cast<uint16_t>(cur - aFrame);
}
} // namespace Lowpan
+59 -85
View File
@@ -550,81 +550,76 @@ private:
* This class implements Fragment Header generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class FragmentHeader
{
public:
enum
{
kInitialHeaderSize = 4, ///< Initial fragment header size in octets.
kSubsequentHeaderSize = 5, ///< Subsequent fragment header size in octets.
kFirstFragmentHeaderSize = 4, ///< First fragment header size in octets.
kSubsequentFragmentHeaderSize = 5, ///< Subsequent fragment header size in octets.
};
/**
* This constructor initializes the Fragment Header.
* 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] aTage The Datagram Tag value.
*
*/
FragmentHeader(void)
{
mDispatchSize = HostSwap16(kDispatch);
mTag = 0;
mOffset = 0;
}
void InitFirstFragment(uint16_t aSize, uint16_t aTag) { Init(aSize, aTag, 0); }
/**
* This method initializes the Fragment Header.
*
*/
void Init(void) { mDispatchSize = HostSwap16(kDispatch); }
/**
* This method initializes the fragment header from a frame @p aFrame.
* The @p aOffset value will be truncated to become a multiple of 8.
*
* @param[in] aFrame The pointer to the frame.
* @param[in] aFrameLength The length of the frame.
*
* @retval OT_ERROR_NONE Fragment Header initialized successfully.
* @retval OT_ERROR_PARSE Fragment header could not be parsed from @p aFrame.
* @param[in] aSize The Datagram Size value.
* @param[in] aTage The Datagram Tag value.
* @param[in] aOffset The Datagram Offset value.
*
*/
otError Init(const uint8_t *aFrame, uint16_t aFrameLength);
void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset);
/**
* This method initializes the fragment header from a message @p aMessage.
* This static method indicates whether or not the header (in a given frame) is a Fragment Header.
*
* @param[in] aMessage The message object.
* @param[in] aOffset An offset into the message to read the header.
*
* @retval OT_ERROR_NONE Fragment Header initialized successfully.
* @retval OT_ERROR_PARSE Fragment header could not be parsed from @p aMessage.
*
*/
otError Init(const Message &aMessage, uint16_t aOffset);
/**
* This method indicates whether or not the header is a Fragment Header.
* @note This method checks whether the frame has the minimum required length and that the first byte in
* header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the
* Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header.
*
* @retval TRUE If the header matches the Fragment Header dispatch value.
* @retval FALSE If the header does not match the Fragment Header dispatch value.
*
*/
bool IsFragmentHeader(void) const { return (HostSwap16(mDispatchSize) & kDispatchMask) == kDispatch; }
static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
/**
* This method returns the Fragment Header length.
* This method parses the Fragment Header from a frame @p aFrame.
*
* @returns The Fragment Header length in bytes.
* @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 OT_ERROR_NONE Fragment Header parsed successfully.
* @retval OT_ERROR_PARSE Fragment header could not be parsed from @p aFrame.
*
*/
uint8_t GetHeaderLength(void) const { return IsOffsetPresent() ? sizeof(*this) : sizeof(*this) - sizeof(mOffset); }
otError ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
/**
* This method indicates whether or not the Offset field is present.
* This method parses the Fragment Header from a message.
*
* @returns TRUE if the Offset field is present, FALSE otherwise.
* @param[in] aMessage The message to read from.
* @param[in] aOffset The offset within the message to start reading from.
* @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
*
* @retval OT_ERROR_NONE Fragment Header parsed successfully.
* @retval OT_ERROR_PARSE Fragment header could not be parsed from @p aFrame.
*
*/
bool IsOffsetPresent(void) const { return (HostSwap16(mDispatchSize) & kOffset) != 0; }
otError ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength);
/**
* This method returns the Datagram Size value.
@@ -632,18 +627,7 @@ public:
* @returns The Datagram Size value.
*
*/
uint16_t GetDatagramSize(void) const { return HostSwap16(mDispatchSize) & kSizeMask; }
/**
* This method sets the Datagram Size value.
*
* @param[in] aSize The Datagram Size value.
*
*/
void SetDatagramSize(uint16_t aSize)
{
mDispatchSize = HostSwap16((HostSwap16(mDispatchSize) & ~kSizeMask) | (aSize & kSizeMask));
}
uint16_t GetDatagramSize(void) const { return mSize; }
/**
* This method returns the Datagram Tag value.
@@ -651,57 +635,47 @@ public:
* @returns The Datagram Tag value.
*
*/
uint16_t GetDatagramTag(void) const { return HostSwap16(mTag); }
/**
* This method sets the Datagram Tag value.
*
* @param[in] aTag The Datagram Tag value.
*
*/
void SetDatagramTag(uint16_t aTag) { mTag = HostSwap16(aTag); }
uint16_t GetDatagramTag(void) const { return mTag; }
/**
* This method returns the Datagram Offset value.
*
* @returns The Datagram Offset value.
* The returned offset value is always multiple of 8.
*
* @returns The Datagram Offset value (multiple of 8).
*
*/
uint16_t GetDatagramOffset(void) const { return IsOffsetPresent() ? static_cast<uint16_t>(mOffset) * 8 : 0; }
uint16_t GetDatagramOffset(void) const { return mOffset; }
/**
* This method sets the Datagram Offset value.
* This method writes the Fragment Header into a given frame.
*
* @param[in] aOffset The Datagram Offset value.
* @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).
*
*/
void SetDatagramOffset(uint16_t aOffset)
{
if (aOffset == 0)
{
mDispatchSize = HostSwap16(HostSwap16(mDispatchSize) & ~kOffset);
}
else
{
mDispatchSize = HostSwap16(HostSwap16(mDispatchSize) | kOffset);
mOffset = (aOffset >> 3) & kOffsetMask;
}
}
uint16_t WriteTo(uint8_t *aFrame) const;
private:
enum
{
kDispatch = 3 << 14,
kOffset = 1 << 13,
kDispatchMask = 0xd800, ///< Accept FRAG1 and FRAGN only.
kSizeMask = 0x7ff,
kOffsetMask = 0xff,
kDispatch = 0xc0, // 0b1100_0000
kDispatchMask = 0xd8, // 0b1101_1000 which accepts first frag (0b1100_0xxx) and next frag (0b1110_0xxx).
kOffsetFlag = 1 << 5, // Dispatch flag to indicate first (no offset) vs. next (offset is present) fragment.
kSizeMask = 0x7ff, // 0b0111_1111_1111 (first 11 bits).
kOffsetMask = 0xfff8, // Clears the last 3 bits to ensure offset is a multiple of 8.
kSizeIndex = 0, // Start index of Size field in the Fragment Header byte sequence.
kTagIndex = 2, // Start index of Tag field in the Fragment Header byte sequence.
kOffsetIndex = 4, // Start index of Offset field in the Fragment Header byte sequence.
};
uint16_t mDispatchSize;
uint16_t mSize;
uint16_t mTag;
uint8_t mOffset;
} OT_TOOL_PACKED_END;
uint16_t mOffset;
};
/**
* @}
+25 -43
View File
@@ -389,21 +389,6 @@ void MeshForwarder::GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::
}
}
otError MeshForwarder::GetFragmentHeader(const uint8_t * aFrame,
uint16_t aFrameLength,
Lowpan::FragmentHeader &aFragmentHeader)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(aFrameLength >= 1 && reinterpret_cast<const Lowpan::FragmentHeader *>(aFrame)->IsFragmentHeader(),
error = OT_ERROR_NOT_FOUND);
SuccessOrExit(error = aFragmentHeader.Init(aFrame, aFrameLength));
exit:
return error;
}
otError MeshForwarder::DecompressIp6Header(const uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMacSource,
@@ -415,14 +400,15 @@ otError MeshForwarder::DecompressIp6Header(const uint8_t * aFrame,
otError error = OT_ERROR_NONE;
const uint8_t * start = aFrame;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
int headerLength;
if (GetFragmentHeader(aFrame, aFrameLength, fragmentHeader) == OT_ERROR_NONE)
if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == OT_ERROR_NONE)
{
// only the first fragment header is followed by a LOWPAN_IPHC header
// Only the first fragment header is followed by a LOWPAN_IPHC header
VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = OT_ERROR_NOT_FOUND);
aFrame += fragmentHeader.GetHeaderLength();
aFrameLength -= fragmentHeader.GetHeaderLength();
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
}
VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = OT_ERROR_NOT_FOUND);
@@ -700,7 +686,7 @@ start:
if (aMessage.GetOffset() == 0)
{
Lowpan::BufferWriter buffer(payload, aFrame.GetMaxPayloadLength() - headerLength -
Lowpan::FragmentHeader::kInitialHeaderSize);
Lowpan::FragmentHeader::kFirstFragmentHeaderSize);
uint8_t hcLength;
Mac::Address meshSource, meshDest;
otError error;
@@ -712,8 +698,8 @@ start:
}
else
{
meshDest = aMacDest;
meshSource = aMacSource;
meshDest = aMacDest;
}
error = Get<Lowpan::Lowpan>().Compress(aMessage, meshSource, meshDest, buffer);
@@ -726,7 +712,7 @@ start:
if (payloadLength > fragmentLength)
{
Lowpan::FragmentHeader *fragmentHeader;
Lowpan::FragmentHeader fragmentHeader;
if ((!aMessage.IsLinkSecurityEnabled()) && aMessage.IsSubTypeMle())
{
@@ -748,16 +734,13 @@ start:
aMessage.SetDatagramTag(mFragTag++);
}
memmove(payload + Lowpan::FragmentHeader::kInitialHeaderSize, payload, hcLength);
memmove(payload + Lowpan::FragmentHeader::kFirstFragmentHeaderSize, payload, hcLength);
fragmentHeader = reinterpret_cast<Lowpan::FragmentHeader *>(payload);
fragmentHeader->Init();
fragmentHeader->SetDatagramSize(aMessage.GetLength());
fragmentHeader->SetDatagramTag(static_cast<uint16_t>(aMessage.GetDatagramTag()));
fragmentHeader->SetDatagramOffset(0);
fragmentHeader.InitFirstFragment(aMessage.GetLength(), static_cast<uint16_t>(aMessage.GetDatagramTag()));
fragmentHeader.WriteTo(payload);
payload += fragmentHeader->GetHeaderLength();
headerLength += fragmentHeader->GetHeaderLength();
payload += Lowpan::FragmentHeader::kFirstFragmentHeaderSize;
headerLength += Lowpan::FragmentHeader::kFirstFragmentHeaderSize;
payloadLength = (aFrame.GetMaxPayloadLength() - headerLength) & ~0x7;
}
@@ -772,19 +755,18 @@ start:
}
else
{
Lowpan::FragmentHeader *fragmentHeader;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
// Write Fragment header
fragmentHeader = reinterpret_cast<Lowpan::FragmentHeader *>(payload);
fragmentHeader->Init();
fragmentHeader->SetDatagramSize(aMessage.GetLength());
fragmentHeader->SetDatagramTag(static_cast<uint16_t>(aMessage.GetDatagramTag()));
fragmentHeader->SetDatagramOffset(aMessage.GetOffset());
fragmentHeader.Init(aMessage.GetLength(), static_cast<uint16_t>(aMessage.GetDatagramTag()),
aMessage.GetOffset());
fragmentHeaderLength = fragmentHeader.WriteTo(payload);
payload += fragmentHeader->GetHeaderLength();
headerLength += fragmentHeader->GetHeaderLength();
payload += fragmentHeaderLength;
headerLength += fragmentHeaderLength;
fragmentLength = (aFrame.GetMaxPayloadLength() - headerLength) & ~0x7;
@@ -1048,8 +1030,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
HandleMesh(payload, payloadLength, macSource, linkInfo);
#endif
}
else if (payloadLength >= sizeof(Lowpan::FragmentHeader) &&
reinterpret_cast<Lowpan::FragmentHeader *>(payload)->IsFragmentHeader())
else if (Lowpan::FragmentHeader::IsFragmentHeader(payload, payloadLength))
{
HandleFragment(payload, payloadLength, macSource, macDest, linkInfo);
}
@@ -1090,12 +1071,13 @@ void MeshForwarder::HandleFragment(uint8_t * aFrame,
{
otError error = OT_ERROR_NONE;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
Message * message = NULL;
// Check the fragment header
SuccessOrExit(error = fragmentHeader.Init(aFrame, aFrameLength));
aFrame += fragmentHeader.GetHeaderLength();
aFrameLength -= fragmentHeader.GetHeaderLength();
SuccessOrExit(error = fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength));
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
if (fragmentHeader.GetDatagramOffset() == 0)
{
-5
View File
@@ -375,11 +375,6 @@ private:
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const otThreadLinkInfo &aLinkInfo);
static otError GetFragmentHeader(const uint8_t * aFrame,
uint16_t aFrameLength,
Lowpan::FragmentHeader &aFragmentHeader);
uint16_t PrepareDataFrame(Mac::TxFrame & aFrame,
Message & aMessage,
const Mac::Address &aMacSource,
+10 -9
View File
@@ -524,7 +524,7 @@ void MeshForwarder::HandleMesh(uint8_t * aFrame,
if (meshDest.GetShort() == Get<Mac::Mac>().GetShortAddress() ||
Get<Mle::MleRouter>().IsMinimalChild(meshDest.GetShort()))
{
if (reinterpret_cast<Lowpan::FragmentHeader *>(aFrame)->IsFragmentHeader())
if (Lowpan::FragmentHeader::IsFragmentHeader(aFrame, aFrameLength))
{
HandleFragment(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
}
@@ -740,12 +740,13 @@ otError MeshForwarder::GetForwardFramePriority(const uint8_t * aFrame,
otError error = OT_ERROR_NONE;
bool isFragment = false;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
if (GetFragmentHeader(aFrame, aFrameLength, fragmentHeader) == OT_ERROR_NONE)
if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == OT_ERROR_NONE)
{
isFragment = true;
aFrame += fragmentHeader.GetHeaderLength();
aFrameLength -= fragmentHeader.GetHeaderLength();
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
if (fragmentHeader.GetDatagramOffset() > 0)
{
@@ -848,19 +849,19 @@ otError MeshForwarder::LogMeshFragmentHeader(MessageAction aAction,
bool shouldLogRss;
Lowpan::MeshHeader meshHeader;
Lowpan::FragmentHeader fragmentHeader;
uint16_t meshHeaderLength;
uint16_t headerLength;
SuccessOrExit(meshHeader.ParseFrom(aMessage, meshHeaderLength));
SuccessOrExit(meshHeader.ParseFrom(aMessage, headerLength));
aMeshSource.SetShort(meshHeader.GetSource());
aMeshDest.SetShort(meshHeader.GetDestination());
aOffset = meshHeaderLength;
aOffset = headerLength;
if (fragmentHeader.Init(aMessage, aOffset) == OT_ERROR_NONE)
if (fragmentHeader.ParseFrom(aMessage, aOffset, headerLength) == OT_ERROR_NONE)
{
hasFragmentHeader = true;
aOffset += fragmentHeader.GetHeaderLength();
aOffset += headerLength;
}
shouldLogRss = (aAction == kMessageReceive) || (aAction == kMessageReassemblyDrop);