diff options
author | Abtin Keshavarzian <abtink@google.com> | 2022-07-14 17:04:47 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-14 17:04:47 -0700 |
commit | 13416b15fb8ea97c3d9ccc1e5f7d0fc1cf05e06c (patch) | |
tree | 71e81481a000cd57912458908ea5c645e8771492 | |
parent | 366786dbed79745045fc47b1721e63a7f488ac57 (diff) | |
download | openthread-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.mk | 1 | ||||
-rw-r--r-- | src/core/BUILD.gn | 2 | ||||
-rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/core/Makefile.am | 2 | ||||
-rw-r--r-- | src/core/common/frame_data.cpp | 107 | ||||
-rw-r--r-- | src/core/common/frame_data.hpp | 177 | ||||
-rw-r--r-- | src/core/common/message.hpp | 35 | ||||
-rw-r--r-- | src/core/net/ip6.cpp | 42 | ||||
-rw-r--r-- | src/core/net/ip6.hpp | 7 | ||||
-rw-r--r-- | src/core/thread/lowpan.cpp | 345 | ||||
-rw-r--r-- | src/core/thread/lowpan.hpp | 133 | ||||
-rw-r--r-- | src/core/thread/mesh_forwarder.cpp | 81 | ||||
-rw-r--r-- | src/core/thread/mesh_forwarder.hpp | 29 | ||||
-rw-r--r-- | src/core/thread/mesh_forwarder_ftd.cpp | 63 | ||||
-rw-r--r-- | tests/unit/test_lowpan.cpp | 126 |
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 |