text: /*
   *  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/config.h>
  
  #include "utils/wrap_stdint.h"
  #include "utils/wrap_string.h"
  
  #include <openthread/message.h>
  #include <openthread/platform/messagepool.h>
  
  #include "openthread-core-config.h"
  #include "common/code_utils.hpp"
  #include "mac/mac_frame.hpp"
  
  namespace ot {
  
  /**
   * @addtogroup core-message
   *
   * @brief
   *   This module includes definitions for the message buffer pool and message buffers.
   *
   * @{
   *
   */
  
  enum
  {
      kNumBuffers = OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS,
      kBufferSize = OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE,
  };
  
  class Message;
  class MessagePool;
  class MessageQueue;
  class PriorityQueue;
  
  /**
   * This structure contains metdata about a Message.
   *
   */
  struct MessageInfo
  {
      enum
      {
          kListAll        = 0,             ///< Identifies the all messages list (maintained by the MessagePool).
          kListInterface  = 1,             ///< Identifies the list for per-interface message queue.
          kNumLists       = 2,             ///< Number of lists.
      };
  
      Message         *mNext[kNumLists];   ///< A pointer to the next Message in a doubly linked list.
      Message         *mPrev[kNumLists];   ///< A pointer to the previous Message in a doubly linked list.
      MessagePool     *mMessagePool;       ///< Identifies the message pool for this message.
      union
      {
          MessageQueue    *mMessage;       ///< Identifies the message queue (if any) where this message is queued.
          PriorityQueue   *mPriority;      ///< Identifies the priority queue (if any) where this message is queued.
      } mQueue;                            ///< Identifies the queue (if any) where this message is queued.
  
      uint16_t         mReserved;          ///< Number of header bytes reserved for the message.
      uint16_t         mLength;            ///< Number of bytes within the message.
      uint16_t         mOffset;            ///< A byte offset within the message.
      uint16_t         mDatagramTag;       ///< The datagram tag used for 6LoWPAN fragmentation.
  
      uint8_t          mChildMask[8];      ///< A bit-vector to indicate which sleepy children need to receive this.
      uint8_t          mTimeout;           ///< Seconds remaining before dropping the message.
      int8_t           mInterfaceId;       ///< The interface ID.
      union
      {
          uint16_t     mPanId;             ///< Used for MLE Discover Request and Response messages.
          uint8_t      mChannel;           ///< Used for MLE Announce.
      } mPanIdChannel;                     ///< Used for MLE Discover Request, Response, and Announce messages.
  
      uint8_t          mType : 2;          ///< Identifies the type of message.
      uint8_t          mSubType : 4;       ///< Identifies the message sub type.
      bool             mDirectTx : 1;      ///< Used to indicate whether a direct transmission is required.
      bool             mLinkSecurity : 1;  ///< Indicates whether or not link security is enabled.
      uint8_t          mPriority : 2;      ///< Identifies the message priority level (lower value is higher priority).
      bool             mInPriorityQ : 1;   ///< Indicates whether the message is queued in normal or priority queue.
  };
  
  /**
   * This class represents a Message buffer.
   *
   */
  class Buffer : public ::otMessage
  {
      friend class Message;
  
  public:
      /**
       * This method returns a pointer to the next message buffer.
       *
       * @returns A pointer to the next message buffer.
       *
       */
      class Buffer *GetNextBuffer(void) const { return static_cast<Buffer *>(mNext); }
  
      /**
       * This method sets the pointer to the next message buffer.
       *
       */
      void SetNextBuffer(class Buffer *buf) { mNext = static_cast<otMessage *>(buf); }
  
  private:
      /**
       * This method returns a pointer to the first byte of data in the first message buffer.
       *
       * @returns A pointer to the first data byte.
       *
       */
      uint8_t *GetFirstData(void) { return mBuffer.mHead.mData; }
  
      /**
       * This method returns a pointer to the first byte of data in the first message buffer.
       *
       * @returns A pointer to the first data byte.
       *
       */
      const uint8_t *GetFirstData(void) const { return mBuffer.mHead.mData; }
  
      /**
       * This method returns a pointer to the first data byte of a subsequent message buffer.
       *
       * @returns A pointer to the first data byte.
       *
       */
      uint8_t *GetData(void) { return mBuffer.mData; }
  
      /**
       * This method returns a pointer to the first data byte of a subsequent message buffer.
       *
       * @returns A pointer to the first data byte.
       *
       */
      const uint8_t *GetData(void) const { return mBuffer.mData; }
  
      enum
      {
          kBufferDataSize = kBufferSize - sizeof(struct otMessage),
          kHeadBufferDataSize = kBufferDataSize - sizeof(struct MessageInfo),
      };
  
      union
      {
          struct
          {
              MessageInfo mInfo;
              uint8_t mData[kHeadBufferDataSize];
          } mHead;
          uint8_t mData[kBufferDataSize];
      } mBuffer;
  };
  
  /**
   * This class represents a message.
   *
   */
  class Message: public Buffer
  {
      friend class MessagePool;
      friend class MessageQueue;
      friend class PriorityQueue;
  
  public:
      enum
      {
          kTypeIp6         = 0,   ///< A full uncompressed IPv6 packet
          kType6lowpan     = 1,   ///< A 6lowpan frame
          kTypeMacDataPoll = 2,   ///< A MAC data poll message
          kTypeSupervision = 3,   ///< A child supervision frame.
      };
  
      enum
      {
          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
      };
  
      enum
      {
          kPriorityHigh       = 0,    ///< High priority level.
          kPriorityMedium     = 1,    ///< Medium priority level.
          kPriorityLow        = 2,    ///< Low priority level.
          kPriorityVeryLow    = 3,    ///< Very low priority level.
  
          kNumPriorities      = 4,    ///< Number of priority levels.
      };
  
      /**
       * This method frees this message buffer.
       *
       */
      otError Free(void);
  
      /**
       * This method returns a pointer to the next message in the same interface list.
       *
       * @returns A pointer to the next message in the same interface list or NULL if at the end of the list.
       *
       */
      Message *GetNext(void) const;
  
      /**
       * This method returns the number of bytes in the message.
       *
       * @returns The number of bytes in the message.
       */
      uint16_t GetLength(void) const { return mBuffer.mHead.mInfo.mLength; }
  
      /**
       * This method sets the number of bytes in the message.
       *
       * @param[in]  aLength  Requested number of bytes in the message.
       *
       * @retval OT_ERROR_NONE     Successfully set the length of the message.
       * @retval OT_ERROR_NO_BUFS  Failed to grow the size of the message because insufficient buffers were available.
       *
       */
      otError SetLength(uint16_t aLength);
  
      /**
       * This method returns the number of buffers in the message.
       *
       */
      uint8_t GetBufferCount(void) const;
  
      /**
       * This method returns the byte offset within the message.
       *
       * @returns A byte offset within the message.
       *
       */
      uint16_t GetOffset(void) const { return mBuffer.mHead.mInfo.mOffset; }
  
      /**
       * This method 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.
       *
       * @retval OT_ERROR_NONE          Successfully moved the byte offset.
       * @retval OT_ERROR_INVALID_ARGS  The resulting byte offset is not within the existing message.
       *
       */
      otError MoveOffset(int aDelta);
  
      /**
       * This method sets the byte offset within the message.
       *
       * @param[in]  aOffset  The number of bytes to move the current offset, which may be positive or negative.
       *
       * @retval OT_ERROR_NONE          Successfully moved the byte offset.
       * @retval OT_ERROR_INVALID_ARGS  The requested byte offset is not within the existing message.
       *
       */
      otError SetOffset(uint16_t aOffset);
  
      /**
       * This method returns the type of the message.
       *
       * @returns The type of the message.
       *
       */
      uint8_t GetType(void) const { return mBuffer.mHead.mInfo.mType; }
  
      /**
       * This method sets the message type.
       *
       * @param[in]  aType  The message type.
       *
       */
      void SetType(uint8_t aType) { mBuffer.mHead.mInfo.mType = aType; }
  
      /**
       * This method returns the sub type of the message.
       *
       * @returns The sub type of the message.
       *
       */
      uint8_t GetSubType(void) const { return mBuffer.mHead.mInfo.mSubType; }
  
      /**
       * This method sets the message sub type.
       *
       * @param[in]  aSubType  The message sub type.
       *
       */
      void SetSubType(uint8_t aSubType) { mBuffer.mHead.mInfo.mSubType = aSubType; }
  
      /**
       * This method returns whether or not the message is of MLE subtype.
       *
       * @retval TRUE   If message is of MLE subtype.
       * @retval FLASE  If message is not of MLE subtype.
       *
       */
      bool IsSubTypeMle(void) const;
  
      /**
       * This method returns the message priority level.
       *
       * @returns The priority level associated with this message.
       *
       */
      uint8_t GetPriority(void) const { return mBuffer.mHead.mInfo.mPriority; }
  
      /**
       * This method 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]  aPrority  The message priority level.
       *
       * @retval OT_ERROR_NONE           Successfully set the priority for the message.
       * @retval OT_ERROR_INVALID_ARGS   Priority level is not invalid.
       *
       */
      otError SetPriority(uint8_t aPriority);
  
      /**
       * This method 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.
       * @param[in]  aLength  The number of bytes to prepend.
       *
       * @retval OT_ERROR_NONE     Successfully prepended the bytes.
       * @retval OT_ERROR_NO_BUFS  Not enough reserved bytes in the message.
       *
       */
      otError Prepend(const void *aBuf, uint16_t aLength);
  
      /**
       * This method removes header bytes from the message.
       *
       * @param[in]  aLength  Number of header bytes to remove.
       *
       * @retval OT_ERROR_NONE  Successfully removed header bytes from the message.
       *
       */
      otError RemoveHeader(uint16_t aLength);
  
      /**
       * This method 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.
       * @param[in]  aLength  The number of bytes to append.
       *
       * @retval OT_ERROR_NONE     Successfully appended the bytes.
       * @retval OT_ERROR_NO_BUFS  Insufficient available buffers to grow the message.
       *
       */
      otError Append(const void *aBuf, uint16_t aLength);
  
      /**
       * This method reads bytes from the message.
       *
       * @param[in]  aOffset  Byte offset within the message to begin reading.
       * @param[in]  aLength  Number of bytes to read.
       * @param[in]  aBuf     A pointer to a data buffer.
       *
       * @returns The number of bytes read.
       *
       */
      uint16_t Read(uint16_t aOffset, uint16_t aLength, void *aBuf) const;
  
      /**
       * This method writes bytes to the message.
       *
       * @param[in]  aOffset  Byte offset within the message to begin writing.
       * @param[in]  aLength  Number of bytes to write.
       * @param[in]  aBuf     A pointer to a data buffer.
       *
       * @returns The number of bytes written.
       *
       */
      int Write(uint16_t aOffset, uint16_t aLength, const void *aBuf);
  
      /**
       * This method copies bytes from one message to another.
       *
       * @param[in] aSourceOffset       Byte offset within the source message to begin reading.
       * @param[in] aDestinationOffset  Byte offset within the destination message to begin writing.
       * @param[in] aLength             Number of bytes to copy.
       * @param[in] aMessage            Message to copy to.
       *
       * @returns The number of bytes copied.
       *
       */
      int CopyTo(uint16_t aSourceOffset, uint16_t aDestinationOffset, uint16_t aLength, Message &aMessage) const;
  
      /**
       * This method creates a copy of the current Message. It allocates the new one
       * from the same Message Poll as the original Message and copies @p aLength octets of a payload.
       *
       * The `Type`, `SubType`, `LinkSecurity` 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 NULL if insufficient message buffers are available.
       */
      Message *Clone(uint16_t aLength) const;
  
      /**
       * This method creates a copy of the current Message. It allocates the new one
       * from the same Message Poll as the original Message and copies a full payload.
       *
       * @returns A pointer to the message or NULL if insufficient message buffers are available.
       */
      Message *Clone(void) const { return Clone(GetLength()); };
  
      /**
       * This method returns the datagram tag used for 6LoWPAN fragmentation.
       *
       * @returns The 6LoWPAN datagram tag.
       *
       */
      uint16_t GetDatagramTag(void) const { return mBuffer.mHead.mInfo.mDatagramTag; }
  
      /**
       * This method sets the datagram tag used for 6LoWPAN fragmentation.
       *
       * @param[in]  aTag  The 6LoWPAN datagram tag.
       *
       */
      void SetDatagramTag(uint16_t aTag) { mBuffer.mHead.mInfo.mDatagramTag = aTag; }
  
      /**
       * This method 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(uint8_t aChildIndex) const;
  
      /**
       * This method unschedules forwarding of the message to the child.
       *
       * @param[in]  aChildIndex  The index into the child table.
       *
       */
      void ClearChildMask(uint8_t aChildIndex);
  
      /**
       * This method schedules forwarding of the message to the child.
       *
       * @param[in]  aChildIndex  The index into the child table.
       *
       */
      void SetChildMask(uint8_t aChildIndex);
  
      /**
       * This method 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;
  
      /**
       * This method 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 mBuffer.mHead.mInfo.mPanIdChannel.mPanId; }
  
      /**
       * This method 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) { mBuffer.mHead.mInfo.mPanIdChannel.mPanId = aPanId; }
  
      /**
       * This method 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 mBuffer.mHead.mInfo.mPanIdChannel.mChannel; }
  
      /**
       * This method 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) { mBuffer.mHead.mInfo.mPanIdChannel.mChannel = aChannel; }
  
      /**
       * This method returns the timeout used for 6LoWPAN reassembly.
       *
       * @returns The time remaining in seconds.
       *
       */
      uint8_t GetTimeout(void) const { return mBuffer.mHead.mInfo.mTimeout; }
  
      /**
       * This method sets the timeout used for 6LoWPAN reassembly.
       *
       * @param[in]  aTimeout  The timeout value.
       *
       */
      void SetTimeout(uint8_t aTimeout) { mBuffer.mHead.mInfo.mTimeout = aTimeout; }
  
      /**
       * This method returns the interface ID.
       *
       * @returns The interface ID.
       *
       */
      int8_t GetInterfaceId(void) const { return mBuffer.mHead.mInfo.mInterfaceId; }
  
      /**
       * This method sets the interface ID.
       *
       * @param[in]  aInterfaceId  The interface ID value.
       *
       */
      void SetInterfaceId(int8_t aInterfaceId) { mBuffer.mHead.mInfo.mInterfaceId = aInterfaceId; }
  
      /**
       * This method 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 GetDirectTransmission(void) const { return mBuffer.mHead.mInfo.mDirectTx; }
  
      /**
       * This method unschedules forwarding using direct transmission.
       *
       */
      void ClearDirectTransmission(void) { mBuffer.mHead.mInfo.mDirectTx = false; }
  
      /**
       * This method schedules forwarding using direct transmission.
       *
       */
      void SetDirectTransmission(void) { mBuffer.mHead.mInfo.mDirectTx = true; }
  
      /**
       * This method 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 mBuffer.mHead.mInfo.mLinkSecurity; }
  
      /**
       * This method 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) { mBuffer.mHead.mInfo.mLinkSecurity = aEnabled; }
  
      /**
       * This method is used to update a checksum value.
       *
       * @param[in]  aChecksum  Initial checksum value.
       * @param[in]  aOffset    Byte offset within the message to begin checksum computation.
       * @param[in]  aLength    Number of bytes to compute the checksum over.
       *
       * @retval The updated checksum value.
       *
       */
      uint16_t UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const;
  
      /**
       * This method returns a pointer to the message queue (if any) where this message is queued.
       *
       * @returns A pointer to the message queue or NULL if not in any message queue.
       *
       */
      MessageQueue *GetMessageQueue(void) const {
          return (!mBuffer.mHead.mInfo.mInPriorityQ) ? mBuffer.mHead.mInfo.mQueue.mMessage : NULL;
      }
  
  private:
  
      /**
       * This method returns a pointer to the message pool to which this message belongs
       *
       * @returns A pointer to the message pool.
       *
       */
      MessagePool *GetMessagePool(void) const { return mBuffer.mHead.mInfo.mMessagePool; }
  
      /**
       * This method sets the message pool this message to which this message belongs.
       *
       * @param[in] aMessagePool  A pointer to the message pool
       *
       */
      void SetMessagePool(MessagePool *aMessagePool) { mBuffer.mHead.mInfo.mMessagePool = aMessagePool; }
  
      /**
       * This method returns `true` if the message is enqueued in any queue (`MessageQueue` or `PriorityQueue`).
       *
       * @returns `true` if the message is in any queue, `false` otherwise.
       *
       */
      bool IsInAQueue(void) const { return (mBuffer.mHead.mInfo.mQueue.mMessage != NULL); }
  
      /**
       * This method sets the message queue information for the message.
       *
       * @param[in]  aMessageQueue  A pointer to the message queue where this message is queued.
       *
       */
      void SetMessageQueue(MessageQueue *aMessageQueue);
  
      /**
       * This method returns a pointer to the priority message queue (if any) where this message is queued.
       *
       * @returns A pointer to the priority queue or NULL if not in any priority queue.
       *
       */
      PriorityQueue *GetPriorityQueue(void) const {
          return (mBuffer.mHead.mInfo.mInPriorityQ) ? mBuffer.mHead.mInfo.mQueue.mPriority : NULL;
      }
  
      /**
       * This method sets the message queue information for the message.
       *
       * @param[in]  aPriorityQueue  A pointer to the priority queue where this message is queued.
       *
       */
      void SetPriorityQueue(PriorityQueue *aPriorityQueue);
  
      /**
       * This method returns a reference to the `mNext` pointer for a given list.
       *
       * @param[in]  aList  The index to the message list.
       *
       * @returns A reference to the mNext pointer for the specified list.
       *
       */
      Message *&Next(uint8_t aList) { return mBuffer.mHead.mInfo.mNext[aList]; }
  
      /**
       * This method returns a const reference to the `mNext` pointer for a given list.
       *
       * @param[in]  aList  The index to the message list.
       *
       * @returns A const reference to the mNext pointer for the specified list.
       *
       */
      Message *const &Next(uint8_t aList) const { return mBuffer.mHead.mInfo.mNext[aList]; }
  
      /**
       * This method returns a reference to the `mPrev` pointer for a given list.
       *
       * @param[in]  aList  The index to the message list.
       *
       * @returns A reference to the mPrev pointer for the specified list.
       *
       */
      Message *&Prev(uint8_t aList) { return mBuffer.mHead.mInfo.mPrev[aList]; }
  
      /**
       * This method returns the number of reserved header bytes.
       *
       * @returns The number of reserved header bytes.
       *
       */
      uint16_t GetReserved(void) const { return mBuffer.mHead.mInfo.mReserved; }
  
      /**
       * This method sets the number of reserved header bytes.
       *
       * @pram[in]  aReservedHeader  The number of header bytes to reserve.
       *
       */
      void SetReserved(uint16_t aReservedHeader) { mBuffer.mHead.mInfo.mReserved = aReservedHeader; }
  
      /**
       * This method adds or frees message buffers to meet the requested length.
       *
       * @param[in]  aLength  The number of bytes that the message buffer needs to handle.
       *
       * @retval OT_ERROR_NONE     Successfully resized the message.
       * @retval OT_ERROR_NO_BUFS  Could not grow the message due to insufficient available message buffers.
       *
       */
      otError ResizeMessage(uint16_t aLength);
  };
  
  /**
   * This class implements a message queue.
   *
   */
  class MessageQueue : public otMessageQueue
  {
      friend class Message;
      friend class PriorityQueue;
  
  public:
      /**
       * This constructor initializes the message queue.
       *
       */
      MessageQueue(void);
  
      /**
       * This method returns a pointer to the first message.
       *
       * @returns A pointer to the first message.
       *
       */
      Message *GetHead(void) const;
  
      /**
       * This method adds a message to the end of the list.
       *
       * @param[in]  aMessage  The message to add.
       *
       * @retval OT_ERROR_NONE     Successfully added the message to the list.
       * @retval OT_ERROR_ALREADY  The message is already enqueued in a list.
       *
       */
      otError Enqueue(Message &aMessage);
  
      /**
       * This method removes a message from the list.
       *
       * @param[in]  aMessage  The message to remove.
       *
       * @retval OT_ERROR_NONE       Successfully removed the message from the list.
       * @retval OT_ERROR_NOT_FOUND  The message is not enqueued in a list.
       *
       */
      otError Dequeue(Message &aMessage);
  
      /**
       * This method returns the number of messages and buffers enqueued.
       *
       * @param[out]  aMessageCount  Returns the number of messages enqueued.
       * @param[out]  aBufferCount   Returns the number of buffers enqueued.
       *
       */
      void GetInfo(uint16_t &aMessageCount, uint16_t &aBufferCount) const;
  
  private:
  
      /**
       * This method returns the tail of the list (last message in the list)
       *
       * @returns A pointer to the tail of the list.
       *
       */
      Message *GetTail(void) const { return static_cast<Message *>(mData); }
  
      /**
       * This method set the tail of the list.
       *
       * @param[in]  aMessage  A pointer to the message to set as new tail.
       *
       */
      void SetTail(Message *aMessage) { mData = aMessage; }
  
      /**
       * This method adds a message to a list.
       *
       * @param[in]  aListId   The list to add @p aMessage to.
       * @param[in]  aMessage  The message to add to @p aListId.
       *
       */
      void AddToList(uint8_t aListId, Message &aMessage);
  
      /**
       * This method removes a message from a list.
       *
       * @param[in]  aListId   The list to add @p aMessage to.
       * @param[in]  aMessage  The message to add to @p aListId.
       *
       */
      void RemoveFromList(uint8_t aListId, Message &aMessage);
  };
  
  /**
   * This class implements a priority queue.
   *
   */
  class PriorityQueue
  {
      friend class Message;
      friend class MessageQueue;
      friend class MessagePool;
  
  public:
      /**
       * This constructor initializes the priority queue.
       *
       */
      PriorityQueue(void);
  
      /**
       * This method returns a pointer to the first message.
       *
       * @returns A pointer to the first message.
       *
       */
      Message *GetHead(void) const;
  
      /**
        * This method 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 NULL if there is no messages with
        *          this priority level.
        *
        */
      Message *GetHeadForPriority(uint8_t aPriority) const;
  
      /**
       * This method adds a message to the queue.
       *
       * @param[in]  aMessage  The message to add.
       *
       * @retval OT_ERROR_NONE     Successfully added the message to the list.
       * @retval OT_ERROR_ALREADY  The message is already enqueued in a list.
       *
       */
      otError Enqueue(Message &aMessage);
  
      /**
       * This method removes a message from the list.
       *
       * @param[in]  aMessage  The message to remove.
       *
       * @retval OT_ERROR_NONE       Successfully removed the message from the list.
       * @retval OT_ERROR_NOT_FOUND  The message is not enqueued in a list.
       *
       */
      otError Dequeue(Message &aMessage);
  
      /**
       * This method returns the number of messages and buffers enqueued.
       *
       * @param[out]  aMessageCount  Returns the number of messages enqueued.
       * @param[out]  aBufferCount   Returns the number of buffers enqueued.
       *
       */
      void GetInfo(uint16_t &aMessageCount, uint16_t &aBufferCount) const;
  
  private:
  
      /**
       * This method returns the tail of the list (last message in the list)
       *
       * @returns A pointer to the tail of the list.
       *
       */
      Message *GetTail(void) const;
  
      /**
       * This method adds a message to a list.
       *
       * @param[in]  aListId   The list to add @p aMessage to.
       * @param[in]  aMessage  The message to add to @p aListId.
       *
       */
      void AddToList(uint8_t aListId, Message &aMessage);
  
      /**
       * This method removes a message from a list.
       *
       * @param[in]  aListId   The list to add @p aMessage to.
       * @param[in]  aMessage  The message to add to @p aListId.
       *
       */
      void RemoveFromList(uint8_t aListId, Message &aMessage);
  
      /**
       * This method decreases (moves back) the given priority while ensuring to wrap from
       * priority value 0 back to `kNumPriorities` -1.
       *
       * @param[in] aPriority  A given priority level
       *
       * @returns Decreased/Moved back priority level
       */
      uint8_t PrevPriority(uint8_t aPriority) const {
          return (aPriority == 0) ? (Message::kNumPriorities - 1) : (aPriority - 1);
      }
  
      /**
       * This private method finds the first non-NULL tail starting from the given priority level and moving back.
       * It wraps from priority value 0 back to `kNumPriorities` -1.
       *
       * aStartPriorityLevel  Starting priority level.
       *
       * @returns The first non-NULL tail pointer, or NULL if all the
       *
       */
      Message *FindFirstNonNullTail(uint8_t aStartPriorityLevel) const;
  
  private:
  
      Message *mTails[Message::kNumPriorities];   ///< Tail pointers associated with different priority levels.
  };
  
  /**
   * This class represents a message pool
   *
   */
  class MessagePool
  {
      friend class Message;
      friend class MessageQueue;
      friend class PriorityQueue;
  
  public:
  
      /**
      * This class represents an iterator for iterating through all queued message from this pool.
      *
      */
      class Iterator
      {
          friend class MessagePool;
  
      public:
          /**
           * This constructor initializes an empty iterator.
           */
          Iterator(void) : mMessage(NULL) { }
  
          /**
           * This method returns the associated message with the iterator.
           *
           * @returns A pointer to associated message with this iterator.
           *
           */
          Message *GetMessage(void) const { return mMessage; }
  
          /**
           * This method returns `true` if the iterator is empty (i.e., associated with a NULL message)
           *
           * @returns `true` if the iterator is empty, `false` otherwise.
           */
          bool IsEmpty(void) const { return (mMessage == NULL); }
  
          /**
           * This method returns `true` if the iterator has ended (beyond the last message on list).
           *
           * @returns `true` if the iterator has ended , `false` otherwise.
           */
          bool HasEnded(void) const { return IsEmpty(); }
  
          /**
           * This method returns a new iterator corresponding to next message on the list.
           *
           * @returns An iterator corresponding to next message on the list.
           *
           */
          Iterator GetNext(void) const { return Iterator(Next()); }
  
          /**
           * This method returns a new iterator corresponding to previous message on the list.
           *
           * @returns An iterator corresponding to previous message on the list.
           *
           */
          Iterator GetPrev(void) const { return Iterator(Prev()); }
  
          /**
           * This method moves the current iterator to the next message on the list.
           *
           * @returns A reference to current iterator.
           *
           */
          Iterator &GoToNext(void) { mMessage = Next(); return *this; }
  
          /**
           * This method moves the current iterator to the previous message on the list.
           *
           * @returns A reference to current iterator.
           *
           */
          Iterator &GoToPrev(void) { mMessage = Prev(); return *this; }
  
      private:
          Iterator(Message *aMessage) : mMessage(aMessage) { }
          Message *Next(void) const;
          Message *Prev(void) const;
  
          Message *mMessage;
      };
  
      /**
       * This constructor initializes the object.
       *
       */
      MessagePool(otInstance *aInstance);
  
      /**
       * This method is used to obtain a new message. The default priority `kDefaultMessagePriority`
       * is assigned to the message.
       *
       * @param[in]  aType           The message type.
       * @param[in]  aReserveHeader  The number of header bytes to reserve.
       *
       * @returns A pointer to the message or NULL if no message buffers are available.
       *
       */
      Message *New(uint8_t aType, uint16_t aReserveHeader);
  
      /**
       * This method is used to free a message and return all message buffers to the buffer pool.
       *
       * @param[in]  aMessage  The message to free.
       *
       * @retval OT_ERROR_NONE          Successfully freed the message.
       * @retval OT_ERROR_INVALID_ARGS  The message is already freed.
       *
       */
      otError Free(Message *aMessage);
  
      /**
       * This method returns a pointer to the first message (head) in the all-messages list.
       * Messages are sorted based on their priority (head with highest priority) and order by which they are enqueued.
       *
       * @returns A pointer to the first message.
       *
       */
      Iterator GetAllMessagesHead(void) const;
  
      /**
       * This method returns a pointer to the last message (head) in the all-messages list.
       * Messages are sorted based on their priority (head with highest priority) and order by which they are enqueued.
       *
       * @returns A pointer to the last message.
       *
       */
      Iterator GetAllMessagesTail(void) const { return Iterator(mAllQueue.GetTail()); }
  
      /**
       * This method returns the number of free buffers.
       *
       * @returns The number of free buffers.
       *
       */
  #if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
      uint16_t GetFreeBufferCount(void) const { return otPlatMessagePoolNumFreeBuffers(mInstance); }
  #else
      uint16_t GetFreeBufferCount(void) const { return mNumFreeBuffers; }
  #endif
  
  private:
      enum
      {
          kDefaultMessagePriority = Message::kPriorityLow,
      };
  
      Buffer *NewBuffer(void);
      otError FreeBuffers(Buffer *aBuffer);
      otError ReclaimBuffers(int aNumBuffers);
      PriorityQueue *GetAllMessagesQueue(void) { return &mAllQueue; }
  
  #if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT == 0
      uint16_t mNumFreeBuffers;
      Buffer   mBuffers[kNumBuffers];
      Buffer   *mFreeBuffers;
  #endif
  
      otInstance *mInstance;
      PriorityQueue mAllQueue;
  };
  
  /**
   * @}
   *
   */
  
  }  // namespace ot
  
  #endif  // MESSAGE_HPP_
  