diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 247d7d96b..622d8df2c 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -432,6 +432,8 @@ openthread_core_files = [ "common/notifier.hpp", "common/num_utils.hpp", "common/numeric_limits.hpp", + "common/offset_range.cpp", + "common/offset_range.hpp", "common/owned_ptr.hpp", "common/owning_list.hpp", "common/pool.hpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index dbc13b2e3..e9c496746 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -112,6 +112,7 @@ set(COMMON_SOURCES common/log.cpp common/message.cpp common/notifier.cpp + common/offset_range.cpp common/preference.cpp common/random.cpp common/settings.cpp diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index 7a90d1c71..2269c10aa 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -149,7 +149,7 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Message &aMessage, ThreadStatusTlv::MlrStatus status = ThreadStatusTlv::kMlrSuccess; Config config; - uint16_t addressesOffset, addressesLength; + OffsetRange offsetRange; Ip6::Address address; Ip6::Address addresses[Ip6AddressesTlv::kMaxAddresses]; uint8_t failedAddressNum = 0; @@ -188,11 +188,10 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Message &aMessage, processTimeoutTlv = hasCommissionerSessionIdTlv && (Tlv::Find(aMessage, timeout) == kErrorNone); - VerifyOrExit(Tlv::FindTlvValueOffset(aMessage, Ip6AddressesTlv::kIp6Addresses, addressesOffset, addressesLength) == - kErrorNone, + VerifyOrExit(Tlv::FindTlvValueOffsetRange(aMessage, Ip6AddressesTlv::kIp6Addresses, offsetRange) == kErrorNone, error = kErrorParse); - VerifyOrExit(addressesLength % sizeof(Ip6::Address) == 0, status = ThreadStatusTlv::kMlrGeneralFailure); - VerifyOrExit(addressesLength / sizeof(Ip6::Address) <= Ip6AddressesTlv::kMaxAddresses, + VerifyOrExit(offsetRange.GetLength() % sizeof(Ip6::Address) == 0, status = ThreadStatusTlv::kMlrGeneralFailure); + VerifyOrExit(offsetRange.GetLength() / sizeof(Ip6::Address) <= Ip6AddressesTlv::kMaxAddresses, status = ThreadStatusTlv::kMlrGeneralFailure); if (!processTimeoutTlv) @@ -220,9 +219,10 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Message &aMessage, expireTime = TimerMilli::GetNow() + TimeMilli::SecToMsec(timeout); - for (uint16_t offset = 0; offset < addressesLength; offset += sizeof(Ip6::Address)) + while (!offsetRange.IsEmpty()) { - IgnoreError(aMessage.Read(addressesOffset + offset, address)); + IgnoreError(aMessage.Read(offsetRange, address)); + offsetRange.AdvanceOffset(sizeof(Ip6::Address)); if (timeout == 0) { @@ -581,7 +581,7 @@ template <> void Manager::HandleTmf(Coap::Message &aMessage, bool proactive; Ip6::Address dua; Ip6::InterfaceIdentifier meshLocalIid; - uint16_t networkNameOffset, networkNameLength; + OffsetRange offsetRange; uint32_t timeSinceLastTransaction; uint16_t srcRloc16 = Mle::kInvalidRloc16; @@ -595,9 +595,7 @@ template <> void Manager::HandleTmf(Coap::Message &aMessage, SuccessOrExit(error = Tlv::Find(aMessage, dua)); SuccessOrExit(error = Tlv::Find(aMessage, meshLocalIid)); SuccessOrExit(error = Tlv::Find(aMessage, timeSinceLastTransaction)); - - SuccessOrExit(error = - Tlv::FindTlvValueOffset(aMessage, ThreadTlv::kNetworkName, networkNameOffset, networkNameLength)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, ThreadTlv::kNetworkName, offsetRange)); error = Tlv::Find(aMessage, srcRloc16); VerifyOrExit(error == kErrorNone || error == kErrorNotFound); diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 72dd7d66f..989877ce5 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -412,6 +412,11 @@ exit: return error; } +Error Message::AppendBytesFromMessage(const Message &aMessage, const OffsetRange &aOffsetRange) +{ + return AppendBytesFromMessage(aMessage, aOffsetRange.GetOffset(), aOffsetRange.GetLength()); +} + Error Message::AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength) { Error error = kErrorNone; @@ -649,11 +654,27 @@ uint16_t Message::ReadBytes(uint16_t aOffset, void *aBuf, uint16_t aLength) cons return static_cast(bufPtr - reinterpret_cast(aBuf)); } +uint16_t Message::ReadBytes(const OffsetRange &aOffsetRange, void *aBuf) const +{ + return ReadBytes(aOffsetRange.GetOffset(), aBuf, aOffsetRange.GetLength()); +} + Error Message::Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const { return (ReadBytes(aOffset, aBuf, aLength) == aLength) ? kErrorNone : kErrorParse; } +Error Message::Read(const OffsetRange &aOffsetRange, void *aBuf, uint16_t aLength) const +{ + Error error = kErrorNone; + + VerifyOrExit(aOffsetRange.Contains(aLength), error = kErrorParse); + VerifyOrExit(ReadBytes(aOffsetRange.GetOffset(), aBuf, aLength) == aLength, error = kErrorParse); + +exit: + return error; +} + bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength, ByteMatcher aMatcher) const { uint16_t bytesToCompare = aLength; diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index 739d23776..64d1307b4 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -52,6 +52,7 @@ #include "common/linked_list.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" +#include "common/offset_range.hpp" #include "common/pool.hpp" #include "common/timer.hpp" #include "common/type_traits.hpp" @@ -707,6 +708,19 @@ public: */ Error AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength); + /** + * Appends bytes read from another or potentially the same message to the end of the current message. + * + * @param[in] aMessage The message to read the bytes from (it can be the same as the current message). + * @param[in] aOffsetRange The offset range in @p aMessage to read bytes from. + * + * @retval kErrorNone Successfully appended the bytes. + * @retval kErrorNoBufs Insufficient available buffers to grow the message. + * @retval kErrorParse Not enough bytes in @p aMessage to read @p aOffsetRange. + * + */ + Error AppendBytesFromMessage(const Message &aMessage, const OffsetRange &aOffsetRange); + /** * Appends an object to the end of the message. * @@ -757,6 +771,17 @@ public: */ uint16_t ReadBytes(uint16_t aOffset, void *aBuf, uint16_t aLength) const; + /** + * Reads bytes from the message. + * + * @param[in] aOffsetRange The offset range in the message to read bytes from. + * @param[out] aBuf A pointer to a data buffer to copy the read bytes into. + * + * @returns The number of bytes read. + * + */ + uint16_t ReadBytes(const OffsetRange &aOffsetRange, void *aBuf) const; + /** * Reads a given number of bytes from the message. * @@ -773,6 +798,22 @@ public: */ Error Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const; + /** + * Reads a given number of bytes from the message. + * + * If there are fewer bytes available in the message or @p aOffsetRange than the requested @p aLength, the + * available bytes are read and copied into @p aBuf. In this case `kErrorParse` will be returned. + * + * @param[in] aOffsetRange The offset range in the message to read from. + * @param[out] aBuf A pointer to a data buffer to copy the read bytes into. + * @param[in] aLength Number of bytes to read. + * + * @retval kErrorNone Requested bytes were successfully read from message. + * @retval kErrorParse Not enough bytes remaining to read the requested @p aLength. + * + */ + Error Read(const OffsetRange &aOffsetRange, void *aBuf, uint16_t aLength) const; + /** * Reads an object from the message. * @@ -796,6 +837,29 @@ public: return Read(aOffset, &aObject, sizeof(ObjectType)); } + /** + * Reads an object from the message. + * + * If there are fewer bytes available in the message or @p aOffsetRange than the requested object size, the + * available bytes will be read and copied into @p aObject (@p aObject will be read partially). In this case + * `kErrorParse` will be returned. + * + * @tparam ObjectType The object type to read from the message. + * + * @param[in] aOffsetRange The offset range in the message to read from. + * @param[out] aObject A reference to the object to read into. + * + * @retval kErrorNone Object @p aObject was successfully read from message. + * @retval kErrorParse Not enough bytes remaining in message to read the entire object. + * + */ + template Error Read(const OffsetRange &aOffsetRange, ObjectType &aObject) const + { + static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); + + return Read(aOffsetRange, &aObject, sizeof(ObjectType)); + } + /** * Compares the bytes in the message at a given offset with a given byte array. * diff --git a/src/core/common/offset_range.cpp b/src/core/common/offset_range.cpp new file mode 100644 index 000000000..cbc39ddb5 --- /dev/null +++ b/src/core/common/offset_range.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, 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 implements helper method for an offset range. + */ + +#include "offset_range.hpp" + +#include "common/code_utils.hpp" +#include "common/message.hpp" +#include "common/num_utils.hpp" +#include "common/numeric_limits.hpp" + +namespace ot { + +void OffsetRange::Init(uint16_t aOffset, uint16_t aLength) +{ + uint16_t maxLength = NumericLimits::kMax - aOffset; + + mOffset = aOffset; + mLength = Min(aLength, maxLength); +} + +void OffsetRange::InitFromRange(uint16_t aStartOffset, uint16_t aEndOffset) +{ + Init(aStartOffset, Max(aStartOffset, aEndOffset) - aStartOffset); +} + +void OffsetRange::InitFromMessageOffsetToEnd(const Message &aMessage) +{ + InitFromRange(aMessage.GetOffset(), aMessage.GetLength()); +} + +void OffsetRange::InitFromMessageFullLength(const Message &aMessage) { Init(0, aMessage.GetLength()); } + +void OffsetRange::AdvanceOffset(uint32_t aLength) +{ + uint16_t length = static_cast(Min(aLength, mLength)); + + mOffset += length; + mLength -= length; +} + +void OffsetRange::ShrinkLength(uint16_t aLength) { mLength = Min(mLength, aLength); } + +} // namespace ot diff --git a/src/core/common/offset_range.hpp b/src/core/common/offset_range.hpp new file mode 100644 index 000000000..9b5b4772e --- /dev/null +++ b/src/core/common/offset_range.hpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2024, 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 an offset range. + */ + +#ifndef OFFSET_RANGE_HPP_ +#define OFFSET_RANGE_HPP_ + +#include "openthread-core-config.h" + +#include +#include + +#include "common/clearable.hpp" + +namespace ot { + +class Message; + +/** + * Represents an offset range. + * + */ +class OffsetRange : public Clearable +{ +public: + /** + * Initializes the `OffsetRange`. + * + * @param[in] aOffset The start offset. + * @param[in] aLength The range length (number of bytes). + * + */ + void Init(uint16_t aOffset, uint16_t aLength); + + /** + * Initializes the `OffsetRange` from given start and end offsets. + * + * The range is inclusive of the start offset (@p aStartOffset) but exclusive of the end offset (@p aEndOffset). + * + * @param[in] aStartOffset The start offset (inclusive). + * @param[in] aEndOffset The end offset (exclusive). + * + */ + void InitFromRange(uint16_t aStartOffset, uint16_t aEndOffset); + + /** + * Initializes the `OffsetRange` from a given `Message` from its offset to the message end. + * + * The start offset of the range is set to `aMessage.GetOffset()`, and the end offset is set to include all bytes + * in the message up to its current length `aMessage.GetLength()`. + * + * @param[in] aMessage The `Message` to initialize the `OffsetRange` from. + * + */ + void InitFromMessageOffsetToEnd(const Message &aMessage); + + /** + * Initializes the `OffsetRange` from a given `Message` from zero offset up to to its full length. + * + * The start offset of the range is set to zero, and the end offset is set to include full length of @p aMessage. + * + * @param[in] aMessage The `Message` to initialize the `OffsetRange` from. + * + */ + void InitFromMessageFullLength(const Message &aMessage); + + /** + * Gets the start offset of the `OffsetRange` + * + * @returns The start offset. + * + */ + uint16_t GetOffset(void) const { return mOffset; } + + /** + * Gets the end offset of the `OffsetRange`. + * + * This offset is exclusive, meaning it marks the position immediately after the last byte within the range. + * + * @returns The end offset. + * + */ + uint16_t GetEndOffset(void) const { return (mOffset + mLength); } + + /** + * Gets the `OffsetRange` length. + * + * @returns The length of the `OffsetRange` in bytes. + * + */ + uint16_t GetLength(void) const { return mLength; } + + /** + * Indicates whether or not the `OffsetRange` is empty. + * + * @retval TRUE The `OffsetRange` is empty. + * @retval FALSE The `OffsetRange` is not empty (contains at least one byte). + * + */ + bool IsEmpty(void) const { return (mLength == 0); } + + /** + * Indicates whether or not the `OffsetRange` contains a given number of bytes. + * + * @param[in] aLength The length to check. + * + * @retval TRUE The `OffsetRange` contains @p aLength or more bytes. + * @retval FALSE The `OffsetRange` does not contain @p aLength bytes. + * + */ + bool Contains(uint32_t aLength) const { return aLength <= mLength; } + + /** + * Advances the start offset forward by the given number of bytes. + * + * This method ensures the start offset does not go beyond the end offset of the `OffsetRange`. If @p aLength is + * greater than the available bytes in the `OffsetRange`, the start offset is adjusted to the end offset, + * effectively shrinking the range to zero length. + * + * @param[in] aLength The number of bytes to advance the start offset. + * + */ + void AdvanceOffset(uint32_t aLength); + + /** + * Shrinks the `OffsetRange` length to a given length. + * + * If the current length of the `OffsetRange` is longer than @p aLength, the offset range is shortened to + * @p aLength. If the range is already shorter or the same, it remains unchanged. + * + * @param[in] aLength The new length to use. + * + */ + void ShrinkLength(uint16_t aLength); + +private: + uint16_t mOffset; + uint16_t mLength; +}; + +} // namespace ot + +#endif // OFFSET_RANGE_HPP_ diff --git a/src/core/common/tlvs.cpp b/src/core/common/tlvs.cpp index 2848e7f0c..0fcf4bbe9 100644 --- a/src/core/common/tlvs.cpp +++ b/src/core/common/tlvs.cpp @@ -56,19 +56,15 @@ const uint8_t *Tlv::GetValue(void) const Error Tlv::AppendTo(Message &aMessage) const { return aMessage.AppendBytes(this, static_cast(GetSize())); } -Error Tlv::ParseAndSkipTlv(const Message &aMessage, uint16_t &aOffset) +Error Tlv::ParseAndSkipTlv(const Message &aMessage, OffsetRange &aOffsetRange) { Error error; ParsedInfo info; - SuccessOrExit(error = info.ParseFrom(aMessage, aOffset)); + SuccessOrExit(error = info.ParseFrom(aMessage, aOffsetRange.GetOffset())); - // `ParseFrom()` has already validated that the entire TLV is - // present within `aMessage`. This ensures that `aOffset + mSize` - // is less than `aMessage.GetLength()`, and therefore we cannot - // have an overflow here. - - aOffset += info.mSize; + VerifyOrExit(aOffsetRange.Contains(info.mSize), error = kErrorParse); + aOffsetRange.AdvanceOffset(info.mSize); exit: return error; @@ -99,32 +95,15 @@ Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tl exit: return error; } -Error Tlv::FindTlvValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aValueOffset, uint16_t &aLength) + +Error Tlv::FindTlvValueOffsetRange(const Message &aMessage, uint8_t aType, OffsetRange &aOffsetRange) { Error error; ParsedInfo info; SuccessOrExit(error = info.FindIn(aMessage, aType)); - aValueOffset = info.mValueOffset; - aLength = info.mLength; - -exit: - return error; -} - -Error Tlv::FindTlvValueStartEndOffsets(const Message &aMessage, - uint8_t aType, - uint16_t &aValueStartOffset, - uint16_t &aValueEndOffset) -{ - Error error; - ParsedInfo info; - - SuccessOrExit(error = info.FindIn(aMessage, aType)); - - aValueStartOffset = info.mValueOffset; - aValueEndOffset = info.mValueOffset + info.mLength; + aOffsetRange.Init(info.mValueOffset, info.mLength); exit: return error; @@ -291,13 +270,11 @@ template Error Tlv::FindUintTlv(const Message &aMessage, uint8_t aType Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, void *aValue, uint16_t aLength) { - Error error; - uint16_t offset; - uint16_t length; + Error error; + OffsetRange offsetRange; - SuccessOrExit(error = FindTlvValueOffset(aMessage, aType, offset, length)); - VerifyOrExit(length >= aLength, error = kErrorParse); - aMessage.ReadBytes(offset, aValue, aLength); + SuccessOrExit(error = FindTlvValueOffsetRange(aMessage, aType, offsetRange)); + error = aMessage.Read(offsetRange, aValue, aLength); exit: return error; diff --git a/src/core/common/tlvs.hpp b/src/core/common/tlvs.hpp index 7baf529a3..3ba23abcb 100644 --- a/src/core/common/tlvs.hpp +++ b/src/core/common/tlvs.hpp @@ -42,6 +42,7 @@ #include "common/const_cast.hpp" #include "common/encoding.hpp" #include "common/error.hpp" +#include "common/offset_range.hpp" #include "common/type_traits.hpp" namespace ot { @@ -245,19 +246,19 @@ public: // Static methods for reading/finding/appending TLVs in a `Message`. /** - * Parses a TLV in a message at a given offset, validating that it is fully contained within the message and then - * updating the offset to skip over the entire parsed TLV. + * Parses a TLV in a message from a given offset range, validating that it is fully contained within the offset + * range and the message, and then updating the offset range to skip over the entire parsed TLV. * * Can be used independent of whether the read TLV (from the message) is an Extended TLV or not. * - * @param[in] aMessage The message to read from. - * @param[in,out] aOffset The offset to read from. On success, it is updated to point after the parsed TLV. + * @param[in] aMessage The message to read from. + * @param[in,out] aOffsetRange The offset range to read from. On success, it is updated to skip the TLV. * - * @retval kErrorNone Successfully parsed a TLV from @p aMessage. @p aOffset is updated. + * @retval kErrorNone Successfully parsed a TLV from @p aMessage. @p aOffsetRange is updated. * @retval kErrorParse The TLV was not well-formed or was not fully contained in @p aMessage. * */ - static Error ParseAndSkipTlv(const Message &aMessage, uint16_t &aOffset); + static Error ParseAndSkipTlv(const Message &aMessage, OffsetRange &aOffsetRange); /** * Reads a TLV's value in a message at a given offset expecting a minimum length for the value. @@ -405,39 +406,19 @@ public: } /** - * Finds the offset and length of TLV value for a given TLV type within @p aMessage. + * Finds the offset range of the TLV value for a given TLV type within @p aMessage. * * Can be used independent of whether the read TLV (from message) is an Extended TLV or not. * * @param[in] aMessage A reference to the message. * @param[in] aType The Type value to search for. - * @param[out] aValueOffset The offset where the value starts. - * @param[out] aLength The length of the value. + * @param[out] aOffsetRange A reference to return the offset range of the TLV value when found. * * @retval kErrorNone Successfully found the TLV. * @retval kErrorNotFound Could not find the TLV with Type @p aType. * */ - static Error FindTlvValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aValueOffset, uint16_t &aLength); - - /** - * Finds the start and end offset of TLV value for a given TLV type with @p aMessage. - * - * Can be used independent of whether the read TLV (from message) is an Extended TLV or not. - * - * @param[in] aMessage A reference to the message. - * @param[in] aType The Type value to search for. - * @param[out] aValueStartOffset The offset where the value starts. - * @param[out] aValueEndOffset The offset immediately after the last byte of value. - * - * @retval kErrorNone Successfully found the TLV. - * @retval kErrorNotFound Could not find the TLV with Type @p aType. - * - */ - static Error FindTlvValueStartEndOffsets(const Message &aMessage, - uint8_t aType, - uint16_t &aValueStartOffset, - uint16_t &aValueEndOffset); + static Error FindTlvValueOffsetRange(const Message &aMessage, uint8_t aType, OffsetRange &aOffsetRange); /** * Searches for a TLV with a given type in a message, ensures its length is same or larger than diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index ef82c3965..ae3cc10e1 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -317,22 +317,20 @@ template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, co Error error = kErrorNone; Message *message = nullptr; Ip6::MessageInfo messageInfo; - uint16_t offset; - uint16_t length; + OffsetRange offsetRange; UdpEncapsulationTlvHeader udpEncapHeader; VerifyOrExit(mState != kStateStopped); - SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Tlv::kUdpEncapsulation, offset, length)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kUdpEncapsulation, offsetRange)); - SuccessOrExit(error = aMessage.Read(offset, udpEncapHeader)); - offset += sizeof(UdpEncapsulationTlvHeader); - length -= sizeof(UdpEncapsulationTlvHeader); + SuccessOrExit(error = aMessage.Read(offsetRange, udpEncapHeader)); + offsetRange.AdvanceOffset(sizeof(UdpEncapsulationTlvHeader)); VerifyOrExit(udpEncapHeader.GetSourcePort() > 0 && udpEncapHeader.GetDestinationPort() > 0, error = kErrorDrop); VerifyOrExit((message = Get().NewMessage()) != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offset, length)); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); messageInfo.SetSockPort(udpEncapHeader.GetSourcePort()); messageInfo.SetSockAddr(mCommissionerAloc.GetAddress()); @@ -376,16 +374,18 @@ bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageIn { ExtendedTlv extTlv; UdpEncapsulationTlvHeader udpEncapHeader; - uint16_t udpLength = aMessage.GetLength() - aMessage.GetOffset(); + OffsetRange offsetRange; + + offsetRange.InitFromMessageOffsetToEnd(aMessage); extTlv.SetType(Tlv::kUdpEncapsulation); - extTlv.SetLength(sizeof(UdpEncapsulationTlvHeader) + udpLength); + extTlv.SetLength(sizeof(UdpEncapsulationTlvHeader) + offsetRange.GetLength()); SuccessOrExit(error = message->Append(extTlv)); udpEncapHeader.SetSourcePort(aMessageInfo.GetPeerPort()); udpEncapHeader.SetDestinationPort(aMessageInfo.GetSockPort()); SuccessOrExit(error = message->Append(udpEncapHeader)); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), udpLength)); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); } SuccessOrExit(error = Tlv::Append(*message, aMessageInfo.GetPeerAddr())); @@ -427,10 +427,12 @@ exit: Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage) { - Error error; + Error error; + OffsetRange offsetRange; + + offsetRange.InitFromMessageOffsetToEnd(aMessage); + SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, offsetRange)); - SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, aMessage.GetOffset(), - aMessage.GetLength() - aMessage.GetOffset())); SuccessOrExit(error = SendMessage(aForwardMessage)); LogInfo("Sent to commissioner"); @@ -498,6 +500,7 @@ template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, co uint16_t joinerRouterRloc; Coap::Message *message = nullptr; Tmf::MessageInfo messageInfo(GetInstance()); + OffsetRange offsetRange; VerifyOrExit(mState != kStateStopped); @@ -508,8 +511,8 @@ template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, co message = Get().NewPriorityNonConfirmablePostMessage(kUriRelayTx); VerifyOrExit(message != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), - aMessage.GetLength() - aMessage.GetOffset())); + offsetRange.InitFromMessageOffsetToEnd(aMessage); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); messageInfo.SetSockAddrToRlocPeerAddrTo(joinerRouterRloc); messageInfo.SetSockPortToTmf(); @@ -531,6 +534,7 @@ Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::Mes Coap::Message *message = nullptr; bool petition = false; bool separate = false; + OffsetRange offsetRange; VerifyOrExit(mState != kStateStopped); @@ -558,8 +562,8 @@ Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::Mes message = Get().NewPriorityConfirmablePostMessage(aUri); VerifyOrExit(message != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), - aMessage.GetLength() - aMessage.GetOffset())); + offsetRange.InitFromMessageOffsetToEnd(aMessage); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); messageInfo.SetSockPortToTmf(); diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index c3987e82c..ce379dc99 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -902,8 +902,7 @@ template <> void Commissioner::HandleTmf(Coap::Message &aMessage, c Ip6::InterfaceIdentifier joinerIid; uint16_t joinerRloc; Ip6::MessageInfo joinerMessageInfo; - uint16_t startOffset; - uint16_t endOffset; + OffsetRange offsetRange; VerifyOrExit(mState == kStateActive, error = kErrorInvalidState); @@ -913,8 +912,7 @@ template <> void Commissioner::HandleTmf(Coap::Message &aMessage, c SuccessOrExit(error = Tlv::Find(aMessage, joinerIid)); SuccessOrExit(error = Tlv::Find(aMessage, joinerRloc)); - SuccessOrExit( - error = Tlv::FindTlvValueStartEndOffsets(aMessage, Tlv::kJoinerDtlsEncapsulation, startOffset, endOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kJoinerDtlsEncapsulation, offsetRange)); if (!Get().IsConnectionActive()) { @@ -951,8 +949,8 @@ template <> void Commissioner::HandleTmf(Coap::Message &aMessage, c LogInfo("Received %s (%s, 0x%04x)", UriToString(), mJoinerIid.ToString().AsCString(), mJoinerRloc); - aMessage.SetOffset(startOffset); - SuccessOrExit(error = aMessage.SetLength(endOffset)); + aMessage.SetOffset(offsetRange.GetOffset()); + SuccessOrExit(error = aMessage.SetLength(offsetRange.GetEndOffset())); joinerMessageInfo.SetPeerAddr(Get().GetMeshLocalEid()); joinerMessageInfo.GetPeerAddr().SetIid(mJoinerIid); diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index cb0c53e9a..ca25268fe 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -337,14 +337,14 @@ void Dataset::SetFrom(const Info &aDatasetInfo) // `mUpdateTime` is already set by `WriteTlvsFrom()`. } -Error Dataset::SetFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength) +Error Dataset::SetFrom(const Message &aMessage, const OffsetRange &aOffsetRange) { Error error = kErrorNone; - VerifyOrExit(aLength <= kMaxLength, error = kErrorInvalidArgs); + VerifyOrExit(aOffsetRange.GetLength() <= kMaxLength, error = kErrorInvalidArgs); - SuccessOrExit(error = aMessage.Read(aOffset, mTlvs, aLength)); - mLength = static_cast(aLength); + SuccessOrExit(error = aMessage.Read(aOffsetRange, mTlvs, aOffsetRange.GetLength())); + mLength = static_cast(aOffsetRange.GetLength()); mUpdateTime = TimerMilli::GetNow(); diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp index d458b2c78..75e448ead 100644 --- a/src/core/meshcop/dataset.hpp +++ b/src/core/meshcop/dataset.hpp @@ -633,16 +633,15 @@ public: /** * Sets the Dataset by reading the TLVs bytes from given message. * - * @param[in] aMessage The message to read from. - * @param[in] aOffset The offset in @p aMessage to start reading the Dataset TLVs. - * @param[in] aLength The dataset length in bytes. + * @param[in] aMessage The message to read from. + * @param[in] aOffsetRange The offset range in @p aMessage to read the Dataset TLVs. * * @retval kErrorNone Successfully set the Dataset. - * @retval kInvalidArgs The @p aLength is longer than `kMaxLength`. + * @retval kInvalidArgs The given offset range length is longer than `kMaxLength`. * @retval kErrorParse Could not read or parse the dataset from @p aMessage. * */ - Error SetFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength); + Error SetFrom(const Message &aMessage, const OffsetRange &aOffsetRange); /** * Returns a pointer to the start of Dataset TLVs sequence. diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 8038af1fb..de2c1d886 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -532,17 +532,17 @@ exit: void DatasetManager::HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const { - TlvList tlvList; - uint8_t tlvType; - uint16_t offset; - uint16_t length; + TlvList tlvList; + uint8_t tlvType; + OffsetRange offsetRange; - SuccessOrExit(Tlv::FindTlvValueOffset(aMessage, Tlv::kGet, offset, length)); + SuccessOrExit(Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kGet, offsetRange)); - for (; length > 0; length--, offset++) + while (!offsetRange.IsEmpty()) { - IgnoreError(aMessage.Read(offset, tlvType)); + IgnoreError(aMessage.Read(offsetRange, tlvType)); tlvList.Add(tlvType); + offsetRange.AdvanceOffset(sizeof(uint8_t)); } // MGMT_PENDING_GET.rsp must include Delay Timer TLV (Thread 1.1.1 diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index 956a5fa58..47e6eaa71 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -71,6 +71,7 @@ Error DatasetManager::ProcessSetOrReplaceRequest(MgmtCommand aCommand, { Error error = kErrorParse; Dataset dataset; + OffsetRange offsetRange; Timestamp activeTimestamp; ChannelTlvValue channelValue; uint16_t sessionId; @@ -81,7 +82,8 @@ Error DatasetManager::ProcessSetOrReplaceRequest(MgmtCommand aCommand, aInfo.Clear(); - SuccessOrExit(dataset.SetFrom(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset())); + offsetRange.InitFromMessageOffsetToEnd(aMessage); + SuccessOrExit(dataset.SetFrom(aMessage, offsetRange)); SuccessOrExit(dataset.ValidateTlvs()); // Verify that the request includes timestamps that are diff --git a/src/core/meshcop/dataset_updater.cpp b/src/core/meshcop/dataset_updater.cpp index fb0a0ef8e..f512f8057 100644 --- a/src/core/meshcop/dataset_updater.cpp +++ b/src/core/meshcop/dataset_updater.cpp @@ -161,14 +161,16 @@ void DatasetUpdater::HandleNotifierEvents(Events aEvents) void DatasetUpdater::HandleDatasetChanged(Dataset::Type aType) { - Dataset requestedDataset; - Dataset newDataset; - Timestamp newTimestamp; - Timestamp requestedTimestamp; + Dataset requestedDataset; + Dataset newDataset; + Timestamp newTimestamp; + Timestamp requestedTimestamp; + OffsetRange offsetRange; VerifyOrExit(IsUpdateOngoing()); - SuccessOrExit(requestedDataset.SetFrom(*mDataset, /* aOffset */ 0, mDataset->GetLength())); + offsetRange.InitFromMessageFullLength(*mDataset); + SuccessOrExit(requestedDataset.SetFrom(*mDataset, offsetRange)); if (aType == Dataset::kActive) { diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index b9f4a57c4..8c31dba51 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -133,6 +133,7 @@ void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &a Tmf::MessageInfo messageInfo(GetInstance()); ExtendedTlv tlv; uint16_t borderAgentRloc; + OffsetRange offsetRange; LogInfo("JoinerRouter::HandleUdpReceive"); @@ -145,10 +146,12 @@ void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &a SuccessOrExit(error = Tlv::Append(*message, aMessageInfo.GetPeerAddr().GetIid())); SuccessOrExit(error = Tlv::Append(*message, Get().GetRloc16())); + offsetRange.InitFromMessageOffsetToEnd(aMessage); + tlv.SetType(Tlv::kJoinerDtlsEncapsulation); - tlv.SetLength(aMessage.GetLength() - aMessage.GetOffset()); + tlv.SetLength(offsetRange.GetLength()); SuccessOrExit(error = message->Append(tlv)); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), tlv.GetLength())); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); messageInfo.SetSockAddrToRlocPeerAddrTo(borderAgentRloc); @@ -168,8 +171,7 @@ template <> void JoinerRouter::HandleTmf(Coap::Message &aMessage, c uint16_t joinerPort; Ip6::InterfaceIdentifier joinerIid; Kek kek; - uint16_t offset; - uint16_t length; + OffsetRange offsetRange; Message *message = nullptr; Message::Settings settings(Message::kNoLinkSecurity, Message::kPriorityNet); Ip6::MessageInfo messageInfo; @@ -181,11 +183,11 @@ template <> void JoinerRouter::HandleTmf(Coap::Message &aMessage, c SuccessOrExit(error = Tlv::Find(aMessage, joinerPort)); SuccessOrExit(error = Tlv::Find(aMessage, joinerIid)); - SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Tlv::kJoinerDtlsEncapsulation, offset, length)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kJoinerDtlsEncapsulation, offsetRange)); VerifyOrExit((message = mSocket.NewMessage(0, settings)) != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offset, length)); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); messageInfo.GetPeerAddr().SetToLinkLocalAddress(joinerIid); messageInfo.SetPeerPort(joinerPort); diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index c4ea22d3b..74d6a39d3 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -146,12 +146,15 @@ Error ChannelMaskTlv::FindIn(const Message &aMessage, uint32_t &aChannelMask) { Error error; EntriesData entriesData; + OffsetRange offsetRange; entriesData.Clear(); entriesData.mMessage = &aMessage; - SuccessOrExit(error = FindTlvValueOffset(aMessage, Tlv::kChannelMask, entriesData.mOffset, entriesData.mLength)); - error = entriesData.Parse(aChannelMask); + SuccessOrExit(error = FindTlvValueOffsetRange(aMessage, Tlv::kChannelMask, offsetRange)); + entriesData.mOffset = offsetRange.GetOffset(); + entriesData.mLength = offsetRange.GetLength(); + error = entriesData.Parse(aChannelMask); exit: return error; diff --git a/src/core/meshcop/tcat_agent.cpp b/src/core/meshcop/tcat_agent.cpp index 86e543966..11c185922 100644 --- a/src/core/meshcop/tcat_agent.cpp +++ b/src/core/meshcop/tcat_agent.cpp @@ -462,10 +462,12 @@ exit: Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength) { - Dataset dataset; - Error error; + Dataset dataset; + OffsetRange offsetRange; + Error error; - SuccessOrExit(error = dataset.SetFrom(aIncommingMessage, aOffset, aLength)); + offsetRange.Init(aOffset, aLength); + SuccessOrExit(error = dataset.SetFrom(aIncommingMessage, offsetRange)); SuccessOrExit(error = dataset.ValidateTlvs()); if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags, diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index 03e2ca4eb..594251a3e 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -312,8 +312,7 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const MeshCoP::Tlv meshcopTlv; MeshCoP::DiscoveryResponseTlv discoveryResponse; ScanResult result; - uint16_t offset; - uint16_t end; + OffsetRange offsetRange; bool didCheckSteeringData = false; Mle::Log(Mle::kMessageReceive, Mle::kTypeDiscoveryResponse, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -321,7 +320,7 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const VerifyOrExit(mState == kStateScanning, error = kErrorDrop); // Find MLE Discovery TLV - SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aRxInfo.mMessage, Tlv::kDiscovery, offset, end)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange)); ClearAllBytes(result); result.mDiscover = true; @@ -333,35 +332,35 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(AsCoreType(&result.mExtAddress)); // Process MeshCoP TLVs - while (offset < end) + while (!offsetRange.IsEmpty()) { - SuccessOrExit(error = aRxInfo.mMessage.Read(offset, meshcopTlv)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, meshcopTlv)); if (meshcopTlv.IsExtended()) { - SuccessOrExit(error = Tlv::ParseAndSkipTlv(aRxInfo.mMessage, offset)); - VerifyOrExit(offset <= end, error = kErrorParse); + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aRxInfo.mMessage, offsetRange)); continue; } - VerifyOrExit(meshcopTlv.GetSize() + offset <= aRxInfo.mMessage.GetLength(), error = kErrorParse); + VerifyOrExit(offsetRange.Contains(meshcopTlv.GetSize()), error = kErrorParse); switch (meshcopTlv.GetType()) { case MeshCoP::Tlv::kDiscoveryResponse: - SuccessOrExit(error = aRxInfo.mMessage.Read(offset, discoveryResponse)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, discoveryResponse)); VerifyOrExit(discoveryResponse.IsValid(), error = kErrorParse); result.mVersion = discoveryResponse.GetVersion(); result.mIsNative = discoveryResponse.IsNativeCommissioner(); break; case MeshCoP::Tlv::kExtendedPanId: - SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offset, + SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offsetRange.GetOffset(), AsCoreType(&result.mExtendedPanId))); break; case MeshCoP::Tlv::kNetworkName: - SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offset, result.mNetworkName.m8)); + SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offsetRange.GetOffset(), + result.mNetworkName.m8)); break; case MeshCoP::Tlv::kSteeringData: @@ -377,7 +376,8 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const steeringData.Init(dataLength); - SuccessOrExit(error = Tlv::ReadTlvValue(aRxInfo.mMessage, offset, steeringData.GetData(), dataLength)); + SuccessOrExit(error = Tlv::ReadTlvValue(aRxInfo.mMessage, offsetRange.GetOffset(), + steeringData.GetData(), dataLength)); if (mEnableFiltering) { @@ -389,15 +389,15 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const break; case MeshCoP::Tlv::kJoinerUdpPort: - SuccessOrExit(error = - Tlv::Read(aRxInfo.mMessage, offset, result.mJoinerUdpPort)); + SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offsetRange.GetOffset(), + result.mJoinerUdpPort)); break; default: break; } - offset += sizeof(meshcopTlv) + meshcopTlv.GetLength(); + offsetRange.AdvanceOffset(meshcopTlv.GetSize()); } VerifyOrExit(!mEnableFiltering || didCheckSteeringData); diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index 840d28e34..7cd068f1a 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -123,11 +123,9 @@ exit: return error; } -void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress) +void Initiator::HandleReport(const Message &aMessage, OffsetRange &aOffsetRange, const Ip6::Address &aAddress) { Error error = kErrorNone; - uint16_t offset = aOffset; - uint16_t endOffset = aOffset + aLength; bool hasStatus = false; bool hasReport = false; Tlv tlv; @@ -142,18 +140,17 @@ void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t values.Clear(); - while (offset < endOffset) + while (!aOffsetRange.IsEmpty()) { - SuccessOrExit(error = aMessage.Read(offset, tlv)); + SuccessOrExit(error = aMessage.Read(aOffsetRange, tlv)); if (tlv.IsExtended()) { - SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offset)); - VerifyOrExit(offset <= endOffset, error = kErrorParse); + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, aOffsetRange)); continue; } - VerifyOrExit(tlv.GetSize() + offset <= endOffset, error = kErrorParse); + VerifyOrExit(aOffsetRange.Contains(tlv.GetSize()), error = kErrorParse); // The report must contain either: // - One or more Report Sub-TLVs (in case of success), or @@ -163,7 +160,7 @@ void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t { case StatusSubTlv::kType: VerifyOrExit(!hasStatus && !hasReport, error = kErrorDrop); - SuccessOrExit(error = Tlv::Read(aMessage, offset, status)); + SuccessOrExit(error = Tlv::Read(aMessage, aOffsetRange.GetOffset(), status)); hasStatus = true; break; @@ -171,7 +168,7 @@ void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t VerifyOrExit(!hasStatus, error = kErrorDrop); // Read the report sub-TLV assuming minimum length - SuccessOrExit(error = aMessage.Read(offset, &reportTlv, sizeof(Tlv) + ReportSubTlv::kMinLength)); + SuccessOrExit(error = aMessage.Read(aOffsetRange, &reportTlv, sizeof(Tlv) + ReportSubTlv::kMinLength)); VerifyOrExit(reportTlv.IsValid(), error = kErrorParse); hasReport = true; @@ -187,7 +184,7 @@ void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t { // If Type ID indicates metric value has 4 bytes length, we // read the full `reportTlv`. - SuccessOrExit(error = aMessage.Read(offset, reportTlv)); + SuccessOrExit(error = aMessage.Read(aOffsetRange.GetOffset(), reportTlv)); } switch (typeId) @@ -220,7 +217,7 @@ void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t break; } - offset += sizeof(Tlv) + tlv.GetLength(); + aOffsetRange.AdvanceOffset(tlv.GetSize()); } VerifyOrExit(hasStatus || hasReport); @@ -310,37 +307,34 @@ exit: Error Initiator::HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress) { - Error error = kErrorNone; - uint16_t offset; - uint16_t endOffset; - uint8_t status; - bool hasStatus = false; + Error error = kErrorNone; + OffsetRange offsetRange; + uint8_t status; + bool hasStatus = false; VerifyOrExit(mMgmtResponseCallback.IsSet()); - SuccessOrExit( - error = Tlv::FindTlvValueStartEndOffsets(aMessage, Mle::Tlv::Type::kLinkMetricsManagement, offset, endOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Mle::Tlv::Type::kLinkMetricsManagement, offsetRange)); - while (offset < endOffset) + while (!offsetRange.IsEmpty()) { Tlv tlv; - SuccessOrExit(error = aMessage.Read(offset, tlv)); + SuccessOrExit(error = aMessage.Read(offsetRange, tlv)); if (tlv.IsExtended()) { - SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offset)); - VerifyOrExit(offset <= endOffset, error = kErrorParse); + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offsetRange)); continue; } - VerifyOrExit(tlv.GetSize() + offset <= endOffset, error = kErrorParse); + VerifyOrExit(offsetRange.Contains(tlv.GetSize()), error = kErrorParse); switch (tlv.GetType()) { case StatusSubTlv::kType: VerifyOrExit(!hasStatus, error = kErrorParse); - SuccessOrExit(error = Tlv::Read(aMessage, offset, status)); + SuccessOrExit(error = Tlv::Read(aMessage, offsetRange.GetOffset(), status)); hasStatus = true; break; @@ -348,7 +342,7 @@ Error Initiator::HandleManagementResponse(const Message &aMessage, const Ip6::Ad break; } - offset += sizeof(Tlv) + tlv.GetLength(); + offsetRange.AdvanceOffset(tlv.GetSize()); } VerifyOrExit(hasStatus, error = kErrorParse); @@ -440,7 +434,7 @@ Error Subject::AppendReport(Message &aMessage, const Message &aRequestMessage, N bool hasQueryId = false; uint16_t length; uint16_t offset; - uint16_t endOffset; + OffsetRange offsetRange; MetricsValues values; values.Clear(); @@ -449,40 +443,43 @@ Error Subject::AppendReport(Message &aMessage, const Message &aRequestMessage, N // Parse MLE Link Metrics Query TLV and its sub-TLVs from // `aRequestMessage`. - SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aRequestMessage, Mle::Tlv::Type::kLinkMetricsQuery, offset, - endOffset)); + SuccessOrExit(error = + Tlv::FindTlvValueOffsetRange(aRequestMessage, Mle::Tlv::Type::kLinkMetricsQuery, offsetRange)); - while (offset < endOffset) + while (!offsetRange.IsEmpty()) { - SuccessOrExit(error = aRequestMessage.Read(offset, tlv)); + OffsetRange tlvOffsetRange; + + SuccessOrExit(error = aRequestMessage.Read(offsetRange, tlv)); if (tlv.IsExtended()) { - SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offset)); - VerifyOrExit(offset <= endOffset, error = kErrorParse); + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offsetRange)); continue; } - VerifyOrExit(tlv.GetSize() + offset <= endOffset, error = kErrorParse); + VerifyOrExit(offsetRange.Contains(tlv.GetSize()), error = kErrorParse); + + tlvOffsetRange = offsetRange; + tlvOffsetRange.ShrinkLength(tlv.GetSize()); switch (tlv.GetType()) { case SubTlv::kQueryId: - SuccessOrExit(error = Tlv::Read(aRequestMessage, offset, queryId)); + SuccessOrExit(error = Tlv::Read(aRequestMessage, tlvOffsetRange.GetOffset(), queryId)); hasQueryId = true; break; case SubTlv::kQueryOptions: - SuccessOrExit(error = ReadTypeIdsFromMessage(aRequestMessage, offset + sizeof(tlv), - static_cast(offset + tlv.GetSize()), - values.GetMetrics())); + tlvOffsetRange.AdvanceOffset(sizeof(tlv)); + SuccessOrExit(error = ReadTypeIdsFromMessage(aRequestMessage, tlvOffsetRange, values.GetMetrics())); break; default: break; } - offset += static_cast(tlv.GetSize()); + offsetRange.AdvanceOffset(tlv.GetSize()); } VerifyOrExit(hasQueryId, error = kErrorParse); @@ -539,31 +536,39 @@ exit: Error Subject::HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus) { Error error = kErrorNone; - uint16_t offset; - uint16_t endOffset; - uint16_t tlvEndOffset; + OffsetRange offsetRange; FwdProbingRegSubTlv fwdProbingSubTlv; EnhAckConfigSubTlv enhAckConfigSubTlv; Metrics metrics; - SuccessOrExit( - error = Tlv::FindTlvValueStartEndOffsets(aMessage, Mle::Tlv::Type::kLinkMetricsManagement, offset, endOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Mle::Tlv::Type::kLinkMetricsManagement, offsetRange)); // Set sub-TLV lengths to zero to indicate that we have // not yet seen them in the message. fwdProbingSubTlv.SetLength(0); enhAckConfigSubTlv.SetLength(0); - for (; offset < endOffset; offset = tlvEndOffset) + while (!offsetRange.IsEmpty()) { - Tlv tlv; - uint16_t minTlvSize; - Tlv *subTlv; + Tlv tlv; + uint16_t minTlvSize; + Tlv *subTlv; + OffsetRange tlvOffsetRange; - SuccessOrExit(error = aMessage.Read(offset, tlv)); + SuccessOrExit(error = aMessage.Read(offsetRange, tlv)); - VerifyOrExit(offset + tlv.GetSize() <= endOffset, error = kErrorParse); - tlvEndOffset = static_cast(offset + tlv.GetSize()); + if (tlv.IsExtended()) + { + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offsetRange)); + continue; + } + + VerifyOrExit(offsetRange.Contains(tlv.GetSize()), error = kErrorParse); + + tlvOffsetRange = offsetRange; + tlvOffsetRange.ShrinkLength(tlv.GetSize()); + + offsetRange.AdvanceOffset(tlv.GetSize()); switch (tlv.GetType()) { @@ -588,8 +593,10 @@ Error Subject::HandleManagementRequest(const Message &aMessage, Neighbor &aNeigh VerifyOrExit(tlv.GetSize() >= minTlvSize, error = kErrorParse); // Read `subTlv` with its `minTlvSize`, followed by the Type IDs. - SuccessOrExit(error = aMessage.Read(offset, subTlv, minTlvSize)); - SuccessOrExit(error = ReadTypeIdsFromMessage(aMessage, offset + minTlvSize, tlvEndOffset, metrics)); + SuccessOrExit(error = aMessage.Read(tlvOffsetRange.GetOffset(), subTlv, minTlvSize)); + + tlvOffsetRange.AdvanceOffset(minTlvSize); + SuccessOrExit(error = ReadTypeIdsFromMessage(aMessage, tlvOffsetRange, metrics)); } if (fwdProbingSubTlv.GetLength() != 0) @@ -609,13 +616,11 @@ exit: Error Subject::HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId) { - Error error = kErrorNone; - uint16_t offset; - uint16_t length; + Error error = kErrorNone; + OffsetRange offsetRange; - SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Mle::Tlv::Type::kLinkProbe, offset, length)); - VerifyOrExit(length >= sizeof(aSeriesId), error = kErrorParse); - error = aMessage.Read(offset, aSeriesId); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Mle::Tlv::Type::kLinkProbe, offsetRange)); + error = aMessage.Read(offsetRange, aSeriesId); exit: return error; @@ -662,20 +667,17 @@ exit: void Subject::Free(SeriesInfo &aSeriesInfo) { mSeriesInfoPool.Free(aSeriesInfo); } -Error Subject::ReadTypeIdsFromMessage(const Message &aMessage, - uint16_t aStartOffset, - uint16_t aEndOffset, - Metrics &aMetrics) +Error Subject::ReadTypeIdsFromMessage(const Message &aMessage, OffsetRange &aOffsetRange, Metrics &aMetrics) { Error error = kErrorNone; aMetrics.Clear(); - for (uint16_t offset = aStartOffset; offset < aEndOffset; offset++) + while (!aOffsetRange.IsEmpty()) { uint8_t typeId; - SuccessOrExit(aMessage.Read(offset, typeId)); + SuccessOrExit(aMessage.Read(aOffsetRange, typeId)); switch (typeId) { @@ -702,7 +704,7 @@ Error Subject::ReadTypeIdsFromMessage(const Message &aMessage, default: if (TypeId::IsExtended(typeId)) { - offset += sizeof(uint8_t); // Skip the additional second byte. + aOffsetRange.AdvanceOffset(sizeof(uint8_t)); // Skip the additional second byte. } else { @@ -710,6 +712,8 @@ Error Subject::ReadTypeIdsFromMessage(const Message &aMessage, } break; } + + aOffsetRange.AdvanceOffset(sizeof(uint8_t)); } exit: diff --git a/src/core/thread/link_metrics.hpp b/src/core/thread/link_metrics.hpp index 7c734bf4a..34294b66e 100644 --- a/src/core/thread/link_metrics.hpp +++ b/src/core/thread/link_metrics.hpp @@ -148,12 +148,11 @@ public: * Handles the received Link Metrics report contained in @p aMessage. * * @param[in] aMessage A reference to the message. - * @param[in] aOffset The offset in bytes where the metrics report sub-TLVs start. - * @param[in] aLength The length of the metrics report sub-TLVs in bytes. + * @param[in] aOffsetRange The offset range in @p aMessage where the metrics report sub-TLVs are present. * @param[in] aAddress A reference to the source address of the message. * */ - void HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress); + void HandleReport(const Message &aMessage, OffsetRange &aOffsetRange, const Ip6::Address &aAddress); /** * Sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series. @@ -342,10 +341,7 @@ private: static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_SERIES_MTD; #endif - static Error ReadTypeIdsFromMessage(const Message &aMessage, - uint16_t aStartOffset, - uint16_t aEndOffset, - Metrics &aMetrics); + static Error ReadTypeIdsFromMessage(const Message &aMessage, OffsetRange &aOffsetRange, Metrics &aMetrics); static Error AppendReportSubTlvToMessage(Message &aMessage, const MetricsValues &aValues); Status ConfigureForwardTrackingSeries(uint8_t aSeriesId, diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 0b013e350..c614ed060 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2842,12 +2842,11 @@ void Mle::HandleDataResponse(RxInfo &aRxInfo) #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE { - uint16_t offset; - uint16_t length; + OffsetRange offsetRange; - if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kLinkMetricsReport, offset, length) == kErrorNone) + if (Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kLinkMetricsReport, offsetRange) == kErrorNone) { - Get().HandleReport(aRxInfo.mMessage, offset, length, + Get().HandleReport(aRxInfo.mMessage, offsetRange, aRxInfo.mMessageInfo.GetPeerAddr()); } } @@ -4948,10 +4947,9 @@ exit: bool Mle::RxMessage::ContainsTlv(Tlv::Type aTlvType) const { - uint16_t offset; - uint16_t length; + OffsetRange offsetRange; - return Tlv::FindTlvValueOffset(*this, aTlvType, offset, length) == kErrorNone; + return Tlv::FindTlvValueOffsetRange(*this, aTlvType, offsetRange) == kErrorNone; } Error Mle::RxMessage::ReadModeTlv(DeviceMode &aMode) const @@ -4979,12 +4977,11 @@ exit: Error Mle::RxMessage::ReadChallengeOrResponse(uint8_t aTlvType, RxChallenge &aRxChallenge) const { - Error error; - uint16_t offset; - uint16_t length; + Error error; + OffsetRange offsetRange; - SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, aTlvType, offset, length)); - error = aRxChallenge.ReadFrom(*this, offset, length); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, aTlvType, offsetRange)); + error = aRxChallenge.ReadFrom(*this, offsetRange); exit: return error; @@ -5049,15 +5046,14 @@ exit: Error Mle::RxMessage::ReadAndSetNetworkDataTlv(const LeaderData &aLeaderData) const { - Error error; - uint16_t offset; - uint16_t length; + Error error; + OffsetRange offsetRange; - SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, Tlv::kNetworkData, offset, length)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, Tlv::kNetworkData, offsetRange)); error = Get().SetNetworkData(aLeaderData.GetDataVersion(NetworkData::kFullSet), aLeaderData.GetDataVersion(NetworkData::kStableSubset), - Get().GetNetworkDataType(), *this, offset, length); + Get().GetNetworkDataType(), *this, offsetRange); exit: return error; } @@ -5078,12 +5074,11 @@ Error Mle::RxMessage::ReadAndSaveDataset(MeshCoP::Dataset::Type aDatasetType, Error error = kErrorNone; Tlv::Type tlvType = (aDatasetType == MeshCoP::Dataset::kActive) ? Tlv::kActiveDataset : Tlv::kPendingDataset; MeshCoP::Dataset dataset; - uint16_t offset; - uint16_t length; + OffsetRange offsetRange; - SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, tlvType, offset, length)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, tlvType, offsetRange)); - SuccessOrExit(error = dataset.SetFrom(*this, offset, length)); + SuccessOrExit(error = dataset.SetFrom(*this, offsetRange)); SuccessOrExit(error = dataset.ValidateTlvs()); SuccessOrExit(error = dataset.WriteTimestamp(aDatasetType, aTimestamp)); @@ -5103,19 +5098,15 @@ exit: Error Mle::RxMessage::ReadTlvRequestTlv(TlvList &aTlvList) const { - Error error; - uint16_t offset; - uint16_t length; + Error error; + OffsetRange offsetRange; - SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, Tlv::kTlvRequest, offset, length)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, Tlv::kTlvRequest, offsetRange)); - if (length > aTlvList.GetMaxSize()) - { - length = aTlvList.GetMaxSize(); - } + offsetRange.ShrinkLength(aTlvList.GetMaxSize()); - ReadBytes(offset, aTlvList.GetArrayBuffer(), length); - aTlvList.SetLength(static_cast(length)); + ReadBytes(offsetRange, aTlvList.GetArrayBuffer()); + aTlvList.SetLength(static_cast(offsetRange.GetLength())); exit: return error; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 6948f9e43..c4aad8ce4 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1761,11 +1761,10 @@ exit: Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) { - Error error; - uint16_t offset; - uint16_t endOffset; - uint8_t count = 0; - uint8_t storedCount = 0; + Error error; + OffsetRange offsetRange; + uint8_t count = 0; + uint8_t storedCount = 0; #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE Ip6::Address oldDua; #endif @@ -1775,8 +1774,7 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) OT_UNUSED_VARIABLE(storedCount); - SuccessOrExit(error = - Tlv::FindTlvValueStartEndOffsets(aRxInfo.mMessage, Tlv::kAddressRegistration, offset, endOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kAddressRegistration, offsetRange)); #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE if (aChild.GetDomainUnicastAddress(oldDua) != kErrorNone) @@ -1807,14 +1805,14 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) aChild.ClearIp6Addresses(); - while (offset < endOffset) + while (!offsetRange.IsEmpty()) { uint8_t controlByte; Ip6::Address address; // Read out the control byte (first byte in entry) - SuccessOrExit(error = aRxInfo.mMessage.Read(offset, controlByte)); - offset++; + SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, controlByte)); + offsetRange.AdvanceOffset(sizeof(uint8_t)); count++; address.Clear(); @@ -1828,9 +1826,8 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) uint8_t contextId = AddressRegistrationTlv::GetContextId(controlByte); Lowpan::Context context; - VerifyOrExit(offset + sizeof(Ip6::InterfaceIdentifier) <= endOffset, error = kErrorParse); - IgnoreError(aRxInfo.mMessage.Read(offset, address.GetIid())); - offset += sizeof(Ip6::InterfaceIdentifier); + IgnoreError(aRxInfo.mMessage.Read(offsetRange, address.GetIid())); + offsetRange.AdvanceOffset(sizeof(Ip6::InterfaceIdentifier)); if (Get().GetContext(contextId, context) != kErrorNone) { @@ -1845,9 +1842,8 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) { // Uncompressed entry contains the full IPv6 address. - VerifyOrExit(offset + sizeof(Ip6::Address) <= endOffset, error = kErrorParse); - IgnoreError(aRxInfo.mMessage.Read(offset, address)); - offset += sizeof(Ip6::Address); + IgnoreError(aRxInfo.mMessage.Read(offsetRange, address)); + offsetRange.AdvanceOffset(sizeof(Ip6::Address)); } #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE @@ -2624,8 +2620,7 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo) MeshCoP::Tlv meshcopTlv; MeshCoP::DiscoveryRequestTlv discoveryRequestTlv; MeshCoP::ExtendedPanId extPanId; - uint16_t offset; - uint16_t end; + OffsetRange offsetRange; Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -2633,31 +2628,31 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo) VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState); - SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aRxInfo.mMessage, Tlv::kDiscovery, offset, end)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange)); - while (offset < end) + while (!offsetRange.IsEmpty()) { - SuccessOrExit(error = aRxInfo.mMessage.Read(offset, meshcopTlv)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, meshcopTlv)); if (meshcopTlv.IsExtended()) { - SuccessOrExit(error = Tlv::ParseAndSkipTlv(aRxInfo.mMessage, offset)); - VerifyOrExit(offset <= end, error = kErrorParse); + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aRxInfo.mMessage, offsetRange)); continue; } - VerifyOrExit(meshcopTlv.GetSize() + offset <= aRxInfo.mMessage.GetLength(), error = kErrorParse); + VerifyOrExit(offsetRange.Contains(meshcopTlv.GetSize())); switch (meshcopTlv.GetType()) { case MeshCoP::Tlv::kDiscoveryRequest: - SuccessOrExit(error = aRxInfo.mMessage.Read(offset, discoveryRequestTlv)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, discoveryRequestTlv)); VerifyOrExit(discoveryRequestTlv.IsValid(), error = kErrorParse); break; case MeshCoP::Tlv::kExtendedPanId: - SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offset, extPanId)); + SuccessOrExit( + error = Tlv::Read(aRxInfo.mMessage, offsetRange.GetOffset(), extPanId)); VerifyOrExit(Get().GetExtPanId() != extPanId, error = kErrorDrop); break; @@ -2666,7 +2661,7 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo) break; } - offset += sizeof(meshcopTlv) + meshcopTlv.GetLength(); + offsetRange.AdvanceOffset(meshcopTlv.GetSize()); } if (discoveryRequestTlv.IsValid()) diff --git a/src/core/thread/mle_types.cpp b/src/core/thread/mle_types.cpp index 0c87ce6e9..9d61bbe12 100644 --- a/src/core/thread/mle_types.cpp +++ b/src/core/thread/mle_types.cpp @@ -160,17 +160,19 @@ void TxChallenge::GenerateRandom(void) { IgnoreError(Random::Crypto::Fill(*this) //--------------------------------------------------------------------------------------------------------------------- // RxChallenge -Error RxChallenge::ReadFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength) +Error RxChallenge::ReadFrom(const Message &aMessage, const OffsetRange &aOffsetRange) { - Error error = kErrorNone; + Error error = kErrorNone; + OffsetRange offsetRange = aOffsetRange; Clear(); - aLength = Min(aLength, kMaxSize); - VerifyOrExit(kMinSize <= aLength, error = kErrorParse); + offsetRange.ShrinkLength(kMaxSize); - SuccessOrExit(error = aMessage.Read(aOffset, mArray.GetArrayBuffer(), aLength)); - mArray.SetLength(static_cast(aLength)); + VerifyOrExit(offsetRange.Contains(kMinSize), error = kErrorParse); + + SuccessOrExit(error = aMessage.Read(offsetRange, mArray.GetArrayBuffer(), offsetRange.GetLength())); + mArray.SetLength(static_cast(offsetRange.GetLength())); exit: return error; diff --git a/src/core/thread/mle_types.hpp b/src/core/thread/mle_types.hpp index f8ee58cbf..88be01597 100644 --- a/src/core/thread/mle_types.hpp +++ b/src/core/thread/mle_types.hpp @@ -51,6 +51,7 @@ #include "common/encoding.hpp" #include "common/equatable.hpp" #include "common/numeric_limits.hpp" +#include "common/offset_range.hpp" #include "common/string.hpp" #include "mac/mac_types.hpp" #include "meshcop/extended_panid.hpp" @@ -526,15 +527,14 @@ public: * * If the given @p aLength is longer than `kMaxSize`, only `kMaxSize` bytes will be read. * - * @param[in] aMessage The message to read the challenge from. - * @param[in] aOffset The offset in @p aMessage to read from. - * @param[in] aLength Number of bytes to read. + * @param[in] aMessage The message to read the challenge from. + * @param[in] aOffsetRange The offset range in @p aMessage to read from. * * @retval kErrorNone Successfully read the challenge data from @p aMessage. - * @retval kErrorParse Not enough bytes to read, or invalid @p aLength (smaller than `kMinSize`). + * @retval kErrorParse Not enough bytes to read, or invalid length (smaller than `kMinSize`). * */ - Error ReadFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength); + Error ReadFrom(const Message &aMessage, const OffsetRange &aOffsetRange); /** * Compares the `RxChallenge` with a given `TxChallenge`. diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index 43f896e70..1b9f85df3 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -482,8 +482,8 @@ Error MlrManager::ParseMlrResponse(Error aResult, uint8_t &aStatus, AddressArray &aFailedAddresses) { - Error error; - uint16_t addressesOffset, addressesLength; + Error error; + OffsetRange offsetRange; aStatus = ThreadStatusTlv::kMlrGeneralFailure; @@ -492,15 +492,16 @@ Error MlrManager::ParseMlrResponse(Error aResult, SuccessOrExit(error = Tlv::Find(*aMessage, aStatus)); - if (ThreadTlv::FindTlvValueOffset(*aMessage, Ip6AddressesTlv::kIp6Addresses, addressesOffset, addressesLength) == - kErrorNone) + if (ThreadTlv::FindTlvValueOffsetRange(*aMessage, Ip6AddressesTlv::kIp6Addresses, offsetRange) == kErrorNone) { - VerifyOrExit(addressesLength % sizeof(Ip6::Address) == 0, error = kErrorParse); - VerifyOrExit(addressesLength / sizeof(Ip6::Address) <= Ip6AddressesTlv::kMaxAddresses, error = kErrorParse); + VerifyOrExit(offsetRange.GetLength() % sizeof(Ip6::Address) == 0, error = kErrorParse); + VerifyOrExit(offsetRange.GetLength() / sizeof(Ip6::Address) <= Ip6AddressesTlv::kMaxAddresses, + error = kErrorParse); - for (uint16_t offset = 0; offset < addressesLength; offset += sizeof(Ip6::Address)) + while (!offsetRange.IsEmpty()) { - IgnoreError(aMessage->Read(addressesOffset + offset, *aFailedAddresses.PushBack())); + IgnoreError(aMessage->Read(offsetRange, *aFailedAddresses.PushBack())); + offsetRange.AdvanceOffset(sizeof(Ip6::Address)); } } diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index efb6225bd..f032f4c0b 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -426,19 +426,19 @@ Error Leader::DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t &aRloc16) co return error; } -Error Leader::SetNetworkData(uint8_t aVersion, - uint8_t aStableVersion, - Type aType, - const Message &aMessage, - uint16_t aOffset, - uint16_t aLength) +Error Leader::SetNetworkData(uint8_t aVersion, + uint8_t aStableVersion, + Type aType, + const Message &aMessage, + const OffsetRange &aOffsetRange) { - Error error = kErrorNone; + Error error = kErrorNone; + uint16_t length = aOffsetRange.GetLength(); - VerifyOrExit(aLength <= kMaxSize, error = kErrorParse); - SuccessOrExit(error = aMessage.Read(aOffset, GetBytes(), aLength)); + VerifyOrExit(length <= kMaxSize, error = kErrorParse); + SuccessOrExit(error = aMessage.Read(aOffsetRange.GetOffset(), GetBytes(), length)); - SetLength(static_cast(aLength)); + SetLength(static_cast(length)); mVersion = aVersion; mStableVersion = aStableVersion; diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp index 72610fc62..0c13a2f67 100644 --- a/src/core/thread/network_data_leader.hpp +++ b/src/core/thread/network_data_leader.hpp @@ -168,19 +168,17 @@ public: * @param[in] aStableVersion The Stable Version value. * @param[in] aType The Network Data type to set, the full set or stable subset. * @param[in] aMessage A reference to the message. - * @param[in] aOffset The offset in @p aMessage pointing to start of Network Data. - * @param[in] aLength The length of Network Data. + * @param[in] aOffsetRange The offset range in @p aMessage to read from. * * @retval kErrorNone Successfully set the network data. * @retval kErrorParse Network Data in @p aMessage is not valid. * */ - Error SetNetworkData(uint8_t aVersion, - uint8_t aStableVersion, - Type aType, - const Message &aMessage, - uint16_t aOffset, - uint16_t aLength); + Error SetNetworkData(uint8_t aVersion, + uint8_t aStableVersion, + Type aType, + const Message &aMessage, + const OffsetRange &aOffsetRange); /** * Gets the Commissioning Dataset from Network Data. diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index 4b8b4cb52..a174ba7c7 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -206,25 +206,25 @@ exit: template <> void Leader::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - uint16_t length; - uint16_t offset; Coap::Message *response = nullptr; + OffsetRange offsetRange; VerifyOrExit(Get().IsLeader() && !mWaitingForNetDataSync); response = Get().NewPriorityResponseMessage(aMessage); VerifyOrExit(response != nullptr); - if (Tlv::FindTlvValueOffset(aMessage, MeshCoP::Tlv::kGet, offset, length) == kErrorNone) + if (Tlv::FindTlvValueOffsetRange(aMessage, MeshCoP::Tlv::kGet, offsetRange) == kErrorNone) { // Append the requested sub-TLV types given in Get TLV. - for (; length > 0; offset++, length--) + while (!offsetRange.IsEmpty()) { uint8_t type; const MeshCoP::Tlv *subTlv; - IgnoreError(aMessage.Read(offset, type)); + IgnoreError(aMessage.Read(offsetRange, type)); + offsetRange.AdvanceOffset(sizeof(type)); subTlv = FindCommissioningDataSubTlv(type); @@ -1334,12 +1334,14 @@ exit: Error Leader::SetCommissioningData(const Message &aMessage) { - Error error = kErrorNone; - uint16_t dataLength = aMessage.GetLength() - aMessage.GetOffset(); + Error error = kErrorNone; + OffsetRange offsetRange; CommissioningDataTlv *dataTlv; - SuccessOrExit(error = UpdateCommissioningData(dataLength, dataTlv)); - aMessage.ReadBytes(aMessage.GetOffset(), dataTlv->GetValue(), dataLength); + offsetRange.InitFromMessageOffsetToEnd(aMessage); + + SuccessOrExit(error = UpdateCommissioningData(offsetRange.GetLength(), dataTlv)); + aMessage.ReadBytes(offsetRange, dataTlv->GetValue()); exit: return error; diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 6e168c290..03080471f 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -239,17 +239,17 @@ Error Server::AppendMacCounters(Message &aMessage) Error Server::AppendRequestedTlvs(const Message &aRequest, Message &aResponse) { - Error error; - uint16_t offset; - uint16_t endOffset; + Error error; + OffsetRange offsetRange; - SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aRequest, Tlv::kTypeList, offset, endOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange)); - for (; offset < endOffset; offset++) + while (!offsetRange.IsEmpty()) { uint8_t tlvType; - SuccessOrExit(error = aRequest.Read(offset, tlvType)); + SuccessOrExit(error = aRequest.Read(offsetRange, tlvType)); + offsetRange.AdvanceOffset(sizeof(tlvType)); SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse)); } @@ -536,9 +536,7 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa Coap::Message *answer; Error error; AnswerInfo info; - uint16_t offset; - uint16_t length; - uint16_t endOffset; + OffsetRange offsetRange; AnswerTlv answerTlv; if (Tlv::Find(aRequest, info.mQueryId) == kErrorNone) @@ -550,14 +548,14 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa SuccessOrExit(error = AllocateAnswer(answer, info)); - SuccessOrExit(error = Tlv::FindTlvValueOffset(aRequest, Tlv::kTypeList, offset, length)); - endOffset = offset + length; + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange)); - for (; offset < endOffset; offset++) + while (!offsetRange.IsEmpty()) { uint8_t tlvType; - SuccessOrExit(error = aRequest.Read(offset, tlvType)); + SuccessOrExit(error = aRequest.Read(offsetRange, tlvType)); + offsetRange.AdvanceOffset(sizeof(tlvType)); switch (tlvType) { diff --git a/src/core/utils/mesh_diag.cpp b/src/core/utils/mesh_diag.cpp index 33c001d65..9b8981e5b 100644 --- a/src/core/utils/mesh_diag.cpp +++ b/src/core/utils/mesh_diag.cpp @@ -379,8 +379,7 @@ exit: bool MeshDiag::ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { bool didPorcess = false; - uint16_t offset; - uint16_t endOffset; + OffsetRange offsetRange; ChildIp6AddressListTlvValue tlvValue; Ip6AddrIterator ip6AddrIterator; @@ -388,11 +387,11 @@ bool MeshDiag::ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6: while (true) { - SuccessOrExit(Tlv::FindTlvValueStartEndOffsets(aMessage, ChildIp6AddressListTlv::kType, offset, endOffset)); + SuccessOrExit(Tlv::FindTlvValueOffsetRange(aMessage, ChildIp6AddressListTlv::kType, offsetRange)); didPorcess = true; - if (offset == endOffset) + if (offsetRange.IsEmpty()) { // We reached end of the list mState = kStateIdle; @@ -404,13 +403,11 @@ bool MeshDiag::ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6: // Read the `ChildIp6AddressListTlvValue` (which contains the // child RLOC16) and then prepare the `Ip6AddrIterator`. - VerifyOrExit(offset + sizeof(tlvValue) <= endOffset); - IgnoreError(aMessage.Read(offset, tlvValue)); - offset += sizeof(tlvValue); + SuccessOrExit(aMessage.Read(offsetRange, tlvValue)); + offsetRange.AdvanceOffset(sizeof(tlvValue)); - ip6AddrIterator.mMessage = &aMessage; - ip6AddrIterator.mCurOffset = offset; - ip6AddrIterator.mEndOffset = endOffset; + ip6AddrIterator.mMessage = &aMessage; + ip6AddrIterator.mOffsetRange = offsetRange; mQueryChildrenIp6Addrs.mCallback.InvokeIfSet(kErrorPending, tlvValue.GetRloc16(), &ip6AddrIterator); @@ -418,7 +415,7 @@ bool MeshDiag::ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6: // callback. VerifyOrExit(mState == kStateQueryChildrenIp6Addrs); - aMessage.SetOffset(endOffset); + aMessage.SetOffset(offsetRange.GetEndOffset()); } exit: @@ -531,7 +528,7 @@ Error MeshDiag::Ip6AddrIterator::InitFrom(const Message &aMessage) { Error error; - SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aMessage, Ip6AddressListTlv::kType, mCurOffset, mEndOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Ip6AddressListTlv::kType, mOffsetRange)); mMessage = &aMessage; exit: @@ -543,10 +540,9 @@ Error MeshDiag::Ip6AddrIterator::GetNextAddress(Ip6::Address &aAddress) Error error = kErrorNone; VerifyOrExit(mMessage != nullptr, error = kErrorNotFound); - VerifyOrExit(mCurOffset + sizeof(Ip6::Address) <= mEndOffset, error = kErrorNotFound); - IgnoreError(mMessage->Read(mCurOffset, aAddress)); - mCurOffset += sizeof(Ip6::Address); + VerifyOrExit(mMessage->Read(mOffsetRange, aAddress) == kErrorNone, error = kErrorNotFound); + mOffsetRange.AdvanceOffset(sizeof(Ip6::Address)); exit: return error; @@ -559,7 +555,8 @@ Error MeshDiag::ChildIterator::InitFrom(const Message &aMessage, uint16_t aParen { Error error; - SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aMessage, ChildTableTlv::kType, mCurOffset, mEndOffset)); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, ChildTableTlv::kType, mOffsetRange)); + mMessage = &aMessage; mParentRloc16 = aParentRloc16; @@ -573,10 +570,9 @@ Error MeshDiag::ChildIterator::GetNextChildInfo(ChildInfo &aChildInfo) ChildTableEntry entry; VerifyOrExit(mMessage != nullptr, error = kErrorNotFound); - VerifyOrExit(mCurOffset + sizeof(ChildTableEntry) <= mEndOffset, error = kErrorNotFound); - IgnoreError(mMessage->Read(mCurOffset, entry)); - mCurOffset += sizeof(ChildTableEntry); + VerifyOrExit(mMessage->Read(mOffsetRange, entry) == kErrorNone, error = kErrorNotFound); + mOffsetRange.AdvanceOffset(sizeof(ChildTableEntry)); aChildInfo.mRloc16 = mParentRloc16 + entry.GetChildId(); entry.GetMode().Get(aChildInfo.mMode); diff --git a/src/core/utils/mesh_diag.hpp b/src/core/utils/mesh_diag.hpp index 3e7b04c11..3869d8dce 100644 --- a/src/core/utils/mesh_diag.hpp +++ b/src/core/utils/mesh_diag.hpp @@ -105,8 +105,7 @@ public: Error InitFrom(const Message &aMessage); const Message *mMessage; - uint16_t mCurOffset; - uint16_t mEndOffset; + OffsetRange mOffsetRange; }; /** @@ -153,8 +152,7 @@ public: Error InitFrom(const Message &aMessage, uint16_t aParentRloc16); const Message *mMessage; - uint16_t mCurOffset; - uint16_t mEndOffset; + OffsetRange mOffsetRange; uint16_t mParentRloc16; }; diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 92aad7622..e936417c1 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -207,6 +207,7 @@ ot_unit_test(ndproxy_table) ot_unit_test(netif) ot_unit_test(network_data) ot_unit_test(network_name) +ot_unit_test(offset_range) ot_unit_test(pool) ot_unit_test(power_calibration) ot_unit_test(priority_queue) diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp index a630086ac..6e2cbc7c9 100644 --- a/tests/unit/test_lowpan.cpp +++ b/tests/unit/test_lowpan.cpp @@ -103,6 +103,7 @@ void TestIphcVector::GetUncompressedStream(Message &aMessage) static void Init(void) { otMeshLocalPrefix meshLocalPrefix = {{0xfd, 0x00, 0xca, 0xfe, 0xfa, 0xce, 0x12, 0x34}}; + OffsetRange offsetRange; sInstance->Get().SetMeshLocalPrefix(static_cast(meshLocalPrefix)); @@ -127,8 +128,10 @@ static void Init(void) SuccessOrQuit(message->AppendBytes(mockNetworkData, sizeof(mockNetworkData))); + offsetRange.Init(2, 0x20); + IgnoreError( - sInstance->Get().SetNetworkData(0, 0, NetworkData::kStableSubset, *message, 2, 0x20)); + sInstance->Get().SetNetworkData(0, 0, NetworkData::kStableSubset, *message, offsetRange)); } /** diff --git a/tests/unit/test_offset_range.cpp b/tests/unit/test_offset_range.cpp new file mode 100644 index 000000000..c648c856b --- /dev/null +++ b/tests/unit/test_offset_range.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2024, 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. + */ + +#include "common/message.hpp" +#include "common/offset_range.hpp" +#include "instance/instance.hpp" + +#include "test_platform.h" +#include "test_util.hpp" + +namespace ot { + +void TestOffsetRange(void) +{ + Instance *instance; + Message *message; + OffsetRange offsetRange; + + instance = testInitInstance(); + VerifyOrQuit(instance != nullptr); + + // Empty `OffsetRange` + + offsetRange.Clear(); + VerifyOrQuit(offsetRange.GetOffset() == 0); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 0); + VerifyOrQuit(offsetRange.IsEmpty()); + + offsetRange.ShrinkLength(10); + VerifyOrQuit(offsetRange.GetOffset() == 0); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 0); + VerifyOrQuit(offsetRange.IsEmpty()); + + offsetRange.AdvanceOffset(20); + VerifyOrQuit(offsetRange.GetOffset() == 0); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 0); + VerifyOrQuit(offsetRange.IsEmpty()); + + // Empty `OffsetRange` with non-zero starting offset + + offsetRange.Init(100, 0); + VerifyOrQuit(offsetRange.GetOffset() == 100); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 100); + VerifyOrQuit(offsetRange.IsEmpty()); + + offsetRange.ShrinkLength(10); + VerifyOrQuit(offsetRange.GetOffset() == 100); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 100); + VerifyOrQuit(offsetRange.IsEmpty()); + + offsetRange.AdvanceOffset(20); + VerifyOrQuit(offsetRange.GetOffset() == 100); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 100); + VerifyOrQuit(offsetRange.IsEmpty()); + + // Non-empty `OffsetRange` + + offsetRange.Init(200, 10); + VerifyOrQuit(offsetRange.GetOffset() == 200); + VerifyOrQuit(offsetRange.GetLength() == 10); + VerifyOrQuit(offsetRange.GetEndOffset() == 210); + VerifyOrQuit(!offsetRange.IsEmpty()); + VerifyOrQuit(offsetRange.Contains(10)); + VerifyOrQuit(!offsetRange.Contains(11)); + + offsetRange.ShrinkLength(10); + VerifyOrQuit(offsetRange.GetOffset() == 200); + VerifyOrQuit(offsetRange.GetLength() == 10); + VerifyOrQuit(offsetRange.GetEndOffset() == 210); + + offsetRange.ShrinkLength(20); + VerifyOrQuit(offsetRange.GetOffset() == 200); + VerifyOrQuit(offsetRange.GetLength() == 10); + VerifyOrQuit(offsetRange.GetEndOffset() == 210); + + offsetRange.ShrinkLength(5); + VerifyOrQuit(offsetRange.GetOffset() == 200); + VerifyOrQuit(offsetRange.GetLength() == 5); + VerifyOrQuit(offsetRange.GetEndOffset() == 205); + VerifyOrQuit(!offsetRange.Contains(10)); + VerifyOrQuit(!offsetRange.Contains(6)); + VerifyOrQuit(offsetRange.Contains(5)); + + offsetRange.AdvanceOffset(4); + VerifyOrQuit(offsetRange.GetOffset() == 204); + VerifyOrQuit(offsetRange.GetLength() == 1); + VerifyOrQuit(offsetRange.GetEndOffset() == 205); + VerifyOrQuit(!offsetRange.IsEmpty()); + VerifyOrQuit(offsetRange.Contains(1)); + VerifyOrQuit(!offsetRange.Contains(2)); + + offsetRange.AdvanceOffset(1); + VerifyOrQuit(offsetRange.GetOffset() == 205); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 205); + VerifyOrQuit(offsetRange.IsEmpty()); + + // `InitFromRange()` + + offsetRange.InitFromRange(300, 400); + VerifyOrQuit(offsetRange.GetOffset() == 300); + VerifyOrQuit(offsetRange.GetLength() == 100); + VerifyOrQuit(offsetRange.GetEndOffset() == 400); + VerifyOrQuit(!offsetRange.IsEmpty()); + VerifyOrQuit(offsetRange.Contains(100)); + VerifyOrQuit(!offsetRange.Contains(101)); + + offsetRange.AdvanceOffset(101); + VerifyOrQuit(offsetRange.GetOffset() == 400); + VerifyOrQuit(offsetRange.GetLength() == 0); + VerifyOrQuit(offsetRange.GetEndOffset() == 400); + VerifyOrQuit(offsetRange.IsEmpty()); + + // Init from a `Message` from offset or full length + + message = instance->Get().Allocate(Message::kTypeOther); + VerifyOrQuit(message != nullptr); + + SuccessOrQuit(message->SetLength(120)); + VerifyOrQuit(message->GetOffset() == 0); + + offsetRange.InitFromMessageOffsetToEnd(*message); + VerifyOrQuit(offsetRange.GetOffset() == 0); + VerifyOrQuit(offsetRange.GetLength() == 120); + VerifyOrQuit(offsetRange.GetEndOffset() == 120); + + offsetRange.InitFromMessageFullLength(*message); + VerifyOrQuit(offsetRange.GetOffset() == 0); + VerifyOrQuit(offsetRange.GetLength() == 120); + VerifyOrQuit(offsetRange.GetEndOffset() == 120); + + message->SetOffset(40); + VerifyOrQuit(message->GetOffset() == 40); + + offsetRange.InitFromMessageOffsetToEnd(*message); + VerifyOrQuit(offsetRange.GetOffset() == 40); + VerifyOrQuit(offsetRange.GetLength() == 80); + VerifyOrQuit(offsetRange.GetEndOffset() == 120); + + offsetRange.InitFromMessageFullLength(*message); + VerifyOrQuit(offsetRange.GetOffset() == 0); + VerifyOrQuit(offsetRange.GetLength() == 120); + VerifyOrQuit(offsetRange.GetEndOffset() == 120); + + message->Free(); + testFreeInstance(instance); +} + +} // namespace ot + +int main(void) +{ + ot::TestOffsetRange(); + printf("All tests passed\n"); + return 0; +} diff --git a/tests/unit/test_tlv.cpp b/tests/unit/test_tlv.cpp index 703abe3e5..165782642 100644 --- a/tests/unit/test_tlv.cpp +++ b/tests/unit/test_tlv.cpp @@ -45,7 +45,7 @@ void TestTlv(void) Tlv tlv; ExtendedTlv extTlv; uint16_t offset; - uint16_t valueOffset; + OffsetRange offsetRange; uint16_t length; uint8_t buffer[4]; @@ -57,7 +57,7 @@ void TestTlv(void) VerifyOrQuit(message->GetOffset() == 0); VerifyOrQuit(message->GetLength() == 0); - VerifyOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 1, valueOffset, length) == kErrorNotFound); + VerifyOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 1, offsetRange) == kErrorNotFound); VerifyOrQuit(Tlv::ReadTlvValue(*message, 0, buffer, 1) == kErrorParse); // Add an empty TLV with type 1 and check that we can find it @@ -68,9 +68,9 @@ void TestTlv(void) tlv.SetLength(0); SuccessOrQuit(message->Append(tlv)); - SuccessOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 1, valueOffset, length)); - VerifyOrQuit(valueOffset == sizeof(Tlv)); - VerifyOrQuit(length == 0); + SuccessOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 1, offsetRange)); + VerifyOrQuit(offsetRange.GetOffset() == sizeof(Tlv)); + VerifyOrQuit(offsetRange.GetLength() == 0); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 0)); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1) == kErrorParse); @@ -82,9 +82,9 @@ void TestTlv(void) extTlv.SetLength(0); SuccessOrQuit(message->Append(extTlv)); - SuccessOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 2, valueOffset, length)); - VerifyOrQuit(valueOffset == offset + sizeof(ExtendedTlv)); - VerifyOrQuit(length == 0); + SuccessOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 2, offsetRange)); + VerifyOrQuit(offsetRange.GetOffset() == offset + sizeof(ExtendedTlv)); + VerifyOrQuit(offsetRange.GetLength() == 0); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 0)); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1) == kErrorParse); @@ -97,9 +97,9 @@ void TestTlv(void) SuccessOrQuit(message->Append(tlv)); SuccessOrQuit(message->Append(0xff)); - SuccessOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 3, valueOffset, length)); - VerifyOrQuit(valueOffset == offset + sizeof(Tlv)); - VerifyOrQuit(length == 1); + SuccessOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 3, offsetRange)); + VerifyOrQuit(offsetRange.GetOffset() == offset + sizeof(Tlv)); + VerifyOrQuit(offsetRange.GetLength() == 1); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1)); VerifyOrQuit(buffer[0] == 0x0ff); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 2) == kErrorParse); @@ -114,9 +114,9 @@ void TestTlv(void) SuccessOrQuit(message->Append(0x12)); SuccessOrQuit(message->Append(0x34)); - SuccessOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 4, valueOffset, length)); - VerifyOrQuit(valueOffset == offset + sizeof(ExtendedTlv)); - VerifyOrQuit(length == 2); + SuccessOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 4, offsetRange)); + VerifyOrQuit(offsetRange.GetOffset() == offset + sizeof(ExtendedTlv)); + VerifyOrQuit(offsetRange.GetLength() == 2); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1)); VerifyOrQuit(buffer[0] == 0x12); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 2)); @@ -132,15 +132,15 @@ void TestTlv(void) tlv.SetLength(1); SuccessOrQuit(message->Append(tlv)); - VerifyOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 5, valueOffset, length) != kErrorNone); + VerifyOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 5, offsetRange) != kErrorNone); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 0) == kErrorParse); // Add the missing value. SuccessOrQuit(message->Append(0xaa)); - SuccessOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 5, valueOffset, length)); - VerifyOrQuit(valueOffset == offset + sizeof(Tlv)); - VerifyOrQuit(length == 1); + SuccessOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 5, offsetRange)); + VerifyOrQuit(offsetRange.GetOffset() == offset + sizeof(Tlv)); + VerifyOrQuit(offsetRange.GetLength() == 1); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1)); VerifyOrQuit(buffer[0] == 0xaa); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 2) == kErrorParse); @@ -154,14 +154,14 @@ void TestTlv(void) SuccessOrQuit(message->Append(extTlv)); SuccessOrQuit(message->Append(0xbb)); - VerifyOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 6, valueOffset, length) != kErrorNone); + VerifyOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 6, offsetRange) != kErrorNone); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1) == kErrorParse); SuccessOrQuit(message->Append(0xcc)); - SuccessOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 6, valueOffset, length) != kErrorNone); - VerifyOrQuit(valueOffset == offset + sizeof(ExtendedTlv)); - VerifyOrQuit(length == 2); + SuccessOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 6, offsetRange) != kErrorNone); + VerifyOrQuit(offsetRange.GetOffset() == offset + sizeof(ExtendedTlv)); + VerifyOrQuit(offsetRange.GetLength() == 2); SuccessOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 2)); VerifyOrQuit(buffer[0] == 0xbb); VerifyOrQuit(buffer[1] == 0xcc); @@ -176,7 +176,7 @@ void TestTlv(void) SuccessOrQuit(message->Append(extTlv)); SuccessOrQuit(message->Append(0x11)); - VerifyOrQuit(Tlv::FindTlvValueOffset(*message, /* aType */ 7, valueOffset, length) != kErrorNone); + VerifyOrQuit(Tlv::FindTlvValueOffsetRange(*message, /* aType */ 7, offsetRange) != kErrorNone); VerifyOrQuit(Tlv::ReadTlvValue(*message, offset, buffer, 1) == kErrorParse); message->Free();