aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbtin Keshavarzian <abtink@google.com>2022-07-14 17:04:47 -0700
committerGitHub <noreply@github.com>2022-07-14 17:04:47 -0700
commit13416b15fb8ea97c3d9ccc1e5f7d0fc1cf05e06c (patch)
tree71e81481a000cd57912458908ea5c645e8771492
parent366786dbed79745045fc47b1721e63a7f488ac57 (diff)
downloadopenthread-13416b15fb8ea97c3d9ccc1e5f7d0fc1cf05e06c.tar.gz
[core] adding `FrameData` class for parsing frames (#7892)
This commit adds a new class `FrameData` which is a sub-class of `Data` (acts as a wrapper over a buffer pointer and a length). It is used in `MeshForwarder` and `Lowpan` to simplify the method calls (can pass `FrameData` instance instead of pointer and length). It also provides helper methods for parsing the frame content (e.g., reading `uint16/32` value assuming big or little endian encoding). When read successfully, the `FrameData` is updated to skip over the read content. These methods help simplify `Lowpan` parsing and decompression code. In particular the `Lowpan` methods now directly update the passed-in `FrameData` to skip over the parsed header portion (instead of returning the parsed header length).
-rw-r--r--Android.mk1
-rw-r--r--src/core/BUILD.gn2
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/Makefile.am2
-rw-r--r--src/core/common/frame_data.cpp107
-rw-r--r--src/core/common/frame_data.hpp177
-rw-r--r--src/core/common/message.hpp35
-rw-r--r--src/core/net/ip6.cpp42
-rw-r--r--src/core/net/ip6.hpp7
-rw-r--r--src/core/thread/lowpan.cpp345
-rw-r--r--src/core/thread/lowpan.hpp133
-rw-r--r--src/core/thread/mesh_forwarder.cpp81
-rw-r--r--src/core/thread/mesh_forwarder.hpp29
-rw-r--r--src/core/thread/mesh_forwarder_ftd.cpp63
-rw-r--r--tests/unit/test_lowpan.cpp126
15 files changed, 738 insertions, 413 deletions
diff --git a/Android.mk b/Android.mk
index 01b85201f..863059fb4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -231,6 +231,7 @@ LOCAL_SRC_FILES := \
src/core/common/crc16.cpp \
src/core/common/data.cpp \
src/core/common/error.cpp \
+ src/core/common/frame_data.cpp \
src/core/common/heap.cpp \
src/core/common/heap_data.cpp \
src/core/common/heap_string.cpp \
diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn
index b7d71ab40..e0b58d431 100644
--- a/src/core/BUILD.gn
+++ b/src/core/BUILD.gn
@@ -397,6 +397,8 @@ openthread_core_files = [
"common/error.cpp",
"common/error.hpp",
"common/extension.hpp",
+ "common/frame_data.cpp",
+ "common/frame_data.hpp",
"common/heap.cpp",
"common/heap.hpp",
"common/heap_allocatable.hpp",
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 40b50355d..e2d090872 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -97,6 +97,7 @@ set(COMMON_SOURCES
common/crc16.cpp
common/data.cpp
common/error.cpp
+ common/frame_data.cpp
common/heap.cpp
common/heap_data.cpp
common/heap_string.cpp
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 394ac25df..1440810aa 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -187,6 +187,7 @@ SOURCES_COMMON = \
common/crc16.cpp \
common/data.cpp \
common/error.cpp \
+ common/frame_data.cpp \
common/heap.cpp \
common/heap_data.cpp \
common/heap_string.cpp \
@@ -437,6 +438,7 @@ HEADERS_COMMON = \
common/equatable.hpp \
common/error.hpp \
common/extension.hpp \
+ common/frame_data.hpp \
common/heap.hpp \
common/heap_allocatable.hpp \
common/heap_array.hpp \
diff --git a/src/core/common/frame_data.cpp b/src/core/common/frame_data.cpp
new file mode 100644
index 000000000..760704186
--- /dev/null
+++ b/src/core/common/frame_data.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes implementation of `FrameData`.
+ */
+
+#include "frame_data.hpp"
+
+#include "common/code_utils.hpp"
+#include "common/encoding.hpp"
+
+namespace ot {
+
+Error FrameData::ReadUint8(uint8_t &aUint8)
+{
+ return ReadBytes(&aUint8, sizeof(uint8_t));
+}
+
+Error FrameData::ReadBigEndianUint16(uint16_t &aUint16)
+{
+ Error error;
+
+ SuccessOrExit(error = ReadBytes(&aUint16, sizeof(uint16_t)));
+ aUint16 = Encoding::BigEndian::HostSwap16(aUint16);
+
+exit:
+ return error;
+}
+
+Error FrameData::ReadBigEndianUint32(uint32_t &aUint32)
+{
+ Error error;
+
+ SuccessOrExit(error = ReadBytes(&aUint32, sizeof(uint32_t)));
+ aUint32 = Encoding::BigEndian::HostSwap32(aUint32);
+
+exit:
+ return error;
+}
+
+Error FrameData::ReadLittleEndianUint16(uint16_t &aUint16)
+{
+ Error error;
+
+ SuccessOrExit(error = ReadBytes(&aUint16, sizeof(uint16_t)));
+ aUint16 = Encoding::LittleEndian::HostSwap16(aUint16);
+
+exit:
+ return error;
+}
+
+Error FrameData::ReadLittleEndianUint32(uint32_t &aUint32)
+{
+ Error error;
+
+ SuccessOrExit(error = ReadBytes(&aUint32, sizeof(uint32_t)));
+ aUint32 = Encoding::LittleEndian::HostSwap32(aUint32);
+
+exit:
+ return error;
+}
+
+Error FrameData::ReadBytes(void *aBuffer, uint16_t aLength)
+{
+ Error error = kErrorNone;
+
+ VerifyOrExit(CanRead(aLength), error = kErrorParse);
+ memcpy(aBuffer, GetBytes(), aLength);
+ SkipOver(aLength);
+
+exit:
+ return error;
+}
+
+void FrameData::SkipOver(uint16_t aLength)
+{
+ Init(GetBytes() + aLength, GetLength() - aLength);
+}
+
+} // namespace ot
diff --git a/src/core/common/frame_data.hpp b/src/core/common/frame_data.hpp
new file mode 100644
index 000000000..336a78279
--- /dev/null
+++ b/src/core/common/frame_data.hpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definitions for `FrameData`.
+ */
+
+#ifndef FRAME_DATA_HPP_
+#define FRAME_DATA_HPP_
+
+#include "openthread-core-config.h"
+
+#include "common/data.hpp"
+#include "common/type_traits.hpp"
+
+namespace ot {
+
+/**
+ * This class represents a frame `Data` which is simply a wrapper over a pointer to a buffer with a given frame length.
+ *
+ * It provide helper method to parse the content. As data is parsed and read, the `FrameData` is updated to skip over
+ * the read content.
+ *
+ */
+class FrameData : public Data<kWithUint16Length>
+{
+public:
+ /**
+ * This method indicates whether or not there are enough bytes remaining in the `FrameData` to read a given number
+ * of bytes.
+ *
+ * @param[in] aLength The read length to check.
+ *
+ * @retval TRUE There are enough remaining bytes to read @p aLength bytes.
+ * @retval FALSE There are not enough remaining bytes to read @p aLength bytes.
+ *
+ */
+ bool CanRead(uint16_t aLength) const { return GetLength() >= aLength; }
+
+ /**
+ * This method reads an `uint8_t` value from the `FrameData`.
+ *
+ * If read successfully, the `FrameData` is updated to skip over the read content.
+ *
+ * @param[out] aUint8 A reference to an `uint8_t` to return the read value.
+ *
+ * @retval kErrorNone Successfully read `uint8_t` value and skipped over it.
+ * @retval kErrorParse Not enough bytes remaining to read.
+ *
+ */
+ Error ReadUint8(uint8_t &aUint8);
+
+ /**
+ * This method reads an `uint16_t` value assuming big endian encoding from the `FrameData`.
+ *
+ * If read successfully, the `FrameData` is updated to skip over the read content.
+ *
+ * @param[out] aUint16 A reference to an `uint16_t` to return the read value.
+ *
+ * @retval kErrorNone Successfully read `uint16_t` value and skipped over it.
+ * @retval kErrorParse Not enough bytes remaining to read.
+ *
+ */
+ Error ReadBigEndianUint16(uint16_t &aUint16);
+
+ /**
+ * This method reads an `uint32_t` value assuming big endian encoding from the `FrameData`.
+ *
+ * If read successfully, the `FrameData` is updated to skip over the read content.
+ *
+ * @param[out] aUint32 A reference to an `uint32_t` to return the read value.
+ *
+ * @retval kErrorNone Successfully read `uint32_t` value and skipped over it.
+ * @retval kErrorParse Not enough bytes remaining to read.
+ *
+ */
+ Error ReadBigEndianUint32(uint32_t &aUint32);
+
+ /**
+ * This method reads an `uint16_t` value assuming little endian encoding from the `FrameData`.
+ *
+ * If read successfully, the `FrameData` is updated to skip over the read content.
+ *
+ * @param[out] aUint16 A reference to an `uint16_t` to return the read value.
+ *
+ * @retval kErrorNone Successfully read `uint16_t` value and skipped over it.
+ * @retval kErrorParse Not enough bytes remaining to read.
+ *
+ */
+ Error ReadLittleEndianUint16(uint16_t &aUint16);
+
+ /**
+ * This method reads an `uint32_t` value assuming little endian encoding from the `FrameData`.
+ *
+ * If read successfully, the `FrameData` is updated to skip over the read content.
+ *
+ * @param[out] aUint32 A reference to an `uint32_t` to return the read value.
+ *
+ * @retval kErrorNone Successfully read `uint32_t` value and skipped over it.
+ * @retval kErrorParse Not enough bytes remaining to read.
+ *
+ */
+ Error ReadLittleEndianUint32(uint32_t &aUint32);
+
+ /**
+ * This method reads a given number of bytes from the `FrameData`.
+ *
+ * If read successfully, the `FrameData` is updated to skip over the read content.
+ *
+ * @param[out] aBuffer The buffer to copy the read bytes into.
+ * @param[in] aLength Number of bytes to read.
+ *
+ * @retval kErrorNone Successfully read @p aLength bytes into @p aBuffer and skipped over them.
+ * @retval kErrorParse Not enough bytes remaining to read @p aLength.
+ *
+ */
+ Error ReadBytes(void *aBuffer, uint16_t aLength);
+
+ /**
+ * This template method reads an object from the `FrameData`.
+ *
+ * @tparam ObjectType The object type to read from the message.
+ *
+ * @param[out] aObject A reference to the object to read into.
+ *
+ * @retval kErrorNone Successfully read @p aObject and skipped over the read content.
+ * @retval kErrorParse Not enough bytes remaining to read the entire object.
+ *
+ */
+ template <typename ObjectType> Error Read(ObjectType &aObject)
+ {
+ static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
+
+ return ReadBytes(&aObject, sizeof(ObjectType));
+ }
+
+ /**
+ * This method skips over a given number of bytes from `FrameData`.
+ *
+ * The caller MUST make sure that the @p aLength is smaller than current data length. Otherwise the behavior of
+ * this method is undefined.
+ *
+ * @param[in] aLength The length (number of bytes) to skip over.
+ *
+ */
+ void SkipOver(uint16_t aLength);
+};
+
+} // namespace ot
+
+#endif // FRAME_DATA_HPP_
diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp
index ea0424c32..8d4c7429a 100644
--- a/src/core/common/message.hpp
+++ b/src/core/common/message.hpp
@@ -663,6 +663,24 @@ public:
}
/**
+ * This method appends bytes from a given `Data` instance to the end of the message.
+ *
+ * On success, this method grows the message by the size of the appended data.
+ *
+ * @tparam kDataLengthType Determines the data length type (`uint8_t` or `uint16_t`).
+ *
+ * @param[in] aData A reference to `Data` to append to the message.
+ *
+ * @retval kErrorNone Successfully appended the bytes from @p aData.
+ * @retval kErrorNoBufs Insufficient available buffers to grow the message.
+ *
+ */
+ template <DataLengthType kDataLengthType> Error AppendData(const Data<kDataLengthType> &aData)
+ {
+ return AppendBytes(aData.GetBytes(), aData.GetLength());
+ }
+
+ /**
* This method reads bytes from the message.
*
* @param[in] aOffset Byte offset within the message to begin reading.
@@ -808,6 +826,23 @@ public:
}
/**
+ * This method writes bytes from a given `Data` instance to the message.
+ *
+ * This method will not resize the message. The given data to write MUST fit within the existing message buffer
+ * (from the given offset @p aOffset up to the message's length).
+ *
+ * @tparam kDataLengthType Determines the data length type (`uint8_t` or `uint16_t`).
+ *
+ * @param[in] aOffset Byte offset within the message to begin writing.
+ * @param[in] aData The `Data` to write to the message.
+ *
+ */
+ template <DataLengthType kDataLengthType> void WriteData(uint16_t aOffset, const Data<kDataLengthType> &aData)
+ {
+ WriteBytes(aOffset, aData.GetBytes(), aData.GetLength());
+ }
+
+ /**
* This method copies bytes from one message to another.
*
* If source and destination messages are the same, `CopyTo()` can be used to perform a backward copy, but
diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp
index 7fda32910..bb3096fd6 100644
--- a/src/core/net/ip6.cpp
+++ b/src/core/net/ip6.cpp
@@ -1534,66 +1534,56 @@ Error Headers::DecompressFrom(const Message & aMessage,
{
static constexpr uint16_t kReadLength = Lowpan::FragmentHeader::kSubsequentFragmentHeaderSize + sizeof(Headers);
- uint8_t frameBuffer[kReadLength];
- uint16_t frameLength;
+ uint8_t frameBuffer[kReadLength];
+ uint16_t frameLength;
+ FrameData frameData;
frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(frameBuffer));
+ frameData.Init(frameBuffer, frameLength);
- return DecompressFrom(frameBuffer, frameLength, aMacSource, aMacDest, aMessage.GetInstance());
+ return DecompressFrom(frameData, aMacSource, aMacDest, aMessage.GetInstance());
}
-Error Headers::DecompressFrom(const uint8_t * aFrame,
- uint16_t aFrameLength,
+Error Headers::DecompressFrom(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Instance & aInstance)
{
- Error error = kErrorNone;
+ Error error = kErrorNone;
+ FrameData frameData = aFrameData;
Lowpan::FragmentHeader fragmentHeader;
- uint16_t fragmentHeaderLength;
- int headerLength;
bool nextHeaderCompressed;
- if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
+ if (fragmentHeader.ParseFrom(frameData) == kErrorNone)
{
// Only the first fragment header is followed by a LOWPAN_IPHC header
VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = kErrorNotFound);
- aFrame += fragmentHeaderLength;
- aFrameLength -= fragmentHeaderLength;
}
- VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound);
- headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressBaseHeader(mIp6Header, nextHeaderCompressed, aMacSource,
- aMacDest, aFrame, aFrameLength);
+ VerifyOrExit(Lowpan::Lowpan::IsLowpanHc(frameData), error = kErrorNotFound);
- VerifyOrExit(headerLength > 0, error = kErrorParse);
-
- aFrame += headerLength;
- aFrameLength -= headerLength;
+ SuccessOrExit(error = aInstance.Get<Lowpan::Lowpan>().DecompressBaseHeader(mIp6Header, nextHeaderCompressed,
+ aMacSource, aMacDest, frameData));
switch (mIp6Header.GetNextHeader())
{
case kProtoUdp:
if (nextHeaderCompressed)
{
- headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressUdpHeader(mHeader.mUdp, aFrame, aFrameLength);
- VerifyOrExit(headerLength >= 0, error = kErrorParse);
+ SuccessOrExit(error = aInstance.Get<Lowpan::Lowpan>().DecompressUdpHeader(mHeader.mUdp, frameData));
}
else
{
- VerifyOrExit(aFrameLength >= sizeof(Udp::Header), error = kErrorParse);
- mHeader.mUdp = *reinterpret_cast<const Udp::Header *>(aFrame);
+ SuccessOrExit(error = frameData.Read(mHeader.mUdp));
}
break;
case kProtoTcp:
- VerifyOrExit(aFrameLength >= sizeof(Tcp::Header), error = kErrorParse);
- mHeader.mTcp = *reinterpret_cast<const Tcp::Header *>(aFrame);
+ SuccessOrExit(error = frameData.Read(mHeader.mTcp));
break;
case kProtoIcmp6:
- VerifyOrExit(aFrameLength >= sizeof(Icmp::Header), error = kErrorParse);
- mHeader.mIcmp = *reinterpret_cast<const Icmp::Header *>(aFrame);
+ SuccessOrExit(error = frameData.Read(mHeader.mIcmp));
break;
default:
diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp
index 3fb9678d9..5e695ccaf 100644
--- a/src/core/net/ip6.hpp
+++ b/src/core/net/ip6.hpp
@@ -42,6 +42,7 @@
#include <openthread/udp.h>
#include "common/encoding.hpp"
+#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
#include "common/message.hpp"
@@ -416,8 +417,7 @@ public:
/**
* This method decompresses lowpan frame and parses the IPv6 and UDP/TCP/ICMP6 headers.
*
- * @param[in] aFrame Buffer containig the lowpan frame.
- * @param[in] aFrameLength Number of bytes in @p aFrame.
+ * @param[in] aFrameData The lowpan frame data.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in] aInstance The OpenThread instance.
@@ -427,8 +427,7 @@ public:
* @retval kErrorParse Failed to parse the headers.
*
*/
- Error DecompressFrom(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ Error DecompressFrom(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Instance & aInstance);
diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp
index 3aca0f8d5..cfda2ee8e 100644
--- a/src/core/thread/lowpan.cpp
+++ b/src/core/thread/lowpan.cpp
@@ -655,26 +655,21 @@ exit:
return error;
}
-int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
- bool & aCompressedNextHeader,
- const Mac::Address &aMacSource,
- const Mac::Address &aMacDest,
- const uint8_t * aBuf,
- uint16_t aBufLength)
+Error Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
+ bool & aCompressedNextHeader,
+ const Mac::Address &aMacSource,
+ const Mac::Address &aMacDest,
+ FrameData & aFrameData)
{
NetworkData::Leader &networkData = Get<NetworkData::Leader>();
Error error = kErrorParse;
- const uint8_t * cur = aBuf;
- const uint8_t * end = aBuf + aBufLength;
uint16_t hcCtl;
+ uint8_t byte;
Context srcContext, dstContext;
bool srcContextValid = true, dstContextValid = true;
uint8_t nextHeader;
- uint8_t * bytes;
- VerifyOrExit(cur + 2 <= end);
- hcCtl = ReadUint16(cur);
- cur += 2;
+ SuccessOrExit(aFrameData.ReadBigEndianUint16(hcCtl));
// check Dispatch bits
VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch);
@@ -685,19 +680,17 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
if ((hcCtl & kHcContextId) != 0)
{
- VerifyOrExit(cur < end);
+ SuccessOrExit(aFrameData.ReadUint8(byte));
- if (networkData.GetContext(cur[0] >> 4, srcContext) != kErrorNone)
+ if (networkData.GetContext(byte >> 4, srcContext) != kErrorNone)
{
srcContextValid = false;
}
- if (networkData.GetContext(cur[0] & 0xf, dstContext) != kErrorNone)
+ if (networkData.GetContext(byte & 0xf, dstContext) != kErrorNone)
{
dstContextValid = false;
}
-
- cur++;
}
else
{
@@ -711,34 +704,35 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
// Traffic Class and Flow Label
if ((hcCtl & kHcTrafficFlowMask) != kHcTrafficFlow)
{
- VerifyOrExit(cur < end);
+ uint8_t *ip6HeaderBytes = reinterpret_cast<uint8_t *>(&aIp6Header);
+
+ VerifyOrExit(aFrameData.GetLength() > 0);
- bytes = reinterpret_cast<uint8_t *>(&aIp6Header);
- bytes[1] |= (cur[0] & 0xc0) >> 2;
+ ip6HeaderBytes[1] |= (aFrameData.GetBytes()[0] & 0xc0) >> 2;
if ((hcCtl & kHcTrafficClass) == 0)
{
- bytes[0] |= (cur[0] >> 2) & 0x0f;
- bytes[1] |= (cur[0] << 6) & 0xc0;
- cur++;
+ IgnoreError(aFrameData.ReadUint8(byte));
+ ip6HeaderBytes[0] |= (byte >> 2) & 0x0f;
+ ip6HeaderBytes[1] |= (byte << 6) & 0xc0;
}
if ((hcCtl & kHcFlowLabel) == 0)
{
- VerifyOrExit(cur + 3 <= end);
- bytes[1] |= cur[0] & 0x0f;
- bytes[2] |= cur[1];
- bytes[3] |= cur[2];
- cur += 3;
+ VerifyOrExit(aFrameData.GetLength() >= 3);
+ ip6HeaderBytes[1] |= aFrameData.GetBytes()[0] & 0x0f;
+ ip6HeaderBytes[2] |= aFrameData.GetBytes()[1];
+ ip6HeaderBytes[3] |= aFrameData.GetBytes()[2];
+ aFrameData.SkipOver(3);
}
}
// Next Header
if ((hcCtl & kHcNextHeader) == 0)
{
- VerifyOrExit(cur < end);
- aIp6Header.SetNextHeader(cur[0]);
- cur++;
+ SuccessOrExit(aFrameData.ReadUint8(byte));
+
+ aIp6Header.SetNextHeader(byte);
aCompressedNextHeader = false;
}
else
@@ -762,9 +756,8 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
break;
default:
- VerifyOrExit(cur < end);
- aIp6Header.SetHopLimit(cur[0]);
- cur++;
+ SuccessOrExit(aFrameData.ReadUint8(byte));
+ aIp6Header.SetHopLimit(byte);
break;
}
@@ -774,25 +767,19 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
case kHcSrcAddrMode0:
if ((hcCtl & kHcSrcAddrContext) == 0)
{
- VerifyOrExit(cur + sizeof(Ip6::Address) <= end);
- memcpy(&aIp6Header.GetSource(), cur, sizeof(aIp6Header.GetSource()));
- cur += sizeof(Ip6::Address);
+ SuccessOrExit(aFrameData.Read(aIp6Header.GetSource()));
}
break;
case kHcSrcAddrMode1:
- VerifyOrExit(cur + Ip6::InterfaceIdentifier::kSize <= end);
- aIp6Header.GetSource().GetIid().SetBytes(cur);
- cur += Ip6::InterfaceIdentifier::kSize;
+ SuccessOrExit(aFrameData.Read(aIp6Header.GetSource().GetIid()));
break;
case kHcSrcAddrMode2:
- VerifyOrExit(cur + 2 <= end);
aIp6Header.GetSource().mFields.m8[11] = 0xff;
aIp6Header.GetSource().mFields.m8[12] = 0xfe;
- memcpy(aIp6Header.GetSource().mFields.m8 + 14, cur, 2);
- cur += 2;
+ SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetSource().mFields.m8 + 14, 2));
break;
case kHcSrcAddrMode3:
@@ -821,23 +808,17 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
{
case kHcDstAddrMode0:
VerifyOrExit((hcCtl & kHcDstAddrContext) == 0);
- VerifyOrExit(cur + sizeof(Ip6::Address) <= end);
- memcpy(&aIp6Header.GetDestination(), cur, sizeof(aIp6Header.GetDestination()));
- cur += sizeof(Ip6::Address);
+ SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination()));
break;
case kHcDstAddrMode1:
- VerifyOrExit(cur + Ip6::InterfaceIdentifier::kSize <= end);
- aIp6Header.GetDestination().GetIid().SetBytes(cur);
- cur += Ip6::InterfaceIdentifier::kSize;
+ SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination().GetIid()));
break;
case kHcDstAddrMode2:
- VerifyOrExit(cur + 2 <= end);
aIp6Header.GetDestination().mFields.m8[11] = 0xff;
aIp6Header.GetDestination().mFields.m8[12] = 0xfe;
- memcpy(aIp6Header.GetDestination().mFields.m8 + 14, cur, 2);
- cur += 2;
+ SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 14, 2));
break;
case kHcDstAddrMode3:
@@ -869,30 +850,22 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
switch (hcCtl & kHcDstAddrModeMask)
{
case kHcDstAddrMode0:
- VerifyOrExit(cur + sizeof(Ip6::Address) <= end);
- memcpy(aIp6Header.GetDestination().mFields.m8, cur, sizeof(Ip6::Address));
- cur += sizeof(Ip6::Address);
+ SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination()));
break;
case kHcDstAddrMode1:
- VerifyOrExit(cur + 6 <= end);
- aIp6Header.GetDestination().mFields.m8[1] = cur[0];
- memcpy(aIp6Header.GetDestination().mFields.m8 + 11, cur + 1, 5);
- cur += 6;
+ SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[1]));
+ SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 11, 5));
break;
case kHcDstAddrMode2:
- VerifyOrExit(cur + 4 <= end);
- aIp6Header.GetDestination().mFields.m8[1] = cur[0];
- memcpy(aIp6Header.GetDestination().mFields.m8 + 13, cur + 1, 3);
- cur += 4;
+ SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[1]));
+ SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 13, 3));
break;
case kHcDstAddrMode3:
- VerifyOrExit(cur < end);
- aIp6Header.GetDestination().mFields.m8[1] = 0x02;
- aIp6Header.GetDestination().mFields.m8[15] = cur[0];
- cur++;
+ aIp6Header.GetDestination().mFields.m8[1] = 0x02;
+ SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[15]));
break;
}
}
@@ -901,14 +874,11 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
switch (hcCtl & kHcDstAddrModeMask)
{
case 0:
- VerifyOrExit(cur + 6 <= end);
VerifyOrExit(dstContextValid);
- aIp6Header.GetDestination().mFields.m8[1] = cur[0];
- aIp6Header.GetDestination().mFields.m8[2] = cur[1];
+ SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 1, 2));
aIp6Header.GetDestination().mFields.m8[3] = dstContext.mPrefix.GetLength();
memcpy(aIp6Header.GetDestination().mFields.m8 + 4, dstContext.mPrefix.GetBytes(), 8);
- memcpy(aIp6Header.GetDestination().mFields.m8 + 12, cur + 2, 4);
- cur += 6;
+ SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 12, 4));
break;
default:
@@ -919,54 +889,41 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
if ((hcCtl & kHcNextHeader) != 0)
{
- VerifyOrExit(cur < end);
- SuccessOrExit(DispatchToNextHeader(cur[0], nextHeader));
+ VerifyOrExit(aFrameData.GetLength() > 0);
+ SuccessOrExit(DispatchToNextHeader(*aFrameData.GetBytes(), nextHeader));
aIp6Header.SetNextHeader(nextHeader);
}
error = kErrorNone;
exit:
- return (error == kErrorNone) ? static_cast<int>(cur - aBuf) : -1;
+ return error;
}
-int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength)
+Error Lowpan::DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData)
{
- Error error = kErrorParse;
- const uint8_t * cur = aBuf;
- const uint8_t * end = aBuf + aBufLength;
- uint8_t hdr[2];
- uint8_t len;
- uint8_t nextHeader;
- uint8_t ctl = cur[0];
- uint8_t padLength;
- Ip6::OptionPad1 optionPad1;
- Ip6::OptionPadN optionPadN;
-
- VerifyOrExit(cur < end);
- cur++;
+ Error error = kErrorParse;
+ uint8_t hdr[2];
+ uint8_t len;
+ uint8_t ctl;
+ uint8_t padLength;
+
+ SuccessOrExit(aFrameData.ReadUint8(ctl));
// next header
if (ctl & kExtHdrNextHeader)
{
- VerifyOrExit(cur < end);
+ SuccessOrExit(aFrameData.ReadUint8(len));
- len = cur[0];
- cur++;
-
- VerifyOrExit(cur + len <= end);
- SuccessOrExit(DispatchToNextHeader(cur[len], nextHeader));
- hdr[0] = static_cast<uint8_t>(nextHeader);
+ VerifyOrExit(aFrameData.CanRead(len + 1));
+ SuccessOrExit(DispatchToNextHeader(aFrameData.GetBytes()[len], hdr[0]));
}
else
{
- VerifyOrExit(cur + 2 <= end);
-
- hdr[0] = cur[0];
- len = cur[1];
- cur += 2;
+ SuccessOrExit(aFrameData.ReadUint8(hdr[0]));
+ SuccessOrExit(aFrameData.ReadUint8(len));
- VerifyOrExit(cur + len <= end);
+ VerifyOrExit(aFrameData.CanRead(len));
}
// length
@@ -976,9 +933,9 @@ int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, ui
aMessage.MoveOffset(sizeof(hdr));
// payload
- SuccessOrExit(aMessage.AppendBytes(cur, len));
+ SuccessOrExit(aMessage.AppendBytes(aFrameData.GetBytes(), len));
aMessage.MoveOffset(len);
- cur += len;
+ aFrameData.SkipOver(len);
// The RFC6282 says: "The trailing Pad1 or PadN option MAY be elided by the compressor.
// A decompressor MUST ensure that the containing header is padded out to a multiple of 8 octets
@@ -989,11 +946,15 @@ int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, ui
{
if (padLength == 1)
{
+ Ip6::OptionPad1 optionPad1;
+
optionPad1.Init();
SuccessOrExit(aMessage.AppendBytes(&optionPad1, padLength));
}
else
{
+ Ip6::OptionPadN optionPadN;
+
optionPadN.Init(padLength);
SuccessOrExit(aMessage.AppendBytes(&optionPadN, padLength));
}
@@ -1004,163 +965,145 @@ int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, ui
error = kErrorNone;
exit:
- return (error == kErrorNone) ? static_cast<int>(cur - aBuf) : -1;
+ return error;
}
-int Lowpan::DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength)
+Error Lowpan::DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData)
{
- Error error = kErrorParse;
- const uint8_t *cur = aBuf;
- const uint8_t *end = aBuf + aBufLength;
- uint8_t udpCtl;
+ Error error = kErrorParse;
+ uint8_t udpCtl;
+ uint8_t byte;
+ uint16_t srcPort = 0;
+ uint16_t dstPort = 0;
- VerifyOrExit(cur < end);
- udpCtl = cur[0];
- cur++;
+ SuccessOrExit(aFrameData.ReadUint8(udpCtl));
VerifyOrExit((udpCtl & kUdpDispatchMask) == kUdpDispatch);
- memset(&aUdpHeader, 0, sizeof(aUdpHeader));
+ aUdpHeader.Clear();
- // source and dest ports
switch (udpCtl & kUdpPortMask)
{
case 0:
- VerifyOrExit(cur + 4 <= end);
- aUdpHeader.SetSourcePort(ReadUint16(cur));
- aUdpHeader.SetDestinationPort(ReadUint16(cur + 2));
- cur += 4;
+ SuccessOrExit(aFrameData.ReadBigEndianUint16(srcPort));
+ SuccessOrExit(aFrameData.ReadBigEndianUint16(dstPort));
break;
case 1:
- VerifyOrExit(cur + 3 <= end);
- aUdpHeader.SetSourcePort(ReadUint16(cur));
- aUdpHeader.SetDestinationPort(0xf000 | cur[2]);
- cur += 3;
+ SuccessOrExit(aFrameData.ReadBigEndianUint16(srcPort));
+ SuccessOrExit(aFrameData.ReadUint8(byte));
+ dstPort = (0xf000 | byte);
break;
case 2:
- VerifyOrExit(cur + 3 <= end);
- aUdpHeader.SetSourcePort(0xf000 | cur[0]);
- aUdpHeader.SetDestinationPort(ReadUint16(cur + 1));
- cur += 3;
+ SuccessOrExit(aFrameData.ReadUint8(byte));
+ srcPort = (0xf000 | byte);
+ SuccessOrExit(aFrameData.ReadBigEndianUint16(dstPort));
break;
case 3:
- VerifyOrExit(cur < end);
- aUdpHeader.SetSourcePort(0xf0b0 | (cur[0] >> 4));
- aUdpHeader.SetDestinationPort(0xf0b0 | (cur[0] & 0xf));
- cur++;
+ SuccessOrExit(aFrameData.ReadUint8(byte));
+ srcPort = (0xf0b0 | (byte >> 4));
+ dstPort = (0xf0b0 | (byte & 0xf));
break;
}
- // checksum
+ aUdpHeader.SetSourcePort(srcPort);
+ aUdpHeader.SetDestinationPort(dstPort);
+
if ((udpCtl & kUdpChecksum) != 0)
{
ExitNow();
}
else
{
- VerifyOrExit(cur + 2 <= end);
- aUdpHeader.SetChecksum(ReadUint16(cur));
- cur += 2;
+ uint16_t checksum;
+
+ SuccessOrExit(aFrameData.ReadBigEndianUint16(checksum));
+ aUdpHeader.SetChecksum(checksum);
}
error = kErrorNone;
exit:
- return (error == kErrorNone) ? static_cast<int>(cur - aBuf) : -1;
+ return error;
}
-int Lowpan::DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength)
+Error Lowpan::DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength)
{
+ Error error;
Ip6::Udp::Header udpHeader;
- int headerLen = -1;
- headerLen = DecompressUdpHeader(udpHeader, aBuf, aBufLength);
- VerifyOrExit(headerLen >= 0);
+ SuccessOrExit(error = DecompressUdpHeader(udpHeader, aFrameData));
// length
if (aDatagramLength == 0)
{
- udpHeader.SetLength(sizeof(udpHeader) + static_cast<uint16_t>(aBufLength - headerLen));
+ udpHeader.SetLength(sizeof(udpHeader) + aFrameData.GetLength());
}
else
{
udpHeader.SetLength(aDatagramLength - aMessage.GetOffset());
}
- VerifyOrExit(aMessage.Append(udpHeader) == kErrorNone, headerLen = -1);
+ SuccessOrExit(error = aMessage.Append(udpHeader));
aMessage.MoveOffset(sizeof(udpHeader));
exit:
- return headerLen;
+ return error;
}
-int Lowpan::Decompress(Message & aMessage,
- const Mac::Address &aMacSource,
- const Mac::Address &aMacDest,
- const uint8_t * aBuf,
- uint16_t aBufLength,
- uint16_t aDatagramLength)
+Error Lowpan::Decompress(Message & aMessage,
+ const Mac::Address &aMacSource,
+ const Mac::Address &aMacDest,
+ FrameData & aFrameData,
+ uint16_t aDatagramLength)
{
- Error error = kErrorParse;
- Ip6::Header ip6Header;
- const uint8_t *cur = aBuf;
- uint16_t remaining = aBufLength;
- bool compressed;
- int rval;
- uint16_t ip6PayloadLength;
- uint16_t compressedLength = 0;
- uint16_t currentOffset = aMessage.GetOffset();
-
- VerifyOrExit(remaining >= 2);
- VerifyOrExit((rval = DecompressBaseHeader(ip6Header, compressed, aMacSource, aMacDest, cur, remaining)) >= 0);
-
- cur += rval;
- remaining -= rval;
+ Error error = kErrorParse;
+ Ip6::Header ip6Header;
+ bool compressed;
+ uint16_t ip6PayloadLength;
+ uint16_t currentOffset = aMessage.GetOffset();
+
+ SuccessOrExit(DecompressBaseHeader(ip6Header, compressed, aMacSource, aMacDest, aFrameData));
SuccessOrExit(aMessage.Append(ip6Header));
aMessage.MoveOffset(sizeof(ip6Header));
while (compressed)
{
- VerifyOrExit(remaining >= 1);
+ uint8_t byte;
- if ((cur[0] & kExtHdrDispatchMask) == kExtHdrDispatch)
+ VerifyOrExit(aFrameData.GetLength() > 0);
+ byte = *aFrameData.GetBytes();
+
+ if ((byte & kExtHdrDispatchMask) == kExtHdrDispatch)
{
- if ((cur[0] & kExtHdrEidMask) == kExtHdrEidIp6)
+ if ((byte & kExtHdrEidMask) == kExtHdrEidIp6)
{
compressed = false;
- cur++;
- remaining--;
+ aFrameData.SkipOver(sizeof(uint8_t));
- VerifyOrExit((rval = Decompress(aMessage, aMacSource, aMacDest, cur, remaining, aDatagramLength)) >= 0);
+ SuccessOrExit(Decompress(aMessage, aMacSource, aMacDest, aFrameData, aDatagramLength));
}
else
{
- compressed = (cur[0] & kExtHdrNextHeader) != 0;
- VerifyOrExit((rval = DecompressExtensionHeader(aMessage, cur, remaining)) >= 0);
+ compressed = (byte & kExtHdrNextHeader) != 0;
+ SuccessOrExit(DecompressExtensionHeader(aMessage, aFrameData));
}
}
- else if ((cur[0] & kUdpDispatchMask) == kUdpDispatch)
+ else if ((byte & kUdpDispatchMask) == kUdpDispatch)
{
compressed = false;
- VerifyOrExit((rval = DecompressUdpHeader(aMessage, cur, remaining, aDatagramLength)) >= 0);
+ SuccessOrExit(DecompressUdpHeader(aMessage, aFrameData, aDatagramLength));
}
else
{
ExitNow();
}
-
- VerifyOrExit(remaining >= rval);
- cur += rval;
- remaining -= rval;
}
- compressedLength = static_cast<uint16_t>(cur - aBuf);
-
if (aDatagramLength)
{
ip6PayloadLength = HostSwap16(aDatagramLength - currentOffset - sizeof(Ip6::Header));
@@ -1168,7 +1111,7 @@ int Lowpan::Decompress(Message & aMessage,
else
{
ip6PayloadLength =
- HostSwap16(aMessage.GetOffset() - currentOffset - sizeof(Ip6::Header) + aBufLength - compressedLength);
+ HostSwap16(aMessage.GetOffset() - currentOffset - sizeof(Ip6::Header) + aFrameData.GetLength());
}
aMessage.Write(currentOffset + Ip6::Header::kPayloadLengthFieldOffset, ip6PayloadLength);
@@ -1176,7 +1119,7 @@ int Lowpan::Decompress(Message & aMessage,
error = kErrorNone;
exit:
- return (error == kErrorNone) ? static_cast<int>(compressedLength) : -1;
+ return error;
}
Ip6::Ecn Lowpan::DecompressEcn(const Message &aMessage, uint16_t aOffset) const
@@ -1229,9 +1172,21 @@ void MeshHeader::Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft
mHopsLeft = aHopsLeft;
}
-bool MeshHeader::IsMeshHeader(const uint8_t *aFrame, uint16_t aFrameLength)
+bool MeshHeader::IsMeshHeader(const FrameData &aFrameData)
{
- return (aFrameLength >= kMinHeaderLength) && ((*aFrame & kDispatchMask) == kDispatch);
+ return (aFrameData.GetLength() >= kMinHeaderLength) && ((*aFrameData.GetBytes() & kDispatchMask) == kDispatch);
+}
+
+Error MeshHeader::ParseFrom(FrameData &aFrameData)
+{
+ Error error;
+ uint16_t headerLength;
+
+ SuccessOrExit(error = ParseFrom(aFrameData.GetBytes(), aFrameData.GetLength(), headerLength));
+ aFrameData.SkipOver(headerLength);
+
+exit:
+ return error;
}
Error MeshHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
@@ -1320,15 +1275,14 @@ uint16_t MeshHeader::WriteTo(uint8_t *aFrame) const
return static_cast<uint16_t>(cur - aFrame);
}
-uint16_t MeshHeader::WriteTo(Message &aMessage, uint16_t aOffset) const
+Error MeshHeader::AppendTo(Message &aMessage) const
{
uint8_t frame[kDeepHopsHeaderLength];
uint16_t headerLength;
headerLength = WriteTo(frame);
- aMessage.WriteBytes(aOffset, frame, headerLength);
- return headerLength;
+ return aMessage.AppendBytes(frame, headerLength);
}
//---------------------------------------------------------------------------------------------------------------------
@@ -1341,11 +1295,28 @@ void FragmentHeader::Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset)
mOffset = (aOffset & kOffsetMask);
}
+bool FragmentHeader::IsFragmentHeader(const FrameData &aFrameData)
+{
+ return IsFragmentHeader(aFrameData.GetBytes(), aFrameData.GetLength());
+}
+
bool FragmentHeader::IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength)
{
return (aFrameLength >= kFirstFragmentHeaderSize) && ((*aFrame & kDispatchMask) == kDispatch);
}
+Error FragmentHeader::ParseFrom(FrameData &aFrameData)
+{
+ Error error;
+ uint16_t headerLength;
+
+ SuccessOrExit(error = ParseFrom(aFrameData.GetBytes(), aFrameData.GetLength(), headerLength));
+ aFrameData.SkipOver(headerLength);
+
+exit:
+ return error;
+}
+
Error FragmentHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
{
Error error = kErrorParse;
diff --git a/src/core/thread/lowpan.hpp b/src/core/thread/lowpan.hpp
index c0edcca38..38b0fa30e 100644
--- a/src/core/thread/lowpan.hpp
+++ b/src/core/thread/lowpan.hpp
@@ -37,6 +37,7 @@
#include "openthread-core-config.h"
#include "common/debug.hpp"
+#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
@@ -245,6 +246,19 @@ public:
}
/**
+ * This method indicates whether or not header in a given frame is a LOWPAN_IPHC header.
+ *
+ * @param[in] aFrameData The frame data.
+ *
+ * @retval TRUE If the header matches the LOWPAN_IPHC dispatch value.
+ * @retval FALSE If the header does not match the LOWPAN_IPHC dispatch value.
+ */
+ static bool IsLowpanHc(const FrameData &aFrameData)
+ {
+ return (aFrameData.GetLength() > 0) && IsLowpanHc(aFrameData.GetBytes());
+ }
+
+ /**
* This method compresses an IPv6 header.
*
* @param[in] aMessage A reference to the IPv6 message.
@@ -260,54 +274,59 @@ public:
/**
* This method decompresses a LOWPAN_IPHC header.
*
- * @param[out] aMessage A reference where the IPv6 header will be placed.
- * @param[in] aMacSource The MAC source address.
- * @param[in] aMacDest The MAC destination address.
- * @param[in] aBuf A pointer to the LOWPAN_IPHC header.
- * @param[in] aBufLength The number of bytes in @p aBuf.
- * @param[in] aDatagramLength The IPv6 datagram length.
+ * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
- * @returns The size of the compressed header in bytes.
+ * @param[out] aMessage A reference where the IPv6 header will be placed.
+ * @param[in] aMacSource The MAC source address.
+ * @param[in] aMacDest The MAC destination address.
+ * @param[in,out] aFrameData A frame data containing the LOWPAN_IPHC header.
+ * @param[in] aDatagramLength The IPv6 datagram length.
+ *
+ * @retval kErrorNone The header was decompressed successfully. @p aMessage and @p aFrameData are updated.
+ * @retval kErrorParse Failed to parse the lowpan header.
+ * @retval kErrorNoBufs Could not grow @p aMessage to write the parsed IPv6 header.
*
*/
- int Decompress(Message & aMessage,
- const Mac::Address &aMacSource,
- const Mac::Address &aMacDest,
- const uint8_t * aBuf,
- uint16_t aBufLength,
- uint16_t aDatagramLength);
+ Error Decompress(Message & aMessage,
+ const Mac::Address &aMacSource,
+ const Mac::Address &aMacDest,
+ FrameData & aFrameData,
+ uint16_t aDatagramLength);
/**
* This method decompresses a LOWPAN_IPHC header.
*
- * @param[out] aIp6Header A reference where the IPv6 header will be placed.
- * @param[out] aCompressedNextHeader A boolean reference to output whether next header is compressed or not.
- * @param[in] aMacSource The MAC source address.
- * @param[in] aMacDest The MAC destination address.
- * @param[in] aBuf A pointer to the LOWPAN_IPHC header.
- * @param[in] aBufLength The number of bytes in @p aBuf.
+ * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
+ *
+ * @param[out] aIp6Header A reference where the IPv6 header will be placed.
+ * @param[out] aCompressedNextHeader A boolean reference to output whether next header is compressed or not.
+ * @param[in] aMacSource The MAC source address.
+ * @param[in] aMacDest The MAC destination address.
+ * @param[in,out] aFrameData A frame data containing the LOWPAN_IPHC header.
*
- * @returns The size of the compressed header in bytes or -1 if decompression fails.
+ * @retval kErrorNone The header was decompressed successfully. @p aIp6Headre and @p aFrameData are updated.
+ * @retval kErrorParse Failed to parse the lowpan header.
*
*/
- int DecompressBaseHeader(Ip6::Header & aIp6Header,
- bool & aCompressedNextHeader,
- const Mac::Address &aMacSource,
- const Mac::Address &aMacDest,
- const uint8_t * aBuf,
- uint16_t aBufLength);
+ Error DecompressBaseHeader(Ip6::Header & aIp6Header,
+ bool & aCompressedNextHeader,
+ const Mac::Address &aMacSource,
+ const Mac::Address &aMacDest,
+ FrameData & aFrameData);
/**
* This method decompresses a LOWPAN_NHC UDP header.
*
- * @param[out] aUdpHeader A reference where the UDP header will be placed.
- * @param[in] aBuf A pointer to the LOWPAN_NHC header.
- * @param[in] aBufLength The number of bytes in @p aBuf.
+ * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
- * @returns The size of the compressed header in bytes or -1 if decompression fails.
+ * @param[out] aUdpHeader A reference where the UDP header will be placed.
+ * @param[in,out] aFrameData A frame data containing the LOWPAN_NHC header.
+ *
+ * @retval kErrorNone The header was decompressed successfully. @p aUdpHeader and @p aFrameData are updated.
+ * @retval kErrorParse Failed to parse the lowpan header.
*
*/
- int DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);
+ Error DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData);
/**
* This method decompresses the IPv6 ECN field in a LOWPAN_IPHC header.
@@ -403,8 +422,8 @@ private:
Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf);
Error CompressUdp(Message &aMessage, BufferWriter &aBuf);
- int DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength);
- int DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength);
+ Error DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData);
+ Error DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength);
Error DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader);
static void CopyContext(const Context &aContext, Ip6::Address &aAddress);
@@ -445,7 +464,7 @@ public:
* @retval FALSE If the header does not match the Mesh Header dispatch value.
*
*/
- static bool IsMeshHeader(const uint8_t *aFrame, uint16_t aFrameLength);
+ static bool IsMeshHeader(const FrameData &aFrameData);
/**
* This method parses the Mesh Header from a frame @p aFrame.
@@ -461,6 +480,19 @@ public:
Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
/**
+ * This method parses the Mesh Header from a given frame data.
+ *
+ * If the Mesh Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
+ *
+ * @param[in,out] aFrameData The frame data to parse from.
+ *
+ * @retval kErrorNone Mesh Header parsed successfully. @p aFrameData is updated to skip over parsed header.
+ * @retval kErrorParse Mesh Header could not be parsed.
+ *
+ */
+ Error ParseFrom(FrameData &aFrameData);
+
+ /**
* This method parses the Mesh Header from a given message.
*
* @note The Mesh Header is read from offset zero within the @p aMessage.
@@ -542,18 +574,16 @@ public:
uint16_t WriteTo(uint8_t *aFrame) const;
/**
- * This method writes the Mesh Header to a message at a given offset.
+ * This method appends the Mesh Header to a given message.
*
- * @note This method expects the @p aMessage length to be already set such that there is enough space for the
- * entire Mesh Header to be written.
*
- * @param[out] aMessage A message to write the Mesh Header into.
- * @param[in] aOffset The offset at which to write the header.
+ * @param[out] aMessage A message to append the Mesh Header to.
*
- * @returns The header length (number of bytes written).
+ * @retval kErrorNone Successfully appended the Mesh Header to @p aMessage.
+ * @retval kErrorNoBufs Insufficient available buffers to grow @p aMessage.
*
*/
- uint16_t WriteTo(Message &aMessage, uint16_t aOffset) const;
+ Error AppendTo(Message &aMessage) const;
private:
static constexpr uint8_t kDispatch = 2 << 6;
@@ -612,11 +642,13 @@ public:
* 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.
*
+ * @param[in] aFrameData The frame data.
+ *
* @retval TRUE If the header matches the Fragment Header dispatch value.
* @retval FALSE If the header does not match the Fragment Header dispatch value.
*
*/
- static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
+ static bool IsFragmentHeader(const FrameData &aFrameData);
/**
* This method parses the Fragment Header from a frame @p aFrame.
@@ -629,7 +661,20 @@ public:
* @retval kErrorParse Fragment header could not be parsed from @p aFrame.
*
*/
- Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
+ 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.
+ *
+ * If the Fragment Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
+ *
+ * @param[in,out] aFrameData The frame data to parse from.
+ *
+ * @retval kErrorNone Fragment Header parsed successfully. @p aFrameData is updated to skip over parsed header.
+ * @retval kErrorParse Fragment header could not be parsed.
+ *
+ */
+ Error ParseFrom(FrameData &aFrameData);
/**
* This method parses the Fragment Header from a message.
@@ -694,6 +739,8 @@ private:
static constexpr uint8_t kTagIndex = 2; // Start index of Tag field in the Fragment Header byte sequence.
static constexpr uint8_t kOffsetIndex = 4; // Start index of Offset field in the Fragment Header byte sequence.
+ static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
+
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 be6c7d7e5..74a9198f0 100644
--- a/src/core/thread/mesh_forwarder.cpp
+++ b/src/core/thread/mesh_forwarder.cpp
@@ -1332,8 +1332,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
ThreadLinkInfo linkInfo;
Mac::Address macDest;
Mac::Address macSource;
- uint8_t * payload;
- uint16_t payloadLength;
+ FrameData frameData;
Error error = kErrorNone;
VerifyOrExit(mEnabled, error = kErrorInvalidState);
@@ -1343,8 +1342,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
linkInfo.SetFrom(aFrame);
- payload = aFrame.GetPayload();
- payloadLength = aFrame.GetPayloadLength();
+ frameData.Init(aFrame.GetPayload(), aFrame.GetPayloadLength());
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
Get<Utils::SupervisionListener>().UpdateOnReceive(macSource, linkInfo.IsLinkSecurityEnabled());
@@ -1353,23 +1351,23 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
switch (aFrame.GetType())
{
case Mac::Frame::kFcfFrameData:
- if (Lowpan::MeshHeader::IsMeshHeader(payload, payloadLength))
+ if (Lowpan::MeshHeader::IsMeshHeader(frameData))
{
#if OPENTHREAD_FTD
- HandleMesh(payload, payloadLength, macSource, linkInfo);
+ HandleMesh(frameData, macSource, linkInfo);
#endif
}
- else if (Lowpan::FragmentHeader::IsFragmentHeader(payload, payloadLength))
+ else if (Lowpan::FragmentHeader::IsFragmentHeader(frameData))
{
- HandleFragment(payload, payloadLength, macSource, macDest, linkInfo);
+ HandleFragment(frameData, macSource, macDest, linkInfo);
}
- else if (payloadLength >= 1 && Lowpan::Lowpan::IsLowpanHc(payload))
+ else if (Lowpan::Lowpan::IsLowpanHc(frameData))
{
- HandleLowpanHC(payload, payloadLength, macSource, macDest, linkInfo);
+ HandleLowpanHC(frameData, macSource, macDest, linkInfo);
}
else
{
- VerifyOrExit(payloadLength == 0, error = kErrorNotLowpanDataFrame);
+ VerifyOrExit(frameData.GetLength() == 0, error = kErrorNotLowpanDataFrame);
LogFrame("Received empty payload frame", aFrame, kErrorNone);
}
@@ -1392,21 +1390,16 @@ exit:
}
}
-void MeshForwarder::HandleFragment(const uint8_t * aFrame,
- uint16_t aFrameLength,
+void MeshForwarder::HandleFragment(FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo)
{
Error error = kErrorNone;
Lowpan::FragmentHeader fragmentHeader;
- uint16_t fragmentHeaderLength;
Message * message = nullptr;
- // Check the fragment header
- SuccessOrExit(error = fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength));
- aFrame += fragmentHeaderLength;
- aFrameLength -= fragmentHeaderLength;
+ SuccessOrExit(error = fragmentHeader.ParseFrom(aFrameData));
#if OPENTHREAD_CONFIG_MULTI_RADIO
@@ -1448,15 +1441,13 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
uint16_t datagramSize = fragmentHeader.GetDatagramSize();
#if OPENTHREAD_FTD
- UpdateRoutes(aFrame, aFrameLength, aMacSource, aMacDest);
+ UpdateRoutes(aFrameData, aMacSource, aMacDest);
#endif
- error = FrameToMessage(aFrame, aFrameLength, datagramSize, aMacSource, aMacDest, message);
- SuccessOrExit(error);
+ SuccessOrExit(error = FrameToMessage(aFrameData, datagramSize, aMacSource, aMacDest, message));
VerifyOrExit(datagramSize >= message->GetLength(), error = kErrorParse);
- error = message->SetLength(datagramSize);
- SuccessOrExit(error);
+ SuccessOrExit(error = message->SetLength(datagramSize));
message->SetDatagramTag(fragmentHeader.GetDatagramTag());
message->SetTimestampToNow();
@@ -1489,7 +1480,7 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
if (msg.GetLength() == fragmentHeader.GetDatagramSize() &&
msg.GetDatagramTag() == fragmentHeader.GetDatagramTag() &&
msg.GetOffset() == fragmentHeader.GetDatagramOffset() &&
- msg.GetOffset() + aFrameLength <= fragmentHeader.GetDatagramSize() &&
+ msg.GetOffset() + aFrameData.GetLength() <= fragmentHeader.GetDatagramSize() &&
msg.IsLinkSecurityEnabled() == aLinkInfo.IsLinkSecurityEnabled())
{
message = &msg;
@@ -1510,8 +1501,8 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
VerifyOrExit(message != nullptr, error = kErrorDrop);
- message->WriteBytes(message->GetOffset(), aFrame, aFrameLength);
- message->MoveOffset(aFrameLength);
+ message->WriteData(message->GetOffset(), aFrameData);
+ message->MoveOffset(aFrameData.GetLength());
message->AddRss(aLinkInfo.GetRss());
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
message->AddLqi(aLinkInfo.GetLqi());
@@ -1531,7 +1522,7 @@ exit:
}
else
{
- LogFragmentFrameDrop(error, aFrameLength, aMacSource, aMacDest, fragmentHeader,
+ LogFragmentFrameDrop(error, aFrameData.GetLength(), aMacSource, aMacDest, fragmentHeader,
aLinkInfo.IsLinkSecurityEnabled());
FreeMessage(message);
}
@@ -1590,40 +1581,31 @@ bool MeshForwarder::UpdateReassemblyList(void)
return mReassemblyList.GetHead() != nullptr;
}
-Error MeshForwarder::FrameToMessage(const uint8_t * aFrame,
- uint16_t aFrameLength,
+Error MeshForwarder::FrameToMessage(const FrameData & aFrameData,
uint16_t aDatagramSize,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Message *& aMessage)
{
- Error error = kErrorNone;
- int headerLength;
+ Error error = kErrorNone;
+ FrameData frameData = aFrameData;
Message::Priority priority;
- error = GetFramePriority(aFrame, aFrameLength, aMacSource, aMacDest, priority);
- SuccessOrExit(error);
+ SuccessOrExit(error = GetFramePriority(frameData, aMacSource, aMacDest, priority));
aMessage = Get<MessagePool>().Allocate(Message::kTypeIp6, /* aReserveHeader */ 0, Message::Settings(priority));
VerifyOrExit(aMessage, error = kErrorNoBufs);
- headerLength =
- Get<Lowpan::Lowpan>().Decompress(*aMessage, aMacSource, aMacDest, aFrame, aFrameLength, aDatagramSize);
- VerifyOrExit(headerLength > 0, error = kErrorParse);
+ SuccessOrExit(error = Get<Lowpan::Lowpan>().Decompress(*aMessage, aMacSource, aMacDest, frameData, aDatagramSize));
- aFrame += headerLength;
- aFrameLength -= static_cast<uint16_t>(headerLength);
-
- SuccessOrExit(error = aMessage->SetLength(aMessage->GetLength() + aFrameLength));
- aMessage->WriteBytes(aMessage->GetOffset(), aFrame, aFrameLength);
- aMessage->MoveOffset(aFrameLength);
+ SuccessOrExit(error = aMessage->AppendData(frameData));
+ aMessage->MoveOffset(frameData.GetLength());
exit:
return error;
}
-void MeshForwarder::HandleLowpanHC(const uint8_t * aFrame,
- uint16_t aFrameLength,
+void MeshForwarder::HandleLowpanHC(const FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo)
@@ -1632,10 +1614,10 @@ void MeshForwarder::HandleLowpanHC(const uint8_t * aFrame,
Message *message = nullptr;
#if OPENTHREAD_FTD
- UpdateRoutes(aFrame, aFrameLength, aMacSource, aMacDest);
+ UpdateRoutes(aFrameData, aMacSource, aMacDest);
#endif
- SuccessOrExit(error = FrameToMessage(aFrame, aFrameLength, 0, aMacSource, aMacDest, message));
+ SuccessOrExit(error = FrameToMessage(aFrameData, 0, aMacSource, aMacDest, message));
message->SetLinkInfo(aLinkInfo);
@@ -1653,7 +1635,7 @@ exit:
}
else
{
- LogLowpanHcFrameDrop(error, aFrameLength, aMacSource, aMacDest, aLinkInfo.IsLinkSecurityEnabled());
+ LogLowpanHcFrameDrop(error, aFrameData.GetLength(), aMacSource, aMacDest, aLinkInfo.IsLinkSecurityEnabled());
FreeMessage(message);
}
}
@@ -1676,8 +1658,7 @@ Error MeshForwarder::HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLi
return Get<Ip6::Ip6>().HandleDatagram(aMessage, &netif, &aLinkInfo, false);
}
-Error MeshForwarder::GetFramePriority(const uint8_t * aFrame,
- uint16_t aFrameLength,
+Error MeshForwarder::GetFramePriority(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Message::Priority & aPriority)
@@ -1685,7 +1666,7 @@ Error MeshForwarder::GetFramePriority(const uint8_t * aFrame,
Error error = kErrorNone;
Ip6::Headers headers;
- SuccessOrExit(error = headers.DecompressFrom(aFrame, aFrameLength, aMacSource, aMacDest, GetInstance()));
+ SuccessOrExit(error = headers.DecompressFrom(aFrameData, aMacSource, aMacDest, GetInstance()));
aPriority = Ip6::Ip6::DscpToPriority(headers.GetIp6Header().GetDscp());
diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp
index adcc2d3e3..be4cb6217 100644
--- a/src/core/thread/mesh_forwarder.hpp
+++ b/src/core/thread/mesh_forwarder.hpp
@@ -38,6 +38,7 @@
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
+#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
#include "common/non_copyable.hpp"
@@ -425,16 +426,11 @@ private:
void SendIcmpErrorIfDstUnreach(const Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest);
- Error CheckReachability(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ Error CheckReachability(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest);
- void UpdateRoutes(const uint8_t * aFrame,
- uint16_t aFrameLength,
- const Mac::Address &aMeshSource,
- const Mac::Address &aMeshDest);
- Error FrameToMessage(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ void UpdateRoutes(const FrameData &aFrameData, const Mac::Address &aMeshSource, const Mac::Address &aMeshDest);
+ Error FrameToMessage(const FrameData & aFrameData,
uint16_t aDatagramSize,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
@@ -442,17 +438,12 @@ private:
void GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
void GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
Message *PrepareNextDirectTransmission(void);
- void HandleMesh(uint8_t * aFrame,
- uint16_t aFrameLength,
- const Mac::Address & aMacSource,
- const ThreadLinkInfo &aLinkInfo);
- void HandleFragment(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ void HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSource, const ThreadLinkInfo &aLinkInfo);
+ void HandleFragment(FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo);
- void HandleLowpanHC(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ void HandleLowpanHC(const FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo);
@@ -505,16 +496,14 @@ private:
static void ScheduleTransmissionTask(Tasklet &aTasklet);
void ScheduleTransmissionTask(void);
- Error GetFramePriority(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ Error GetFramePriority(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Message::Priority & aPriority);
Error GetFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
uint16_t aSrcRloc16,
Message::Priority & aPriority);
- void GetForwardFramePriority(const uint8_t * aFrame,
- uint16_t aFrameLength,
+ void GetForwardFramePriority(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
Message::Priority & aPriority);
diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp
index d3c5932ad..25688e297 100644
--- a/src/core/thread/mesh_forwarder_ftd.cpp
+++ b/src/core/thread/mesh_forwarder_ftd.cpp
@@ -666,15 +666,14 @@ exit:
return;
}
-Error MeshForwarder::CheckReachability(const uint8_t * aFrame,
- uint16_t aFrameLength,
+Error MeshForwarder::CheckReachability(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest)
{
Error error;
Ip6::Headers ip6Headers;
- error = ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance());
+ error = ip6Headers.DecompressFrom(aFrameData, aMeshSource, aMeshDest, GetInstance());
if (error == kErrorNotFound)
{
@@ -704,41 +703,34 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::
Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aIp6Headers));
}
-void MeshForwarder::HandleMesh(uint8_t * aFrame,
- uint16_t aFrameLength,
- const Mac::Address & aMacSource,
- const ThreadLinkInfo &aLinkInfo)
+void MeshForwarder::HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSource, const ThreadLinkInfo &aLinkInfo)
{
Error error = kErrorNone;
Message * message = nullptr;
Mac::Address meshDest;
Mac::Address meshSource;
Lowpan::MeshHeader meshHeader;
- uint16_t headerLength;
// Security Check: only process Mesh Header frames that had security enabled.
VerifyOrExit(aLinkInfo.IsLinkSecurityEnabled(), error = kErrorSecurity);
- SuccessOrExit(error = meshHeader.ParseFrom(aFrame, aFrameLength, headerLength));
+ SuccessOrExit(error = meshHeader.ParseFrom(aFrameData));
meshSource.SetShort(meshHeader.GetSource());
meshDest.SetShort(meshHeader.GetDestination());
- aFrame += headerLength;
- aFrameLength -= headerLength;
-
- UpdateRoutes(aFrame, aFrameLength, meshSource, meshDest);
+ UpdateRoutes(aFrameData, meshSource, meshDest);
if (meshDest.GetShort() == Get<Mac::Mac>().GetShortAddress() ||
Get<Mle::MleRouter>().IsMinimalChild(meshDest.GetShort()))
{
- if (Lowpan::FragmentHeader::IsFragmentHeader(aFrame, aFrameLength))
+ if (Lowpan::FragmentHeader::IsFragmentHeader(aFrameData))
{
- HandleFragment(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
+ HandleFragment(aFrameData, meshSource, meshDest, aLinkInfo);
}
- else if (Lowpan::Lowpan::IsLowpanHc(aFrame))
+ else if (Lowpan::Lowpan::IsLowpanHc(aFrameData))
{
- HandleLowpanHC(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
+ HandleLowpanHC(aFrameData, meshSource, meshDest, aLinkInfo);
}
else
{
@@ -748,22 +740,21 @@ void MeshForwarder::HandleMesh(uint8_t * aFrame,
else if (meshHeader.GetHopsLeft() > 0)
{
Message::Priority priority = Message::kPriorityNormal;
- uint16_t offset = 0;
Get<Mle::MleRouter>().ResolveRoutingLoops(aMacSource.GetShort(), meshDest.GetShort());
- SuccessOrExit(error = CheckReachability(aFrame, aFrameLength, meshSource, meshDest));
+ SuccessOrExit(error = CheckReachability(aFrameData, meshSource, meshDest));
meshHeader.DecrementHopsLeft();
- GetForwardFramePriority(aFrame, aFrameLength, meshSource, meshDest, priority);
+ GetForwardFramePriority(aFrameData, meshSource, meshDest, priority);
message =
Get<MessagePool>().Allocate(Message::kType6lowpan, /* aReserveHeader */ 0, Message::Settings(priority));
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
- SuccessOrExit(error = message->SetLength(meshHeader.GetHeaderLength() + aFrameLength));
- offset += meshHeader.WriteTo(*message, offset);
- message->WriteBytes(offset, aFrame, aFrameLength);
+ SuccessOrExit(error = meshHeader.AppendTo(*message));
+ SuccessOrExit(error = message->AppendData(aFrameData));
+
message->SetLinkInfo(aLinkInfo);
#if OPENTHREAD_CONFIG_MULTI_RADIO
@@ -789,14 +780,13 @@ exit:
if (error != kErrorNone)
{
- LogInfo("Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s", ErrorToString(error), aFrameLength,
- aMacSource.ToString().AsCString(), ToYesNo(aLinkInfo.IsLinkSecurityEnabled()));
+ LogInfo("Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s", ErrorToString(error),
+ aFrameData.GetLength(), aMacSource.ToString().AsCString(), ToYesNo(aLinkInfo.IsLinkSecurityEnabled()));
FreeMessage(message);
}
}
-void MeshForwarder::UpdateRoutes(const uint8_t * aFrame,
- uint16_t aFrameLength,
+void MeshForwarder::UpdateRoutes(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest)
{
@@ -805,7 +795,7 @@ void MeshForwarder::UpdateRoutes(const uint8_t * aFrame,
VerifyOrExit(!aMeshDest.IsBroadcast() && aMeshSource.IsShort());
- SuccessOrExit(ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance()));
+ SuccessOrExit(ip6Headers.DecompressFrom(aFrameData, aMeshSource, aMeshDest, GetInstance()));
if (!ip6Headers.GetSourceAddress().GetIid().IsLocator() &&
Get<NetworkData::Leader>().IsOnMesh(ip6Headers.GetSourceAddress()))
@@ -944,22 +934,19 @@ exit:
return error;
}
-void MeshForwarder::GetForwardFramePriority(const uint8_t * aFrame,
- uint16_t aFrameLength,
+void MeshForwarder::GetForwardFramePriority(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
Message::Priority & aPriority)
{
Error error = kErrorNone;
+ FrameData frameData = aFrameData;
bool isFragment = false;
Lowpan::FragmentHeader fragmentHeader;
- uint16_t fragmentHeaderLength;
- if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
+ if (fragmentHeader.ParseFrom(frameData) == kErrorNone)
{
isFragment = true;
- aFrame += fragmentHeaderLength;
- aFrameLength -= fragmentHeaderLength;
if (fragmentHeader.GetDatagramOffset() > 0)
{
@@ -969,20 +956,18 @@ void MeshForwarder::GetForwardFramePriority(const uint8_t * aFrame,
}
// Get priority from IPv6 header or UDP destination port directly
- error = GetFramePriority(aFrame, aFrameLength, aMeshSource, aMeshDest, aPriority);
+ error = GetFramePriority(frameData, aMeshSource, aMeshDest, aPriority);
exit:
if (error != kErrorNone)
{
LogNote("Failed to get forwarded frame priority, error:%s, len:%d, src:%d, dst:%s", ErrorToString(error),
- aFrameLength, aMeshSource.ToString().AsCString(), aMeshDest.ToString().AsCString());
+ frameData.GetLength(), aMeshSource.ToString().AsCString(), aMeshDest.ToString().AsCString());
}
else if (isFragment)
{
- UpdateFragmentPriority(fragmentHeader, aFrameLength, aMeshSource.GetShort(), aPriority);
+ UpdateFragmentPriority(fragmentHeader, frameData.GetLength(), aMeshSource.GetShort(), aPriority);
}
-
- return;
}
// LCOV_EXCL_START
diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp
index 355807498..d5311142b 100644
--- a/tests/unit/test_lowpan.cpp
+++ b/tests/unit/test_lowpan.cpp
@@ -145,12 +145,14 @@ static void Init(void)
*/
static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress)
{
- Message *message = nullptr;
- uint8_t result[512];
- uint8_t iphc[512];
- uint8_t ip6[512];
- uint16_t iphcLength;
- uint16_t ip6Length;
+ Message * message = nullptr;
+ uint8_t result[512];
+ uint8_t iphc[512];
+ uint8_t ip6[512];
+ uint16_t iphcLength;
+ uint16_t ip6Length;
+ FrameData frameData;
+ Error error;
aVector.GetCompressedStream(iphc, iphcLength);
aVector.GetUncompressedStream(ip6, ip6Length);
@@ -223,28 +225,29 @@ static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress)
{
VerifyOrQuit((message = sInstance->Get<MessagePool>().Allocate(Message::kTypeIp6)) != nullptr);
- int decompressedBytes =
- sLowpan->Decompress(*message, aVector.mMacSource, aVector.mMacDestination, iphc, iphcLength, 0);
+ frameData.Init(iphc, iphcLength);
+
+ error = sLowpan->Decompress(*message, aVector.mMacSource, aVector.mMacDestination, frameData, 0);
message->ReadBytes(0, result, message->GetLength());
if (aVector.mError == kErrorNone)
{
+ SuccessOrQuit(error, "Lowpan::Decompress failed");
+
// Append payload to the IPv6 Packet.
- memcpy(result + message->GetLength(), iphc + decompressedBytes,
- iphcLength - static_cast<uint16_t>(decompressedBytes));
+ memcpy(result + message->GetLength(), frameData.GetBytes(), frameData.GetLength());
- DumpBuffer("Resulted IPv6 uncompressed packet", result,
- message->GetLength() + iphcLength - static_cast<uint16_t>(decompressedBytes));
+ DumpBuffer("Resulted IPv6 uncompressed packet", result, message->GetLength() + frameData.GetLength());
- VerifyOrQuit(decompressedBytes == aVector.mIphcHeader.mLength, "Lowpan::Decompress failed");
+ VerifyOrQuit((frameData.GetBytes() - iphc) == aVector.mIphcHeader.mLength, "Lowpan::Decompress failed");
VerifyOrQuit(message->GetOffset() == aVector.mPayloadOffset, "Lowpan::Decompress failed");
VerifyOrQuit(message->GetOffset() == message->GetLength(), "Lowpan::Decompress failed");
VerifyOrQuit(memcmp(ip6, result, ip6Length) == 0, "Lowpan::Decompress failed");
}
else
{
- VerifyOrQuit(decompressedBytes < 0, "Lowpan::Decompress failed");
+ VerifyOrQuit(error == kErrorParse, "Lowpan::Decompress failed");
}
message->Free();
@@ -1864,7 +1867,7 @@ void TestLowpanMeshHeader(void)
uint8_t frame[kMaxFrameSize];
uint16_t length;
- uint16_t headerLength;
+ FrameData frameData;
Lowpan::MeshHeader meshHeader;
meshHeader.Init(kSourceAddr, kDestAddr, 1);
@@ -1878,14 +1881,17 @@ void TestLowpanMeshHeader(void)
VerifyOrQuit(memcmp(frame, kMeshHeader1, length) == 0, "MeshHeader::WriteTo() failed");
memset(&meshHeader, 0, sizeof(meshHeader));
- VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frame, length));
- SuccessOrQuit(meshHeader.ParseFrom(frame, length, headerLength));
- VerifyOrQuit(headerLength == length, "MeshHeader::ParseFrom() returned length is incorrect");
+ frameData.Init(frame, length);
+ VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frameData));
+ SuccessOrQuit(meshHeader.ParseFrom(frameData));
+ VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
+ VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(meshHeader.GetSource() == kSourceAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetHopsLeft() == 1, "failed after ParseFrom()");
- VerifyOrQuit(meshHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
+ frameData.Init(frame, length - 1);
+ VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse,
"MeshHeader::ParseFrom() did not fail with incorrect length");
//- - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1901,27 +1907,34 @@ void TestLowpanMeshHeader(void)
VerifyOrQuit(memcmp(frame, kMeshHeader2, length) == 0, "MeshHeader::WriteTo() failed");
memset(&meshHeader, 0, sizeof(meshHeader));
- VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frame, length));
- SuccessOrQuit(meshHeader.ParseFrom(frame, length, headerLength));
- VerifyOrQuit(headerLength == length, "MeshHeader::ParseFrom() returned length is incorrect");
+ frameData.Init(frame, length);
+ VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frameData));
+ SuccessOrQuit(meshHeader.ParseFrom(frameData));
+ VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
+ VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(meshHeader.GetSource() == kSourceAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetHopsLeft() == 0x20, "failed after ParseFrom()");
- VerifyOrQuit(meshHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
+ frameData.Init(frame, length - 1);
+ VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse,
"MeshHeader::ParseFrom() did not fail with incorrect length");
//- - - - - - - - - - - - - - - - - - - - - - - - - -
- SuccessOrQuit(meshHeader.ParseFrom(kMeshHeader3, sizeof(kMeshHeader3), headerLength));
- VerifyOrQuit(headerLength == sizeof(kMeshHeader3), "MeshHeader::ParseFrom() returned length is incorrect");
+ length = sizeof(kMeshHeader3);
+ frameData.Init(kMeshHeader3, sizeof(kMeshHeader3));
+ SuccessOrQuit(meshHeader.ParseFrom(frameData));
+ VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
+ VerifyOrQuit(frameData.GetBytes() - kMeshHeader3 == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(meshHeader.GetSource() == kSourceAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetHopsLeft() == 1, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.WriteTo(frame) == sizeof(kMeshHeader1));
- VerifyOrQuit(meshHeader.ParseFrom(kMeshHeader3, sizeof(kMeshHeader3) - 1, headerLength) == kErrorParse,
+ frameData.Init(kMeshHeader3, sizeof(kMeshHeader3) - 1);
+ VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse,
"MeshHeader::ParseFrom() did not fail with incorrect length");
}
@@ -1945,7 +1958,7 @@ void TestLowpanFragmentHeader(void)
uint8_t frame[kMaxFrameSize];
uint16_t length;
- uint16_t headerLength;
+ FrameData frameData;
Lowpan::FragmentHeader fragHeader;
fragHeader.InitFirstFragment(kSize, kTag);
@@ -1960,15 +1973,21 @@ void TestLowpanFragmentHeader(void)
VerifyOrQuit(memcmp(frame, kFragHeader1, length) == 0, "FragmentHeader::WriteTo() failed");
memset(&fragHeader, 0, sizeof(fragHeader));
- VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frame, length));
- SuccessOrQuit(fragHeader.ParseFrom(frame, length, headerLength));
- VerifyOrQuit(headerLength == length, "FragmentHeader::ParseFrom() returned length is incorrect");
+
+ frameData.Init(frame, length);
+ VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frameData));
+ SuccessOrQuit(fragHeader.ParseFrom(frameData));
+ VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
+ VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramOffset() == 0, "failed after ParseFrom()");
- VerifyOrQuit(fragHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
+ frameData.Init(frame, length - 1);
+ VerifyOrQuit(fragHeader.ParseFrom(frameData) == kErrorParse,
"FragmentHeader::ParseFrom() did not fail with incorrect length");
+ VerifyOrQuit(frameData.GetLength() == length - 1);
+ VerifyOrQuit(frameData.GetBytes() == frame);
//- - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1990,51 +2009,70 @@ void TestLowpanFragmentHeader(void)
VerifyOrQuit(memcmp(frame, kFragHeader2, length) == 0, "FragmentHeader::WriteTo() failed");
memset(&fragHeader, 0, sizeof(fragHeader));
- VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frame, length));
- SuccessOrQuit(fragHeader.ParseFrom(frame, length, headerLength));
- VerifyOrQuit(headerLength == length, "FragmentHeader::ParseFrom() returned length is incorrect");
+ frameData.Init(frame, length);
+ VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frameData));
+ SuccessOrQuit(fragHeader.ParseFrom(frameData));
+ VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
+ VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramOffset() == kOffset, "failed after ParseFrom()");
- VerifyOrQuit(fragHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
+ frameData.Init(frame, length - 1);
+ VerifyOrQuit(fragHeader.ParseFrom(frameData) == kErrorParse,
"FragmentHeader::ParseFrom() did not fail with incorrect length");
+ VerifyOrQuit(frameData.GetLength() == length - 1);
+ VerifyOrQuit(frameData.GetBytes() == frame);
//- - - - - - - - - - - - - - - - - - - - - - - - - -
length = sizeof(kFragHeader3);
memcpy(frame, kFragHeader3, length);
- SuccessOrQuit(fragHeader.ParseFrom(frame, length, headerLength));
- VerifyOrQuit(headerLength == length, "FragmentHeader::ParseFrom() returned length is incorrect");
+ frameData.Init(frame, length);
+ SuccessOrQuit(fragHeader.ParseFrom(frameData));
+ VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
+ VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramOffset() == 0, "failed after ParseFrom()");
- VerifyOrQuit(fragHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
+ frameData.Init(frame, length - 1);
+ VerifyOrQuit(fragHeader.ParseFrom(frameData) == kErrorParse,
"FragmentHeader::ParseFrom() did not fail with incorrect length");
+ VerifyOrQuit(frameData.GetLength() == length - 1);
+ VerifyOrQuit(frameData.GetBytes() == frame);
//- - - - - - - - - - - - - - - - - - - - - - - - - -
length = sizeof(kInvalidFragHeader1);
memcpy(frame, kInvalidFragHeader1, length);
- VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frame, length),
+ frameData.Init(frame, length);
+ VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frameData),
"IsFragmentHeader() did not detect invalid header");
- VerifyOrQuit(fragHeader.ParseFrom(frame, length, headerLength) != kErrorNone,
+ VerifyOrQuit(fragHeader.ParseFrom(frameData) != kErrorNone,
"FragmentHeader::ParseFrom() did not fail with invalid header");
+ VerifyOrQuit(frameData.GetLength() == length);
+ VerifyOrQuit(frameData.GetBytes() == frame);
length = sizeof(kInvalidFragHeader2);
memcpy(frame, kInvalidFragHeader2, length);
- VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frame, length),
+ frameData.Init(frame, length);
+ VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frameData),
"IsFragmentHeader() did not detect invalid header");
- VerifyOrQuit(fragHeader.ParseFrom(frame, length, headerLength) != kErrorNone,
+ VerifyOrQuit(fragHeader.ParseFrom(frameData) != kErrorNone,
"FragmentHeader::ParseFrom() did not fail with invalid header");
+ VerifyOrQuit(frameData.GetLength() == length);
+ VerifyOrQuit(frameData.GetBytes() == frame);
length = sizeof(kInvalidFragHeader3);
memcpy(frame, kInvalidFragHeader3, length);
- VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frame, length),
+ frameData.Init(frame, length);
+ VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frameData),
"IsFragmentHeader() did not detect invalid header");
- VerifyOrQuit(fragHeader.ParseFrom(frame, length, headerLength) != kErrorNone,
+ VerifyOrQuit(fragHeader.ParseFrom(frameData) != kErrorNone,
"FragmentHeader::ParseFrom() did not fail with invalid header");
+ VerifyOrQuit(frameData.GetLength() == length);
+ VerifyOrQuit(frameData.GetBytes() == frame);
}
} // namespace ot