blob: 772613a06a1bda88ba5c9ec8cddcca9fb41d1b4c [file] [log] [blame]
/*
* 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 forwarding IPv6 datagrams across the Thread mesh.
*/
#ifndef MESH_FORWARDER_HPP_
#define MESH_FORWARDER_HPP_
#include "openthread-core-config.h"
#include "common/locator.hpp"
#include "common/tasklet.hpp"
#include "mac/channel_mask.hpp"
#include "mac/data_poll_sender.hpp"
#include "mac/mac.hpp"
#include "net/ip6.hpp"
#include "thread/address_resolver.hpp"
#include "thread/indirect_sender.hpp"
#include "thread/lowpan.hpp"
#include "thread/network_data_leader.hpp"
#include "thread/topology.hpp"
namespace ot {
enum
{
kReassemblyTimeout = OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT,
};
/**
* @addtogroup core-mesh-forwarding
*
* @brief
* This module includes definitions for mesh forwarding within Thread.
*
* @{
*/
/**
* This class represents an IPv6 fragment priority entry
*
*/
class FragmentPriorityEntry
{
public:
/**
* This method returns the fragment datagram tag value.
*
* @returns The fragment datagram tag value.
*
*/
uint16_t GetDatagramTag(void) const { return mDatagramTag; }
/**
* This method sets the fragment datagram tag value.
*
* @param[in] aDatagramTag The fragment datagram tag value.
*
*/
void SetDatagramTag(uint16_t aDatagramTag) { mDatagramTag = aDatagramTag; }
/**
* This method returns the source Rloc16 of the fragment.
*
* @returns The source Rloc16 value.
*
*/
uint16_t GetSrcRloc16(void) const { return mSrcRloc16; }
/**
* This method sets the source Rloc16 value of the fragment.
*
* @param[in] aSrcRloc16 The source Rloc16 value.
*
*/
void SetSrcRloc16(uint16_t aSrcRloc16) { mSrcRloc16 = aSrcRloc16; }
/**
* This method returns the fragment priority value.
*
* @returns The fragment priority value.
*
*/
uint8_t GetPriority(void) const { return mPriority; }
/**
* This method sets the fragment priority value.
*
* @param[in] aPriority The fragment priority value.
*
*/
void SetPriority(uint8_t aPriority) { mPriority = aPriority; }
/**
* This method returns the fragment priority entry's remaining lifetime.
*
* @returns The fragment priority entry's remaining lifetime.
*
*/
uint8_t GetLifetime(void) const { return mLifetime; }
/**
* This method sets the remaining lifetime of the fragment priority entry.
*
* @param[in] aLifetime The remaining lifetime of the fragment priority entry (in seconds).
*
*/
void SetLifetime(uint8_t aLifetime)
{
if (aLifetime > kMaxLifeTime)
{
aLifetime = kMaxLifeTime;
}
mLifetime = aLifetime;
}
/**
* This method decrements the entry lifetime.
*
*/
void DecrementLifetime(void) { mLifetime--; }
private:
enum
{
kMaxLifeTime = 5, ///< The maximum lifetime of the fragment entry (in seconds).
};
uint16_t mSrcRloc16; ///< The source Rloc16 of the datagram.
uint16_t mDatagramTag; ///< The datagram tag of the fragment header.
uint8_t mPriority : 3; ///< The priority level of the first fragment.
uint8_t mLifetime : 3; ///< The lifetime of the entry (in seconds). 0 means the entry is invalid.
};
/**
* This class implements mesh forwarding within Thread.
*
*/
class MeshForwarder : public InstanceLocator
{
friend class Mac::Mac;
friend class Instance;
friend class DataPollSender;
friend class IndirectSender;
public:
/**
* This constructor initializes the object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit MeshForwarder(Instance &aInstance);
/**
* This method enables mesh forwarding and the IEEE 802.15.4 MAC layer.
*
*/
void Start(void);
/**
* This method disables mesh forwarding and the IEEE 802.15.4 MAC layer.
*
*/
void Stop(void);
/**
* This method submits a message to the mesh forwarder for forwarding.
*
* @param[in] aMessage A reference to the message.
*
* @retval OT_ERROR_NONE Successfully enqueued the message.
* @retval OT_ERROR_ALREADY The message was already enqueued.
* @retval OT_ERROR_DROP The message could not be sent and should be dropped.
*
*/
otError SendMessage(Message &aMessage);
/**
* This method is called by the address resolver when an EID-to-RLOC mapping has been resolved.
*
* @param[in] aEid A reference to the EID that has been resolved.
* @param[in] aError OT_ERROR_NONE on success and OT_ERROR_DROP otherwise.
*
*/
void HandleResolved(const Ip6::Address &aEid, otError aError);
/**
* This method indicates whether or not rx-on-when-idle mode is enabled.
*
* @retval TRUE The rx-on-when-idle mode is enabled.
* @retval FALSE The rx-on-when-idle-mode is disabled.
*
*/
bool GetRxOnWhenIdle(void) const;
/**
* This method sets the rx-on-when-idle mode
*
* @param[in] aRxOnWhenIdle TRUE to enable, FALSE otherwise.
*
*/
void SetRxOnWhenIdle(bool aRxOnWhenIdle);
/**
* This method sets the scan parameters for MLE Discovery Request messages.
*
* @param[in] aScanChannels A reference to channel mask indicating which channels to scan.
* If @p aScanChannels is empty, then all channels are used instead.
*
*/
void SetDiscoverParameters(const Mac::ChannelMask &aScanChannels);
/**
* This method frees any indirect messages queued for children that are no longer attached.
*
*/
void UpdateIndirectMessages(void);
/**
* This method frees any messages queued for an existing child.
*
* @param[in] aChild A reference to the child.
* @param[in] aSubType The message sub-type to remove.
* Use Message::kSubTypeNone remove all messages for @p aChild.
*
*/
void RemoveMessages(Child &aChild, uint8_t aSubType);
/**
* This method frees unicast/multicast MLE Data Responses from Send Message Queue if any.
*
*/
void RemoveDataResponseMessages(void);
/**
* This method evicts the message with lowest priority in the send queue.
*
* @param[in] aPriority The highest priority level of the evicted message.
*
* @retval OT_ERROR_NONE Successfully evicted a low priority message.
* @retval OT_ERROR_NOT_FOUND No low priority messages available to evict.
*
*/
otError EvictMessage(uint8_t aPriority);
/**
* This method returns a reference to the send queue.
*
* @returns A reference to the send queue.
*
*/
const PriorityQueue &GetSendQueue(void) const { return mSendQueue; }
/**
* This method returns a reference to the reassembly queue.
*
* @returns A reference to the reassembly queue.
*
*/
const MessageQueue &GetReassemblyQueue(void) const { return mReassemblyList; }
/**
* This method returns a reference to the IP level counters.
*
* @returns A reference to the IP level counters.
*
*/
const otIpCounters &GetCounters(void) const { return mIpCounters; }
/**
* This method resets the IP level counters.
*
*/
void ResetCounters(void) { memset(&mIpCounters, 0, sizeof(mIpCounters)); }
#if OPENTHREAD_FTD
/**
* This method returns a reference to the resolving queue.
*
* @returns A reference to the resolving queue.
*
*/
const MessageQueue &GetResolvingQueue(void) const { return mResolvingQueue; }
#endif
private:
enum
{
kStateUpdatePeriod = 1000, ///< State update period in milliseconds.
kDefaultMsgPriority = Message::kPriorityNormal, ///< Default message priority.
/**
* The number of fragment priority entries.
*
*/
kNumFragmentPriorityEntries = OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES,
};
enum MessageAction ///< Defines the action parameter in `LogMessageInfo()` method.
{
kMessageReceive, ///< Indicates that the message was received.
kMessageTransmit, ///< Indicates that the message was sent.
kMessagePrepareIndirect, ///< Indicates that the message is being prepared for indirect tx.
kMessageDrop, ///< Indicates that the outbound message is being dropped (e.g., dst unknown).
kMessageReassemblyDrop, ///< Indicates that the message is being dropped from reassembly list.
kMessageEvict, ///< Indicates that the message was evicted.
};
otError CheckReachability(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest);
void UpdateRoutes(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest);
otError DecompressIp6Header(const uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Ip6::Header & aIp6Header,
uint8_t & aHeaderLength,
bool & aNextHeaderCompressed);
otError GetIp6Header(const uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Ip6::Header & aIp6Header);
void GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
void GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
Message *GetDirectTransmission(void);
otError PrepareDiscoverRequest(void);
void HandleMesh(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address & aMacSource,
const otThreadLinkInfo &aLinkInfo);
void HandleFragment(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const otThreadLinkInfo &aLinkInfo);
void HandleLowpanHC(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const otThreadLinkInfo &aLinkInfo);
uint16_t PrepareDataFrame(Mac::TxFrame & aFrame,
Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
bool aAddMeshHeader = false,
uint16_t aMeshSource = 0xffff,
uint16_t aMeshDest = 0xffff);
void SendMesh(Message &aMessage, Mac::TxFrame &aFrame);
otError UpdateIp6Route(Message &aMessage);
otError UpdateIp6RouteFtd(Ip6::Header &ip6Header);
otError UpdateMeshRoute(Message &aMessage);
bool UpdateReassemblyList(void);
bool UpdateFragmentLifetime(void);
void UpdateFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
uint16_t aFragmentLength,
uint16_t aSrcRloc16,
uint8_t aPriority);
otError HandleDatagram(Message &aMessage, const otThreadLinkInfo &aLinkInfo, const Mac::Address &aMacSource);
void ClearReassemblyList(void);
void RemoveMessage(Message &aMessage);
void HandleDiscoverComplete(void);
void HandleReceivedFrame(Mac::RxFrame &aFrame);
otError HandleFrameRequest(Mac::TxFrame &aFrame);
Neighbor *UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame, otError aError, const Mac::Address &aMacDest);
void HandleSentFrame(Mac::TxFrame &aFrame, otError aError);
static void HandleDiscoverTimer(Timer &aTimer);
void HandleDiscoverTimer(void);
static void HandleUpdateTimer(Timer &aTimer);
void HandleUpdateTimer(void);
static void ScheduleTransmissionTask(Tasklet &aTasklet);
void ScheduleTransmissionTask(void);
otError GetFramePriority(const uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
uint8_t & aPriority);
otError GetFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader, uint16_t aSrcRloc16, uint8_t &aPriority);
otError GetForwardFramePriority(const uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
uint8_t & aPriority);
FragmentPriorityEntry *FindFragmentPriorityEntry(uint16_t aTag, uint16_t aSrcRloc16);
FragmentPriorityEntry *GetUnusedFragmentPriorityEntry(void);
otError GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest);
void LogMessage(MessageAction aAction, const Message &aMessage, const Mac::Address *aAddress, otError aError);
void LogFrame(const char *aActionText, const Mac::Frame &aFrame, otError aError);
void LogFragmentFrameDrop(otError aError,
uint16_t aFrameLength,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const Lowpan::FragmentHeader &aFragmentHeader,
bool aIsSecure);
void LogLowpanHcFrameDrop(otError aError,
uint16_t aFrameLength,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
bool aIsSecure);
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
const char *MessageActionToString(MessageAction aAction, otError aError);
const char *MessagePriorityToString(const Message &aMessage);
otError ParseIp6UdpTcpHeader(const Message &aMessage,
Ip6::Header & aIp6Header,
uint16_t & aChecksum,
uint16_t & aSourcePort,
uint16_t & aDestPort);
#if OPENTHREAD_FTD
otError DecompressIp6UdpTcpHeader(const Message & aMessage,
uint16_t aOffset,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
Ip6::Header & aIp6Header,
uint16_t & aChecksum,
uint16_t & aSourcePort,
uint16_t & aDestPort);
otError LogMeshFragmentHeader(MessageAction aAction,
const Message & aMessage,
const Mac::Address *aMacAddress,
otError aError,
uint16_t & aOffset,
Mac::Address & aMeshSource,
Mac::Address & aMeshDest,
otLogLevel aLogLevel);
void LogMeshIpHeader(const Message & aMessage,
uint16_t aOffset,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
otLogLevel aLogLevel);
void LogMeshMessage(MessageAction aAction,
const Message & aMessage,
const Mac::Address *aAddress,
otError aError,
otLogLevel aLogLevel);
#endif
void LogIp6SourceDestAddresses(Ip6::Header &aIp6Header,
uint16_t aSourcePort,
uint16_t aDestPort,
otLogLevel aLogLevel);
void LogIp6Message(MessageAction aAction,
const Message & aMessage,
const Mac::Address *aAddress,
otError aError,
otLogLevel aLogLevel);
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
TimerMilli mDiscoverTimer;
TimerMilli mUpdateTimer;
PriorityQueue mSendQueue;
MessageQueue mReassemblyList;
uint16_t mFragTag;
uint16_t mMessageNextOffset;
Message *mSendMessage;
Mac::Address mMacSource;
Mac::Address mMacDest;
uint16_t mMeshSource;
uint16_t mMeshDest;
bool mAddMeshHeader;
bool mSendBusy;
Tasklet mScheduleTransmissionTask;
bool mEnabled;
Mac::ChannelMask mScanChannels;
uint8_t mScanChannel;
uint16_t mRestorePanId;
bool mScanning;
otIpCounters mIpCounters;
#if OPENTHREAD_FTD
FragmentPriorityEntry mFragmentEntries[kNumFragmentPriorityEntries];
MessageQueue mResolvingQueue;
IndirectSender mIndirectSender;
#endif
DataPollSender mDataPollSender;
};
/**
* @}
*
*/
} // namespace ot
#endif // MESH_FORWARDER_HPP_