/* * Copyright (c) 2016, 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 the message buffer pool and message buffers. */ #ifndef MESSAGE_HPP_ #define MESSAGE_HPP_ #include "openthread-core-config.h" #include #include #include #include #include "common/as_core_type.hpp" #include "common/clearable.hpp" #include "common/code_utils.hpp" #include "common/const_cast.hpp" #include "common/data.hpp" #include "common/encoding.hpp" #include "common/iterator_utils.hpp" #include "common/linked_list.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "common/pool.hpp" #include "common/timer.hpp" #include "common/type_traits.hpp" #include "mac/mac_types.hpp" #include "thread/child_mask.hpp" #include "thread/link_quality.hpp" /** * Represents an opaque (and empty) type for an OpenThread message buffer. * */ struct otMessage { }; namespace ot { namespace Crypto { class AesCcm; class Sha256; class HmacSha256; } // namespace Crypto /** * @addtogroup core-message * * @brief * This module includes definitions for the message buffer pool and message buffers. * * @{ * */ /** * Frees a given message buffer if not `nullptr`. * * And the ones that follow contain small but common code patterns used in many of the core modules. They * are intentionally defined as macros instead of inline methods/functions to ensure that they are fully inlined. * Note that an `inline` method/function is not necessarily always inlined by the toolchain and not inlining such * small implementations can add a rather large code-size overhead. * * @param[in] aMessage A pointer to a `Message` to free (can be `nullptr`). * */ #define FreeMessage(aMessage) \ do \ { \ if ((aMessage) != nullptr) \ { \ (aMessage)->Free(); \ } \ } while (false) /** * Frees a given message buffer if a given `Error` indicates an error. * * The parameter @p aMessage can be `nullptr` in which case this macro does nothing. * * @param[in] aMessage A pointer to a `Message` to free (can be `nullptr`). * @param[in] aError The `Error` to check. * */ #define FreeMessageOnError(aMessage, aError) \ do \ { \ if (((aError) != kErrorNone) && ((aMessage) != nullptr)) \ { \ (aMessage)->Free(); \ } \ } while (false) /** * Frees a given message buffer if a given `Error` indicates an error and sets the `aMessage` to `nullptr`. * * @param[in] aMessage A pointer to a `Message` to free (can be `nullptr`). * @param[in] aError The `Error` to check. * */ #define FreeAndNullMessageOnError(aMessage, aError) \ do \ { \ if (((aError) != kErrorNone) && ((aMessage) != nullptr)) \ { \ (aMessage)->Free(); \ (aMessage) = nullptr; \ } \ } while (false) constexpr uint16_t kNumBuffers = OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS; constexpr uint16_t kBufferSize = OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE; class Message; class MessagePool; class MessageQueue; class PriorityQueue; class ThreadLinkInfo; /** * Represents a Message buffer. * */ class Buffer : public otMessageBuffer, public LinkedListEntry { friend class Message; public: /** * Returns a pointer to the next message buffer. * * @returns A pointer to the next message buffer. * */ Buffer *GetNextBuffer(void) { return GetNext(); } /** * Returns a pointer to the next message buffer. * * @returns A pointer to the next message buffer. * */ const Buffer *GetNextBuffer(void) const { return GetNext(); } /** * Sets the pointer to the next message buffer. * * @param[in] aNext A pointer to the next buffer. * */ void SetNextBuffer(Buffer *aNext) { SetNext(aNext); } protected: struct Metadata { Message *mNext; // Next message in a doubly linked list. Message *mPrev; // Previous message in a doubly linked list. MessagePool *mMessagePool; // Message pool for this message. void *mQueue; // The queue where message is queued (if any). Queue type from `mInPriorityQ`. uint32_t mDatagramTag; // The datagram tag used for 6LoWPAN frags or IPv6fragmentation. TimeMilli mTimestamp; // The message timestamp. uint16_t mReserved; // Number of reserved bytes (for header). uint16_t mLength; // Current message length (number of bytes). uint16_t mOffset; // A byte offset within the message. uint16_t mMeshDest; // Used for unicast non-link-local messages. uint16_t mPanId; // PAN ID (used for MLE Discover Request and Response). uint8_t mChannel; // The message channel (used for MLE Announce). RssAverager mRssAverager; // The averager maintaining the received signal strength (RSS) average. #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE LqiAverager mLqiAverager; // The averager maintaining the Link quality indicator (LQI) average. #endif #if OPENTHREAD_FTD ChildMask mChildMask; // ChildMask to indicate which sleepy children need to receive this. #endif uint8_t mType : 3; // The message type. uint8_t mSubType : 4; // The message sub type. bool mDirectTx : 1; // Whether a direct transmission is required. bool mLinkSecurity : 1; // Whether link security is enabled. uint8_t mPriority : 2; // The message priority level (higher value is higher priority). bool mInPriorityQ : 1; // Whether the message is queued in normal or priority queue. bool mTxSuccess : 1; // Whether the direct tx of the message was successful. bool mDoNotEvict : 1; // Whether this message may be evicted. bool mMulticastLoop : 1; // Whether this multicast message may be looped back. bool mResolvingAddress : 1; // Whether the message is pending an address query resolution. #if OPENTHREAD_CONFIG_MULTI_RADIO uint8_t mRadioType : 2; // The radio link type the message was received on, or should be sent on. bool mIsRadioTypeSet : 1; // Whether the radio type is set. static_assert(Mac::kNumRadioTypes <= (1 << 2), "mRadioType bitfield cannot store all radio type values"); #endif #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE bool mTimeSync : 1; // Whether the message is also used for time sync purpose. int64_t mNetworkTimeOffset; // The time offset to the Thread network time, in microseconds. uint8_t mTimeSyncSeq; // The time sync sequence. #endif }; static_assert(kBufferSize > sizeof(Metadata) + sizeof(otMessageBuffer), "Metadata does not fit in a single buffer"); static constexpr uint16_t kBufferDataSize = kBufferSize - sizeof(otMessageBuffer); static constexpr uint16_t kHeadBufferDataSize = kBufferDataSize - sizeof(Metadata); Metadata &GetMetadata(void) { return mBuffer.mHead.mMetadata; } const Metadata &GetMetadata(void) const { return mBuffer.mHead.mMetadata; } uint8_t *GetFirstData(void) { return mBuffer.mHead.mData; } const uint8_t *GetFirstData(void) const { return mBuffer.mHead.mData; } uint8_t *GetData(void) { return mBuffer.mData; } const uint8_t *GetData(void) const { return mBuffer.mData; } private: union { struct { Metadata mMetadata; uint8_t mData[kHeadBufferDataSize]; } mHead; uint8_t mData[kBufferDataSize]; } mBuffer; }; static_assert(sizeof(Buffer) >= kBufferSize, "Buffer size is not valid. Increase OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE."); /** * Represents a message. * */ class Message : public otMessage, public Buffer, public GetProvider { friend class Checksum; friend class Crypto::HmacSha256; friend class Crypto::Sha256; friend class Crypto::AesCcm; friend class MessagePool; friend class MessageQueue; friend class PriorityQueue; public: /** * Represents the message type. * */ enum Type : uint8_t { kTypeIp6 = 0, ///< A full uncompressed IPv6 packet kType6lowpan = 1, ///< A 6lowpan frame kTypeSupervision = 2, ///< A child supervision frame. kTypeMacEmptyData = 3, ///< An empty MAC data frame. kTypeIp4 = 4, ///< A full uncompressed IPv4 packet, for NAT64. kTypeOther = 5, ///< Other (data) message. }; /** * Represents the message sub-type. * */ enum SubType : uint8_t { kSubTypeNone = 0, ///< None kSubTypeMleAnnounce = 1, ///< MLE Announce kSubTypeMleDiscoverRequest = 2, ///< MLE Discover Request kSubTypeMleDiscoverResponse = 3, ///< MLE Discover Response kSubTypeJoinerEntrust = 4, ///< Joiner Entrust kSubTypeMplRetransmission = 5, ///< MPL next retransmission message kSubTypeMleGeneral = 6, ///< General MLE kSubTypeJoinerFinalizeResponse = 7, ///< Joiner Finalize Response kSubTypeMleChildUpdateRequest = 8, ///< MLE Child Update Request kSubTypeMleDataResponse = 9, ///< MLE Data Response kSubTypeMleChildIdRequest = 10, ///< MLE Child ID Request kSubTypeMleDataRequest = 11, ///< MLE Data Request }; enum Priority : uint8_t { kPriorityLow = OT_MESSAGE_PRIORITY_LOW, ///< Low priority level. kPriorityNormal = OT_MESSAGE_PRIORITY_NORMAL, ///< Normal priority level. kPriorityHigh = OT_MESSAGE_PRIORITY_HIGH, ///< High priority level. kPriorityNet = OT_MESSAGE_PRIORITY_HIGH + 1, ///< Network Control priority level. }; static constexpr uint8_t kNumPriorities = 4; ///< Number of priority levels. /** * Represents the link security mode (used by `Settings` constructor). * */ enum LinkSecurityMode : bool { kNoLinkSecurity = false, ///< Link security disabled (no link security). kWithLinkSecurity = true, ///< Link security enabled. }; /** * Represents the message ownership model when a `Message` instance is passed to a method/function. * */ enum Ownership : uint8_t { /** * This value indicates that the method/function receiving a `Message` instance should take custody of the * message (e.g., the method should `Free()` the message if no longer needed). * */ kTakeCustody, /** * This value indicates that the method/function receiving a `Message` instance does not own the message (e.g., * it should not `Free()` or `Enqueue()` it in a queue). The receiving method/function should create a * copy/clone of the message to keep (if/when needed). * */ kCopyToUse, }; /** * Represents settings used for creating a new message. * */ class Settings : public otMessageSettings { public: /** * Initializes the `Settings` object. * * @param[in] aSecurityMode A link security mode. * @param[in] aPriority A message priority. * */ Settings(LinkSecurityMode aSecurityMode, Priority aPriority); /** * Initializes the `Settings` with a given message priority and link security enabled. * * @param[in] aPriority A message priority. * */ explicit Settings(Priority aPriority) : Settings(kWithLinkSecurity, aPriority) { } /** * Gets the message priority. * * @returns The message priority. * */ Priority GetPriority(void) const { return static_cast(mPriority); } /** * Indicates whether the link security should be enabled. * * @returns TRUE if link security should be enabled, FALSE otherwise. * */ bool IsLinkSecurityEnabled(void) const { return mLinkSecurityEnabled; } /** * Converts a pointer to an `otMessageSettings` to a `Settings`. * * @param[in] aSettings A pointer to `otMessageSettings` to convert from. * If it is `nullptr`, then the default settings `GetDefault()` will be used. * * @returns A reference to the converted `Settings` or the default if @p aSettings is `nullptr`. * */ static const Settings &From(const otMessageSettings *aSettings); /** * Returns the default settings with link security enabled and `kPriorityNormal` priority. * * @returns A reference to the default settings (link security enable and `kPriorityNormal` priority). * */ static const Settings &GetDefault(void) { return static_cast(kDefault); } private: static const otMessageSettings kDefault; }; /** * Returns a reference to the OpenThread Instance which owns the `Message`. * * @returns A reference to the `Instance`. * */ Instance &GetInstance(void) const; /** * Frees this message buffer. * */ void Free(void); /** * Returns a pointer to the next message. * * @returns A pointer to the next message in the list or `nullptr` if at the end of the list. * */ Message *GetNext(void) const; /** * Returns the number of bytes in the message. * * @returns The number of bytes in the message. * */ uint16_t GetLength(void) const { return GetMetadata().mLength; } /** * Sets the number of bytes in the message. * * @param[in] aLength Requested number of bytes in the message. * * @retval kErrorNone Successfully set the length of the message. * @retval kErrorNoBufs Failed to grow the size of the message because insufficient buffers were available. * */ Error SetLength(uint16_t aLength); /** * Returns the number of buffers in the message. * */ uint8_t GetBufferCount(void) const; /** * Returns the byte offset within the message. * * @returns A byte offset within the message. * */ uint16_t GetOffset(void) const { return GetMetadata().mOffset; } /** * Moves the byte offset within the message. * * @param[in] aDelta The number of bytes to move the current offset, which may be positive or negative. * */ void MoveOffset(int aDelta); /** * Sets the byte offset within the message. * * @param[in] aOffset The byte offset within the message. * */ void SetOffset(uint16_t aOffset); /** * Returns the type of the message. * * @returns The type of the message. * */ Type GetType(void) const { return static_cast(GetMetadata().mType); } /** * Sets the message type. * * @param[in] aType The message type. * */ void SetType(Type aType) { GetMetadata().mType = aType; } /** * Returns the sub type of the message. * * @returns The sub type of the message. * */ SubType GetSubType(void) const { return static_cast(GetMetadata().mSubType); } /** * Sets the message sub type. * * @param[in] aSubType The message sub type. * */ void SetSubType(SubType aSubType) { GetMetadata().mSubType = aSubType; } /** * Returns whether or not the message is of MLE subtype. * * @retval TRUE If message is of MLE subtype. * @retval FALSE If message is not of MLE subtype. * */ bool IsSubTypeMle(void) const; /** * Checks whether this multicast message may be looped back. * * @retval TRUE If message may be looped back. * @retval FALSE If message must not be looped back. * */ bool GetMulticastLoop(void) const { return GetMetadata().mMulticastLoop; } /** * Sets whether multicast may be looped back. * * @param[in] aMulticastLoop Whether allow looping back multicast. * */ void SetMulticastLoop(bool aMulticastLoop) { GetMetadata().mMulticastLoop = aMulticastLoop; } /** * Returns the message priority level. * * @returns The priority level associated with this message. * */ Priority GetPriority(void) const { return static_cast(GetMetadata().mPriority); } /** * Sets the messages priority. * If the message is already queued in a priority queue, changing the priority ensures to * update the message in the associated queue. * * @param[in] aPriority The message priority level. * * @retval kErrorNone Successfully set the priority for the message. * @retval kErrorInvalidArgs Priority level is not invalid. * */ Error SetPriority(Priority aPriority); /** * Convert a `Priority` to a string. * * @param[in] aPriority The priority level. * * @returns A string representation of @p aPriority. * */ static const char *PriorityToString(Priority aPriority); /** * Prepends bytes to the front of the message. * * On success, this method grows the message by @p aLength bytes. * * @param[in] aBuf A pointer to a data buffer (can be `nullptr` to grow message without writing bytes). * @param[in] aLength The number of bytes to prepend. * * @retval kErrorNone Successfully prepended the bytes. * @retval kErrorNoBufs Not enough reserved bytes in the message. * */ Error PrependBytes(const void *aBuf, uint16_t aLength); /** * Prepends an object to the front of the message. * * On success, this method grows the message by the size of the object. * * @tparam ObjectType The object type to prepend to the message. * * @param[in] aObject A reference to the object to prepend to the message. * * @retval kErrorNone Successfully prepended the object. * @retval kErrorNoBufs Not enough reserved bytes in the message. * */ template Error Prepend(const ObjectType &aObject) { static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); return PrependBytes(&aObject, sizeof(ObjectType)); } /** * Removes header bytes from the message at start of message. * * The caller MUST ensure that message contains the bytes to be removed, i.e. `aOffset` is smaller than the message * length. * * @param[in] aLength Number of header bytes to remove from start of `Message`. * */ void RemoveHeader(uint16_t aLength); /** * Removes header bytes from the message at a given offset. * * Shrinks the message. The existing header bytes before @p aOffset are copied forward and replace the * removed bytes. * * The caller MUST ensure that message contains the bytes to be removed, i.e. `aOffset + aLength` is smaller than * the message length. * * @param[in] aOffset The offset to start removing. * @param[in] aLength Number of header bytes to remove. * */ void RemoveHeader(uint16_t aOffset, uint16_t aLength); /** * Grows the message to make space for new header bytes at a given offset. * * Grows the message header (similar to `PrependBytes()`). The existing header bytes from start to * `aOffset + aLength` are then copied backward to make room for the new header bytes. Note that this method does * not change the bytes from @p aOffset up @p aLength (the new inserted header range). Caller can write to this * range to update the bytes after successful return from this method. * * @param[in] aOffset The offset at which to insert the header bytes * @param[in] aLength Number of header bytes to insert. * * @retval kErrorNone Successfully grown the message and copied the existing header bytes. * @retval kErrorNoBufs Insufficient available buffers to grow the message. * */ Error InsertHeader(uint16_t aOffset, uint16_t aLength); /** * Appends bytes to the end of the message. * * On success, this method grows the message by @p aLength bytes. * * @param[in] aBuf A pointer to a data buffer (MUST not be `nullptr`). * @param[in] aLength The number of bytes to append. * * @retval kErrorNone Successfully appended the bytes. * @retval kErrorNoBufs Insufficient available buffers to grow the message. * */ Error AppendBytes(const void *aBuf, uint16_t aLength); /** * Appends bytes read from another or potentially the same message to the end of the current message. * * On success, this method grows the message by @p aLength bytes. * * @param[in] aMessage The message to read the bytes from (it can be the same as the current message). * @param[in] aOffset The offset in @p aMessage to start reading the bytes from. * @param[in] aLength The number of bytes to read from @p aMessage and append. * * @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 aLength bytes from @p aOffset. * */ Error AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength); /** * Appends an object to the end of the message. * * On success, this method grows the message by the size of the appended object * * @tparam ObjectType The object type to append to the message. * * @param[in] aObject A reference to the object to append to the message. * * @retval kErrorNone Successfully appended the object. * @retval kErrorNoBufs Insufficient available buffers to grow the message. * */ template Error Append(const ObjectType &aObject) { static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); return AppendBytes(&aObject, sizeof(ObjectType)); } /** * 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 Error AppendData(const Data &aData) { return AppendBytes(aData.GetBytes(), aData.GetLength()); } /** * Reads bytes from the message. * * @param[in] aOffset Byte offset within the message to begin reading. * @param[out] aBuf A pointer to a data buffer to copy the read bytes into. * @param[in] aLength Number of bytes to read. * * @returns The number of bytes read. * */ uint16_t ReadBytes(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 than the requested read length, the available bytes will be * read and copied into @p aBuf. In this case `kErrorParse` will be returned. * * @param[in] aOffset Byte offset within the message to begin reading. * @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 @p aLength bytes were successfully read from message. * @retval kErrorParse Not enough bytes remaining in message to read the entire object. * */ Error Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const; /** * Reads an object from the message. * * If there are fewer bytes available in the message 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] aOffset Byte offset within the message to begin reading. * @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(uint16_t aOffset, ObjectType &aObject) const { static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); return Read(aOffset, &aObject, sizeof(ObjectType)); } /** * Compares the bytes in the message at a given offset with a given byte array. * * If there are fewer bytes available in the message than the requested @p aLength, the comparison is treated as * failure (returns FALSE). * * @param[in] aOffset Byte offset within the message to read from for the comparison. * @param[in] aBuf A pointer to a data buffer to compare with the bytes from message. * @param[in] aLength Number of bytes in @p aBuf. * @param[in] aMatcher A `ByteMatcher` function pointer to match the bytes. If `nullptr` then bytes are directly * compared. * * @returns TRUE if there are enough bytes available in @p aMessage and they match the bytes from @p aBuf, * FALSE otherwise. * */ bool CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength, ByteMatcher aMatcher = nullptr) const; /** * Compares the bytes in the message at a given offset with bytes read from another message. * * If either message has fewer bytes available than the requested @p aLength, the comparison is treated as failure * (returns FALSE). * * @param[in] aOffset Byte offset within the message to read from for the comparison. * @param[in] aOtherMessage The other message to compare with. * @param[in] aOtherOffset Byte offset within @p aOtherMessage to read from for the comparison. * @param[in] aLength Number of bytes to compare. * @param[in] aMatcher A `ByteMatcher` function pointer to match the bytes. If `nullptr` then bytes are * directly compared. * * @returns TRUE if there are enough bytes available in both messages and they all match. FALSE otherwise. * */ bool CompareBytes(uint16_t aOffset, const Message &aOtherMessage, uint16_t aOtherOffset, uint16_t aLength, ByteMatcher aMatcher = nullptr) const; /** * Compares the bytes in the message at a given offset with an object. * * The bytes in the message are compared with the bytes in @p aObject. If there are fewer bytes available in the * message than the requested object size, it is treated as failed comparison (returns FALSE). * * @tparam ObjectType The object type to compare with the bytes in message. * * @param[in] aOffset Byte offset within the message to read from for the comparison. * @param[in] aObject A reference to the object to compare with the message bytes. * * @returns TRUE if there are enough bytes available in @p aMessage and they match the bytes in @p aObject, * FALSE otherwise. * */ template bool Compare(uint16_t aOffset, const ObjectType &aObject) const { static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); return CompareBytes(aOffset, &aObject, sizeof(ObjectType)); } /** * Writes bytes to the message. * * Will not resize the message. The given data to write (with @p aLength bytes) MUST fit within the * existing message buffer (from the given offset @p aOffset up to the message's length). * * @param[in] aOffset Byte offset within the message to begin writing. * @param[in] aBuf A pointer to a data buffer. * @param[in] aLength Number of bytes to write. * */ void WriteBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength); /** * Writes bytes read from another or potentially the same message to the message at a given offset. * * Will not resize the message. The bytes to write (with @p aLength) MUST fit within the existing * message buffer (from the given @p aWriteOffset up to the message's length). * * Can be used to copy bytes within the same message in either direction, i.e., copy forward where * `aWriteOffset > aReadOffset` or copy backward where `aWriteOffset < aReadOffset`. * * @param[in] aWriteOffset Byte offset within this message to begin writing. * @param[in] aMessage The message to read the bytes from. * @param[in] aReadOffset The offset in @p aMessage to start reading the bytes from. * @param[in] aLength The number of bytes to read from @p aMessage and write. * */ void WriteBytesFromMessage(uint16_t aWriteOffset, const Message &aMessage, uint16_t aReadOffset, uint16_t aLength); /** * Writes an object to the message. * * Will not resize the message. The entire given object (all its bytes) MUST fit within the existing * message buffer (from the given offset @p aOffset up to the message's length). * * @tparam ObjectType The object type to write to the message. * * @param[in] aOffset Byte offset within the message to begin writing. * @param[in] aObject A reference to the object to write. * */ template void Write(uint16_t aOffset, const ObjectType &aObject) { static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); WriteBytes(aOffset, &aObject, sizeof(ObjectType)); } /** * Writes bytes from a given `Data` instance to the message. * * 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 void WriteData(uint16_t aOffset, const Data &aData) { WriteBytes(aOffset, aData.GetBytes(), aData.GetLength()); } /** * Creates a copy of the message. * * It allocates the new message from the same message pool as the original one and copies @p aLength octets * of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the * cloned message are also copied from the original one. * * @param[in] aLength Number of payload bytes to copy. * * @returns A pointer to the message or nullptr if insufficient message buffers are available. * */ Message *Clone(uint16_t aLength) const; /** * Creates a copy of the message. * * It allocates the new message from the same message pool as the original one and copies the entire payload. The * `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the cloned message are also * copied from the original one. * * @returns A pointer to the message or `nullptr` if insufficient message buffers are available. * */ Message *Clone(void) const { return Clone(GetLength()); } /** * Returns the datagram tag used for 6LoWPAN fragmentation or the identification used for IPv6 * fragmentation. * * @returns The 6LoWPAN datagram tag or the IPv6 fragment identification. * */ uint32_t GetDatagramTag(void) const { return GetMetadata().mDatagramTag; } /** * Sets the datagram tag used for 6LoWPAN fragmentation. * * @param[in] aTag The 6LoWPAN datagram tag. * */ void SetDatagramTag(uint32_t aTag) { GetMetadata().mDatagramTag = aTag; } #if OPENTHREAD_FTD /** * Returns whether or not the message forwarding is scheduled for the child. * * @param[in] aChildIndex The index into the child table. * * @retval TRUE If the message is scheduled to be forwarded to the child. * @retval FALSE If the message is not scheduled to be forwarded to the child. * */ bool GetChildMask(uint16_t aChildIndex) const; /** * Unschedules forwarding of the message to the child. * * @param[in] aChildIndex The index into the child table. * */ void ClearChildMask(uint16_t aChildIndex); /** * Schedules forwarding of the message to the child. * * @param[in] aChildIndex The index into the child table. * */ void SetChildMask(uint16_t aChildIndex); /** * Returns whether or not the message forwarding is scheduled for at least one child. * * @retval TRUE If message forwarding is scheduled for at least one child. * @retval FALSE If message forwarding is not scheduled for any child. * */ bool IsChildPending(void) const; #endif // OPENTHREAD_FTD /** * Returns the RLOC16 of the mesh destination. * * @note Only use this for non-link-local unicast messages. * * @returns The IEEE 802.15.4 Destination PAN ID. * */ uint16_t GetMeshDest(void) const { return GetMetadata().mMeshDest; } /** * Sets the RLOC16 of the mesh destination. * * @note Only use this when sending non-link-local unicast messages. * * @param[in] aMeshDest The IEEE 802.15.4 Destination PAN ID. * */ void SetMeshDest(uint16_t aMeshDest) { GetMetadata().mMeshDest = aMeshDest; } /** * Returns the IEEE 802.15.4 Destination PAN ID. * * @note Only use this when sending MLE Discover Request or Response messages. * * @returns The IEEE 802.15.4 Destination PAN ID. * */ uint16_t GetPanId(void) const { return GetMetadata().mPanId; } /** * Sets the IEEE 802.15.4 Destination PAN ID. * * @note Only use this when sending MLE Discover Request or Response messages. * * @param[in] aPanId The IEEE 802.15.4 Destination PAN ID. * */ void SetPanId(uint16_t aPanId) { GetMetadata().mPanId = aPanId; } /** * Returns the IEEE 802.15.4 Channel to use for transmission. * * @note Only use this when sending MLE Announce messages. * * @returns The IEEE 802.15.4 Channel to use for transmission. * */ uint8_t GetChannel(void) const { return GetMetadata().mChannel; } /** * Sets the IEEE 802.15.4 Channel to use for transmission. * * @note Only use this when sending MLE Announce messages. * * @param[in] aChannel The IEEE 802.15.4 Channel to use for transmission. * */ void SetChannel(uint8_t aChannel) { GetMetadata().mChannel = aChannel; } /** * Returns the message timestamp. * * @returns The message timestamp. * */ TimeMilli GetTimestamp(void) const { return GetMetadata().mTimestamp; } /** * Sets the message timestamp to a given time. * * @param[in] aTimestamp The timestamp value. * */ void SetTimestamp(TimeMilli aTimestamp) { GetMetadata().mTimestamp = aTimestamp; } /** * Sets the message timestamp to the current time. * */ void SetTimestampToNow(void) { SetTimestamp(TimerMilli::GetNow()); } /** * Returns whether or not message forwarding is scheduled for direct transmission. * * @retval TRUE If message forwarding is scheduled for direct transmission. * @retval FALSE If message forwarding is not scheduled for direct transmission. * */ bool IsDirectTransmission(void) const { return GetMetadata().mDirectTx; } /** * Unschedules forwarding using direct transmission. * */ void ClearDirectTransmission(void) { GetMetadata().mDirectTx = false; } /** * Schedules forwarding using direct transmission. * */ void SetDirectTransmission(void) { GetMetadata().mDirectTx = true; } /** * Indicates whether the direct transmission of message was successful. * * @retval TRUE If direct transmission of message was successful (all fragments were delivered and acked). * @retval FALSE If direct transmission of message failed (at least one fragment failed). * */ bool GetTxSuccess(void) const { return GetMetadata().mTxSuccess; } /** * Sets whether the direct transmission of message was successful. * * @param[in] aTxSuccess TRUE if the direct transmission is successful, FALSE otherwise (i.e., at least one * fragment transmission failed). * */ void SetTxSuccess(bool aTxSuccess) { GetMetadata().mTxSuccess = aTxSuccess; } /** * Indicates whether the message may be evicted. * * @retval TRUE If the message must not be evicted. * @retval FALSE If the message may be evicted. * */ bool GetDoNotEvict(void) const { return GetMetadata().mDoNotEvict; } /** * Sets whether the message may be evicted. * * @param[in] aDoNotEvict TRUE if the message may not be evicted, FALSE otherwise. * */ void SetDoNotEvict(bool aDoNotEvict) { GetMetadata().mDoNotEvict = aDoNotEvict; } /** * Indicates whether the message is waiting for an address query resolution. * * @retval TRUE If the message is waiting for address query resolution. * @retval FALSE If the message is not waiting for address query resolution. * */ bool IsResolvingAddress(void) const { return GetMetadata().mResolvingAddress; } /** * Sets whether the message is waiting for an address query resolution. * * @param[in] aResolvingAddress TRUE if message is waiting for address resolution, FALSE otherwise. * */ void SetResolvingAddress(bool aResolvingAddress) { GetMetadata().mResolvingAddress = aResolvingAddress; } /** * Indicates whether or not link security is enabled for the message. * * @retval TRUE If link security is enabled. * @retval FALSE If link security is not enabled. * */ bool IsLinkSecurityEnabled(void) const { return GetMetadata().mLinkSecurity; } /** * Sets whether or not link security is enabled for the message. * * @param[in] aEnabled TRUE if link security is enabled, FALSE otherwise. * */ void SetLinkSecurityEnabled(bool aEnabled) { GetMetadata().mLinkSecurity = aEnabled; } /** * Updates the average RSS (Received Signal Strength) associated with the message by adding the given * RSS value to the average. Note that a message can be composed of multiple 802.15.4 data frame fragments each * received with a different signal strength. * * @param[in] aRss A new RSS value (in dBm) to be added to average. * */ void AddRss(int8_t aRss) { IgnoreError(GetMetadata().mRssAverager.Add(aRss)); } /** * Returns the average RSS (Received Signal Strength) associated with the message. * * @returns The current average RSS value (in dBm) or `Radio::kInvalidRssi` if no average is available. * */ int8_t GetAverageRss(void) const { return GetMetadata().mRssAverager.GetAverage(); } /** * Returns a const reference to RssAverager of the message. * * @returns A const reference to the RssAverager of the message. * */ const RssAverager &GetRssAverager(void) const { return GetMetadata().mRssAverager; } #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE /** * Updates the average LQI (Link Quality Indicator) associated with the message. * * The given LQI value would be added to the average. Note that a message can be composed of multiple 802.15.4 * frame fragments each received with a different signal strength. * * @param[in] aLqi A new LQI value (has no unit) to be added to average. * */ void AddLqi(uint8_t aLqi) { GetMetadata().mLqiAverager.Add(aLqi); } /** * Returns the average LQI (Link Quality Indicator) associated with the message. * * @returns The current average LQI value (in dBm) or OT_RADIO_LQI_NONE if no average is available. * */ uint8_t GetAverageLqi(void) const { return GetMetadata().mLqiAverager.GetAverage(); } /** * Returns the count of frames counted so far. * * @returns The count of frames that have been counted. * */ uint8_t GetPsduCount(void) const { return GetMetadata().mLqiAverager.GetCount(); } #endif /** * Sets the message's link info properties (PAN ID, link security, RSS) from a given `ThreadLinkInfo`. * * @param[in] aLinkInfo The `ThreadLinkInfo` instance from which to set message's related properties. * */ void SetLinkInfo(const ThreadLinkInfo &aLinkInfo); /** * Returns a pointer to the message queue (if any) where this message is queued. * * @returns A pointer to the message queue or `nullptr` if not in any message queue. * */ MessageQueue *GetMessageQueue(void) const { return !GetMetadata().mInPriorityQ ? static_cast(GetMetadata().mQueue) : nullptr; } /** * Returns a pointer to the priority message queue (if any) where this message is queued. * * @returns A pointer to the priority queue or `nullptr` if not in any priority queue. * */ PriorityQueue *GetPriorityQueue(void) const { return GetMetadata().mInPriorityQ ? static_cast(GetMetadata().mQueue) : nullptr; } /** * Indicates whether or not the message is also used for time sync purpose. * * When OPENTHREAD_CONFIG_TIME_SYNC_ENABLE is 0, this method always return false. * * @retval TRUE If the message is also used for time sync purpose. * @retval FALSE If the message is not used for time sync purpose. * */ bool IsTimeSync(void) const; #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE /** * Sets whether or not the message is also used for time sync purpose. * * @param[in] aEnabled TRUE if the message is also used for time sync purpose, FALSE otherwise. * */ void SetTimeSync(bool aEnabled) { GetMetadata().mTimeSync = aEnabled; } /** * Sets the offset to network time. * * @param[in] aNetworkTimeOffset The offset to network time. * */ void SetNetworkTimeOffset(int64_t aNetworkTimeOffset) { GetMetadata().mNetworkTimeOffset = aNetworkTimeOffset; } /** * Gets the offset to network time. * * @returns The offset to network time. * */ int64_t GetNetworkTimeOffset(void) const { return GetMetadata().mNetworkTimeOffset; } /** * Sets the time sync sequence. * * @param[in] aTimeSyncSeq The time sync sequence. * */ void SetTimeSyncSeq(uint8_t aTimeSyncSeq) { GetMetadata().mTimeSyncSeq = aTimeSyncSeq; } /** * Gets the time sync sequence. * * @returns The time sync sequence. * */ uint8_t GetTimeSyncSeq(void) const { return GetMetadata().mTimeSyncSeq; } #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE #if OPENTHREAD_CONFIG_MULTI_RADIO /** * Indicates whether the radio type is set. * * @retval TRUE If the radio type is set. * @retval FALSE If the radio type is not set. * */ bool IsRadioTypeSet(void) const { return GetMetadata().mIsRadioTypeSet; } /** * Gets the radio link type the message was received on, or should be sent on. * * Should be used only when `IsRadioTypeSet()` returns `true`. * * @returns The radio link type of the message. * */ Mac::RadioType GetRadioType(void) const { return static_cast(GetMetadata().mRadioType); } /** * Sets the radio link type the message was received on, or should be sent on. * * @param[in] aRadioType A radio link type of the message. * */ void SetRadioType(Mac::RadioType aRadioType) { GetMetadata().mIsRadioTypeSet = true; GetMetadata().mRadioType = aRadioType; } /** * Clears any previously set radio type on the message. * * After calling this method, `IsRadioTypeSet()` returns false until radio type is set (`SetRadioType()`). * */ void ClearRadioType(void) { GetMetadata().mIsRadioTypeSet = false; } #endif // #if OPENTHREAD_CONFIG_MULTI_RADIO protected: class ConstIterator : public ItemPtrIterator { friend class ItemPtrIterator; public: ConstIterator(void) = default; explicit ConstIterator(const Message *aMessage) : ItemPtrIterator(aMessage) { } private: void Advance(void) { mItem = mItem->GetNext(); } }; class Iterator : public ItemPtrIterator { friend class ItemPtrIterator; public: Iterator(void) : mNext(nullptr) { } explicit Iterator(Message *aMessage) : ItemPtrIterator(aMessage) , mNext(NextMessage(aMessage)) { } private: void Advance(void); static Message *NextMessage(Message *aMessage) { return (aMessage != nullptr) ? aMessage->GetNext() : nullptr; } Message *mNext; }; uint16_t GetReserved(void) const { return GetMetadata().mReserved; } void SetReserved(uint16_t aReservedHeader) { GetMetadata().mReserved = aReservedHeader; } private: class Chunk : public Data { public: const Buffer *GetBuffer(void) const { return mBuffer; } void SetBuffer(const Buffer *aBuffer) { mBuffer = aBuffer; } private: const Buffer *mBuffer; // Buffer containing the chunk }; class MutableChunk : public Chunk { public: uint8_t *GetBytes(void) { return AsNonConst(Chunk::GetBytes()); } }; void GetFirstChunk(uint16_t aOffset, uint16_t &aLength, Chunk &aChunk) const; void GetNextChunk(uint16_t &aLength, Chunk &aChunk) const; void GetFirstChunk(uint16_t aOffset, uint16_t &aLength, MutableChunk &aChunk) { AsConst(this)->GetFirstChunk(aOffset, aLength, static_cast(aChunk)); } void GetNextChunk(uint16_t &aLength, MutableChunk &aChunk) { AsConst(this)->GetNextChunk(aLength, static_cast(aChunk)); } MessagePool *GetMessagePool(void) const { return GetMetadata().mMessagePool; } void SetMessagePool(MessagePool *aMessagePool) { GetMetadata().mMessagePool = aMessagePool; } bool IsInAQueue(void) const { return (GetMetadata().mQueue != nullptr); } void SetMessageQueue(MessageQueue *aMessageQueue); void SetPriorityQueue(PriorityQueue *aPriorityQueue); Message *&Next(void) { return GetMetadata().mNext; } Message *const &Next(void) const { return GetMetadata().mNext; } Message *&Prev(void) { return GetMetadata().mPrev; } static Message *NextOf(Message *aMessage) { return (aMessage != nullptr) ? aMessage->Next() : nullptr; } static const Message *NextOf(const Message *aMessage) { return (aMessage != nullptr) ? aMessage->Next() : nullptr; } Error ResizeMessage(uint16_t aLength); }; /** * Implements a message queue. * */ class MessageQueue : public otMessageQueue { friend class Message; friend class PriorityQueue; public: typedef otMessageQueueInfo Info; ///< This struct represents info (number of messages/buffers) about a queue. /** * Represents a position (head or tail) in the queue. This is used to specify where a new message * should be added in the queue. * */ enum QueuePosition : uint8_t { kQueuePositionHead, ///< Indicates the head (front) of the list. kQueuePositionTail, ///< Indicates the tail (end) of the list. }; /** * Initializes the message queue. * */ MessageQueue(void) { SetTail(nullptr); } /** * Returns a pointer to the first message. * * @returns A pointer to the first message. * */ Message *GetHead(void) { return Message::NextOf(GetTail()); } /** * Returns a pointer to the first message. * * @returns A pointer to the first message. * */ const Message *GetHead(void) const { return Message::NextOf(GetTail()); } /** * Adds a message to the end of the list. * * @param[in] aMessage The message to add. * */ void Enqueue(Message &aMessage) { Enqueue(aMessage, kQueuePositionTail); } /** * Adds a message at a given position (head/tail) of the list. * * @param[in] aMessage The message to add. * @param[in] aPosition The position (head or tail) where to add the message. * */ void Enqueue(Message &aMessage, QueuePosition aPosition); /** * Removes a message from the list. * * @param[in] aMessage The message to remove. * */ void Dequeue(Message &aMessage); /** * Removes a message from the queue and frees it. * * @param[in] aMessage The message to remove and free. * */ void DequeueAndFree(Message &aMessage); /** * Removes and frees all messages from the queue. * */ void DequeueAndFreeAll(void); /** * Gets the information about number of messages and buffers in the queue. * * Updates `aInfo` and adds number of message/buffers in the message queue to the corresponding member * variable in `aInfo`. The caller needs to make sure `aInfo` is initialized before calling this method (e.g., * clearing `aInfo`). Same `aInfo` can be passed in multiple calls of `GetInfo(aInfo)` on different queues to add * up the number of messages/buffers on different queues. * * @param[out] aInfo A reference to `Info` structure to update.ni * */ void GetInfo(Info &aInfo) const; // The following methods are intended to support range-based `for` // loop iteration over the queue entries and should not be used // directly. The range-based `for` works correctly even if the // current entry is removed from the queue during iteration. Message::Iterator begin(void); Message::Iterator end(void) { return Message::Iterator(); } Message::ConstIterator begin(void) const; Message::ConstIterator end(void) const { return Message::ConstIterator(); } private: Message *GetTail(void) { return static_cast(mData); } const Message *GetTail(void) const { return static_cast(mData); } void SetTail(Message *aMessage) { mData = aMessage; } }; /** * Implements a priority queue. * */ class PriorityQueue : private Clearable { friend class Message; friend class MessageQueue; friend class MessagePool; friend class Clearable; public: typedef otMessageQueueInfo Info; ///< This struct represents info (number of messages/buffers) about a queue. /** * Initializes the priority queue. * */ PriorityQueue(void) { Clear(); } /** * Returns a pointer to the first message. * * @returns A pointer to the first message. * */ Message *GetHead(void) { return AsNonConst(AsConst(this)->GetHead()); } /** * Returns a pointer to the first message. * * @returns A pointer to the first message. * */ const Message *GetHead(void) const; /** * Returns a pointer to the first message for a given priority level. * * @param[in] aPriority Priority level. * * @returns A pointer to the first message with given priority level or `nullptr` if there is no messages with * this priority level. * */ Message *GetHeadForPriority(Message::Priority aPriority) { return AsNonConst(AsConst(this)->GetHeadForPriority(aPriority)); } /** * Returns a pointer to the first message for a given priority level. * * @param[in] aPriority Priority level. * * @returns A pointer to the first message with given priority level or `nullptr` if there is no messages with * this priority level. * */ const Message *GetHeadForPriority(Message::Priority aPriority) const; /** * Adds a message to the queue. * * @param[in] aMessage The message to add. * */ void Enqueue(Message &aMessage); /** * Removes a message from the list. * * @param[in] aMessage The message to remove. * */ void Dequeue(Message &aMessage); /** * Removes a message from the queue and frees it. * * @param[in] aMessage The message to remove and free. * */ void DequeueAndFree(Message &aMessage); /** * Removes and frees all messages from the queue. * */ void DequeueAndFreeAll(void); /** * Returns the tail of the list (last message in the list). * * @returns A pointer to the tail of the list. * */ Message *GetTail(void) { return AsNonConst(AsConst(this)->GetTail()); } /** * Returns the tail of the list (last message in the list). * * @returns A pointer to the tail of the list. * */ const Message *GetTail(void) const; /** * Gets the information about number of messages and buffers in the priority queue. * * Updates `aInfo` array and adds number of message/buffers in the message queue to the corresponding * member variable in `aInfo`. The caller needs to make sure `aInfo` is initialized before calling this method * (e.g., clearing `aInfo`). Same `aInfo` can be passed in multiple calls of `GetInfo(aInfo)` on different queues * to add up the number of messages/buffers on different queues. * * @param[out] aInfo A reference to an `Info` structure to update. * */ void GetInfo(Info &aInfo) const; // The following methods are intended to support range-based `for` // loop iteration over the queue entries and should not be used // directly. The range-based `for` works correctly even if the // current entry is removed from the queue during iteration. Message::Iterator begin(void); Message::Iterator end(void) { return Message::Iterator(); } Message::ConstIterator begin(void) const; Message::ConstIterator end(void) const { return Message::ConstIterator(); } private: uint8_t PrevPriority(uint8_t aPriority) const { return (aPriority == Message::kNumPriorities - 1) ? 0 : (aPriority + 1); } const Message *FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const; Message *FindFirstNonNullTail(Message::Priority aStartPriorityLevel) { return AsNonConst(AsConst(this)->FindFirstNonNullTail(aStartPriorityLevel)); } Message *mTails[Message::kNumPriorities]; // Tail pointers associated with different priority levels. }; /** * Represents a message pool * */ class MessagePool : public InstanceLocator, private NonCopyable { friend class Message; friend class MessageQueue; friend class PriorityQueue; public: /** * Initializes the object. * */ explicit MessagePool(Instance &aInstance); /** * Allocates a new message with specified settings. * * @param[in] aType The message type. * @param[in] aReserveHeader The number of header bytes to reserve. * @param[in] aSettings The message settings. * * @returns A pointer to the message or `nullptr` if no message buffers are available. * */ Message *Allocate(Message::Type aType, uint16_t aReserveHeader, const Message::Settings &aSettings); /** * Allocates a new message of a given type using default settings. * * @param[in] aType The message type. * * @returns A pointer to the message or `nullptr` if no message buffers are available. * */ Message *Allocate(Message::Type aType); /** * Allocates a new message with a given type and reserved length using default settings. * * @param[in] aType The message type. * @param[in] aReserveHeader The number of header bytes to reserve. * * @returns A pointer to the message or `nullptr` if no message buffers are available. * */ Message *Allocate(Message::Type aType, uint16_t aReserveHeader); /** * Is used to free a message and return all message buffers to the buffer pool. * * @param[in] aMessage The message to free. * */ void Free(Message *aMessage); /** * Returns the number of free buffers. * * @returns The number of free buffers, or 0xffff (UINT16_MAX) if number is unknown. * */ uint16_t GetFreeBufferCount(void) const; /** * Returns the total number of buffers. * * @returns The total number of buffers, or 0xffff (UINT16_MAX) if number is unknown. * */ uint16_t GetTotalBufferCount(void) const; /** * Returns the maximum number of buffers in use at the same time since OT stack initialization or * since last call to `ResetMaxUsedBufferCount()`. * * @returns The maximum number of buffers in use at the same time so far (buffer allocation watermark). * */ uint16_t GetMaxUsedBufferCount(void) const { return mMaxAllocated; } /** * Resets the tracked maximum number of buffers in use. * * @sa GetMaxUsedBufferCount * */ void ResetMaxUsedBufferCount(void) { mMaxAllocated = mNumAllocated; } private: Buffer *NewBuffer(Message::Priority aPriority); void FreeBuffers(Buffer *aBuffer); Error ReclaimBuffers(Message::Priority aPriority); #if !OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT && !OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE Pool mBufferPool; #endif uint16_t mNumAllocated; uint16_t mMaxAllocated; }; inline Instance &Message::GetInstance(void) const { return GetMessagePool()->GetInstance(); } /** * @} * */ DefineCoreType(otMessageBuffer, Buffer); DefineCoreType(otMessageSettings, Message::Settings); DefineCoreType(otMessage, Message); DefineCoreType(otMessageQueue, MessageQueue); } // namespace ot #endif // MESSAGE_HPP_