openthread/src/core/common/message.hpp

740 lines
22 KiB
C++

/*
* 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 <stdint.h>
#include <string.h>
#include <openthread-types.h>
#include <openthread-core-config.h>
#include <common/code_utils.hpp>
#include <mac/mac_frame.hpp>
namespace Thread {
/**
* @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;
/**
* This structure contains pointers to the head and tail of a Message list.
*
*/
struct MessageList
{
Message *mHead; ///< A pointer to the first Message in the list.
Message *mTail; ///< A pointer to the last Message in the list.
};
/**
* This structure contains pointers to the MessageList structure, the next Message, and previous Message.
*
*/
struct MessageListEntry
{
struct MessageList *mList; ///< A pointer to the MessageList structure for the list.
Message *mNext; ///< A pointer to the next Message in the list.
Message *mPrev; ///< A pointer to the previous Message in the list.
};
/**
* This structure contains a pointer to the next Message buffer.
*
*/
struct BufferHeader
{
class Buffer *mNext; ///< A pointer to the next Message buffer.
};
/**
* This structure contains metdata about a Message.
*
*/
struct MessageInfo
{
MessagePool *mMessagePool; ///< Identifies the message pool for this message.
enum
{
kListAll = 0, ///< Identifies the all messages list.
kListInterface = 1, ///< Identifies the per-interface message list.
};
MessageListEntry mList[2]; ///< Message lists.
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.
uint16_t mPanId; ///< The Destination PAN ID.
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
int8_t mInterfaceId; ///< The interface ID.
uint8_t mType : 2; ///< Identifies the type of message.
bool mDirectTx : 1; ///< Used to indicate whether a direct transmission is required.
bool mLinkSecurity : 1; ///< Indicates whether or not link security is enabled.
bool mMleDiscoverRequest : 1; ///< Identifies MLE Discover Request.
bool mMleDiscoverResponse : 1; ///< Identifies MLE Discover Response.
bool mJoinerEntrust : 1; ///< Indicates whether or not this message is a Joiner Entrust.
};
/**
* This class represents a Message buffer.
*
*/
class Buffer
{
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 mHeader.mNext; }
/**
* This method sets the pointer to the next message buffer.
*
*/
void SetNextBuffer(class Buffer *buf) { mHeader.mNext = 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 mHeadData; }
/**
* 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 mHeadData; }
/**
* 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 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 mData; }
enum
{
kBufferDataSize = kBufferSize - sizeof(struct BufferHeader),
kHeadBufferDataSize = kBufferDataSize - sizeof(struct MessageInfo),
};
struct BufferHeader mHeader;
union
{
struct
{
MessageInfo mInfo;
uint8_t mHeadData[kHeadBufferDataSize];
};
uint8_t mData[kBufferDataSize];
};
};
/**
* This class represents a message.
*
*/
class Message: private Buffer
{
friend class MessagePool;
friend class MessageQueue;
public:
enum
{
kTypeIp6 = 0, ///< A full uncompress IPv6 packet
kType6lowpan = 1, ///< A 6lowpan frame
kTypeMacDataPoll = 2, ///< A MAC data poll message
};
/**
* This method frees this message buffer.
*
*/
ThreadError 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.
*
*/
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;
/**
* This method sets the number of bytes in the message.
*
* @param[in] aLength Requested number of bytes in the message.
*
* @retval kThreadError_None Successfully set the length of the message.
* @retval kThreadError_NoBufs Failed to grow the size of the message because insufficient buffers were
* available.
*
*/
ThreadError SetLength(uint16_t aLength);
/**
* This method returns the byte offset within the message.
*
* @returns A byte offset within the message.
*
*/
uint16_t GetOffset(void) const;
/**
* 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 kThreadError_None Successfully moved the byte offset.
* @retval kThreadError_InvalidArgs The resulting byte offset is not within the existing message.
*
*/
ThreadError 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 kThreadError_None Successfully moved the byte offset.
* @retval kThreadError_InvalidArgs The requested byte offset is not within the existing message.
*
*/
ThreadError SetOffset(uint16_t aOffset);
/**
* This method returns the type of the message.
*
* @returns The type of the message.
*
*/
uint8_t GetType(void) const;
/**
* 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 kThreadError_None Successfully prepended the bytes.
* @retval kThreadError_NoBufs Not enough reserved bytes in the message.
*
*/
ThreadError Prepend(const void *aBuf, 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 kThreadError_None Successfully appended the bytes.
* @retval kThreadError_NoBufs Insufficient available buffers to grow the message.
*
*/
ThreadError 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 returns the datagram tag used for 6LoWPAN fragmentation.
*
* @returns The 6LoWPAN datagram tag.
*
*/
uint16_t GetDatagramTag(void) const;
/**
* This method sets the datagram tag used for 6LoWPAN fragmentation.
*
* @param[in] aTag The 6LoWPAN datagram tag.
*
*/
void SetDatagramTag(uint16_t 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.
*
* @returns The IEEE 802.15.4 Destination PAN ID.
*
*/
uint16_t GetPanId(void) const;
/**
* This method sets the IEEE 802.15.4 Destination PAN ID.
*
* @param[in] aPanId The IEEE 802.15.4 Destination PAN ID.
*
*/
void SetPanId(uint16_t aPanId);
/**
* This method returns the timeout used for 6LoWPAN reassembly.
*
* @returns The time remaining in seconds.
*
*/
uint8_t GetTimeout(void) const;
/**
* This method sets the timeout used for 6LoWPAN reassembly.
*
* @param[in] aTimeout The timeout value.
*
*/
void SetTimeout(uint8_t aTimeout);
/**
* This method returns the interface ID.
*
* @returns The interface ID.
*
*/
int8_t GetInterfaceId(void) const;
/**
* This method sets the interface ID.
*
* @param[in] aInterfaceId The interface ID value.
*
*/
void SetInterfaceId(int8_t 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;
/**
* This method unschedules forwarding using direct transmission.
*
*/
void ClearDirectTransmission(void);
/**
* This method schedules forwarding using direct transmission.
*
*/
void SetDirectTransmission(void);
/**
* 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;
/**
* This method sets whether or not link security is enabled for the message.
*
* @param[in] aLinkSecurityEnabled TRUE if link security is enabled, FALSE otherwise.
*
*/
void SetLinkSecurityEnabled(bool aLinkSecurityEnabled);
/**
* This method indicates whether or not this message is an MLE Discovery Request.
*
* @retval TRUE If this message is an MLE Discovery Request.
* @retval FALSE If this message is not an MLE Discovery Request.
*
*/
bool IsMleDiscoverRequest(void) const;
/**
* This method sets whether or not this message is an MLE Discovery Request.
*
* @param[in] aLinkSecurityEnabled TRUE if this message is an MLE Discovery Request, FALSE otherwise.
*
*/
void SetMleDiscoverRequest(bool aMleDiscoverRequest);
/**
* This method indicates whether or not this message is an MLE Discovery Response.
*
* @retval TRUE If this message is an MLE Discovery Response.
* @retval FALSE If this message is not an MLE Discovery Response.
*
*/
bool IsMleDiscoverResponse(void) const;
/**
* This method sets whether or not this message is an MLE Discovery Response.
*
* @param[in] aLinkSecurityEnabled TRUE if this message is an MLE Discovery Response, FALSE otherwise.
*
*/
void SetMleDiscoverResponse(bool aMleDiscoverResponse);
/**
* This method indicates whether or not this message is an Joiner Entrust.
*
* @retval TRUE If this message is an Joiner Entrust.
* @retval FALSE If this message is not an Joiner Entrust.
*
*/
bool IsJoinerEntrust(void) const;
/**
* This method sets whether or not this message is an Joiner Entrust.
*
* @param[in] aLinkSecurityEnabled TRUE if this message is an Joiner Entrust, FALSE otherwise.
*
*/
void SetJoinerEntrust(bool aJoinerEntrust);
/**
* 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;
private:
MessagePool *GetMessagePool(void) { return mInfo.mMessagePool; }
void SetMessagePool(MessagePool *aMessagePool) { mInfo.mMessagePool = aMessagePool; }
/**
* This method returns a reference to a message list.
*
* @param[in] aList The message list.
*
* @returns A reference to a message list.
*
*/
MessageListEntry &GetMessageList(uint8_t aList) { return mInfo.mList[aList]; }
/**
* This method returns a reference to a message list.
*
* @param[in] aList The message list.
*
* @returns A reference to a message list.
*
*/
const MessageListEntry &GetMessageList(uint8_t aList) const { return mInfo.mList[aList]; }
/**
* This method returns the number of reserved header bytes.
*
* @returns The number of reserved header bytes.
*
*/
uint16_t GetReserved(void) const;
/**
* This method sets the number of reserved header bytes.
*
* @pram[in] aReservedHeader The number of header bytes to reserve.
*
*/
void SetReserved(uint16_t aReservedHeader);
/**
* This method sets the message type.
*
* @param[in] aType The message type.
*
*/
void SetType(uint8_t aType);
/**
* 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 kThreadError_None Successfully resized the message.
* @retval kThreadError_InvalidArags Could not grow the message due to insufficient available message buffers.
*
*/
ThreadError ResizeMessage(uint16_t aLength);
};
/**
* This class implements a message queue.
*
*/
class MessageQueue
{
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 kThreadError_None Successfully added the message to the list.
* @retval kThreadError_Busy The message is already enqueued in a list.
*
*/
ThreadError Enqueue(Message &aMessage);
/**
* This method removes a message from the list.
*
* @param[in] aMessage The message to remove.
*
* @retval kThreadError_None Successfully removed the message from the list.
* @retval kThreadError_Busy The message is not enqueued in a list.
*
*/
ThreadError Dequeue(Message &aMessage);
private:
/**
* This static 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.
*
* @retval kThreadError_None Successfully added the message to the list.
* @retval kThreadError_Busy The message is already enqueued in a list.
*
*/
static ThreadError AddToList(uint8_t aListId, Message &aMessage);
/**
* This static 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.
*
* @retval kThreadError_None Successfully added the message to the list.
* @retval kThreadError_Busy The message is not enqueued in the list.
*
*/
static ThreadError RemoveFromList(uint8_t aListId, Message &aMessage);
MessageList mInterface; ///< The instance-specific message list.
};
class MessagePool
{
friend class Message;
friend class MessageQueue;
public:
/**
* This constructor initializes the object.
*
*/
MessagePool(void);
/**
* This method is used to obtain a new 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 kThreadError_None Successfully freed the message.
* @retval kThreadError_InvalidArgs The message is already freed.
*
*/
ThreadError Free(Message *aMessage);
private:
Buffer *NewBuffer(void);
ThreadError FreeBuffers(Buffer *aBuffer);
ThreadError ReclaimBuffers(int aNumBuffers);
int mNumFreeBuffers;
Buffer mBuffers[kNumBuffers];
Buffer *mFreeBuffers;
MessageList mAll;
};
/**
* @}
*
*/
} // namespace Thread
#endif // MESSAGE_HPP_