1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for forwarding IPv6 datagrams across the Thread mesh.
32  */
33 
34 #ifndef MESH_FORWARDER_HPP_
35 #define MESH_FORWARDER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include "common/clearable.hpp"
40 #include "common/locator.hpp"
41 #include "common/non_copyable.hpp"
42 #include "common/tasklet.hpp"
43 #include "common/time_ticker.hpp"
44 #include "mac/channel_mask.hpp"
45 #include "mac/data_poll_sender.hpp"
46 #include "mac/mac.hpp"
47 #include "mac/mac_frame.hpp"
48 #include "net/ip6.hpp"
49 #include "thread/address_resolver.hpp"
50 #include "thread/indirect_sender.hpp"
51 #include "thread/lowpan.hpp"
52 #include "thread/network_data_leader.hpp"
53 #include "thread/topology.hpp"
54 
55 namespace ot {
56 
57 namespace Mle {
58 class DiscoverScanner;
59 }
60 
61 namespace Utils {
62 class HistoryTracker;
63 }
64 
65 /**
66  * @addtogroup core-mesh-forwarding
67  *
68  * @brief
69  *   This module includes definitions for mesh forwarding within Thread.
70  *
71  * @{
72  */
73 
74 /**
75  * This class represents link-specific information for messages received from the Thread radio.
76  *
77  */
78 class ThreadLinkInfo : public otThreadLinkInfo, public Clearable<ThreadLinkInfo>
79 {
80 public:
81     /**
82      * This method returns the IEEE 802.15.4 Source PAN ID.
83      *
84      * @returns The IEEE 802.15.4 Source PAN ID.
85      *
86      */
GetPanId(void) const87     Mac::PanId GetPanId(void) const { return mPanId; }
88 
89     /**
90      * This method returns the IEEE 802.15.4 Channel.
91      *
92      * @returns The IEEE 802.15.4 Channel.
93      *
94      */
GetChannel(void) const95     uint8_t GetChannel(void) const { return mChannel; }
96 
97     /**
98      * This method indicates whether or not link security is enabled.
99      *
100      * @retval TRUE   If link security is enabled.
101      * @retval FALSE  If link security is not enabled.
102      *
103      */
IsLinkSecurityEnabled(void) const104     bool IsLinkSecurityEnabled(void) const { return mLinkSecurity; }
105 
106     /**
107      * This method returns the Received Signal Strength (RSS) in dBm.
108      *
109      * @returns The Received Signal Strength (RSS) in dBm.
110      *
111      */
GetRss(void) const112     int8_t GetRss(void) const { return mRss; }
113 
114     /**
115      * This method returns the frame/radio Link Quality Indicator (LQI) value.
116      *
117      * @returns The Link Quality Indicator value.
118      *
119      */
GetLqi(void) const120     uint8_t GetLqi(void) const { return mLqi; }
121 
122 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
123     /**
124      * This method returns the Time Sync Sequence.
125      *
126      * @returns The Time Sync Sequence.
127      *
128      */
GetTimeSyncSeq(void) const129     uint8_t GetTimeSyncSeq(void) const { return mTimeSyncSeq; }
130 
131     /**
132      * This method returns the time offset to the Thread network time (in microseconds).
133      *
134      * @returns The time offset to the Thread network time (in microseconds).
135      *
136      */
GetNetworkTimeOffset(void) const137     int64_t GetNetworkTimeOffset(void) const { return mNetworkTimeOffset; }
138 #endif
139 
140     /**
141      * This method sets the `ThreadLinkInfo` from a given received frame.
142      *
143      * @param[in] aFrame  A received frame.
144      *
145      */
146     void SetFrom(const Mac::RxFrame &aFrame);
147 };
148 
149 /**
150  * This class implements mesh forwarding within Thread.
151  *
152  */
153 class MeshForwarder : public InstanceLocator, private NonCopyable
154 {
155     friend class Mac::Mac;
156     friend class Instance;
157     friend class DataPollSender;
158     friend class IndirectSender;
159     friend class Mle::DiscoverScanner;
160     friend class TimeTicker;
161     friend class Utils::HistoryTracker;
162 
163 public:
164     /**
165      * This constructor initializes the object.
166      *
167      * @param[in]  aInstance     A reference to the OpenThread instance.
168      *
169      */
170     explicit MeshForwarder(Instance &aInstance);
171 
172     /**
173      * This method enables mesh forwarding and the IEEE 802.15.4 MAC layer.
174      *
175      */
176     void Start(void);
177 
178     /**
179      * This method disables mesh forwarding and the IEEE 802.15.4 MAC layer.
180      *
181      */
182     void Stop(void);
183 
184     /**
185      * This method submits a message to the mesh forwarder for forwarding.
186      *
187      * @param[in]  aMessage  A reference to the message.
188      *
189      * @retval kErrorNone     Successfully enqueued the message.
190      * @retval kErrorAlready  The message was already enqueued.
191      * @retval kErrorDrop     The message could not be sent and should be dropped.
192      *
193      */
194     Error SendMessage(Message &aMessage);
195 
196 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
197     /**
198      * This method sends an empty data frame to the parent.
199      *
200      * @retval kErrorNone          Successfully enqueued an empty message.
201      * @retval kErrorInvalidState  Device is not in Rx-Off-When-Idle mode or it has no parent.
202      * @retval kErrorNoBufs        Insufficient message buffers available.
203      *
204      */
205     Error SendEmptyMessage(void);
206 #endif
207 
208     /**
209      * This method is called by the address resolver when an EID-to-RLOC mapping has been resolved.
210      *
211      * @param[in]  aEid    A reference to the EID that has been resolved.
212      * @param[in]  aError  kErrorNone on success and kErrorDrop otherwise.
213      *
214      */
215     void HandleResolved(const Ip6::Address &aEid, Error aError);
216 
217     /**
218      * This method indicates whether or not rx-on-when-idle mode is enabled.
219      *
220      * @retval TRUE   The rx-on-when-idle mode is enabled.
221      * @retval FALSE  The rx-on-when-idle-mode is disabled.
222      *
223      */
224     bool GetRxOnWhenIdle(void) const;
225 
226     /**
227      * This method sets the rx-on-when-idle mode
228      *
229      * @param[in]  aRxOnWhenIdle  TRUE to enable, FALSE otherwise.
230      *
231      */
232     void SetRxOnWhenIdle(bool aRxOnWhenIdle);
233 
234     /**
235      * This method sets the scan parameters for MLE Discovery Request messages.
236      *
237      * @param[in]  aScanChannels  A reference to channel mask indicating which channels to scan.
238      *                            If @p aScanChannels is empty, then all channels are used instead.
239      *
240      */
241     void SetDiscoverParameters(const Mac::ChannelMask &aScanChannels);
242 
243 #if OPENTHREAD_FTD
244     /**
245      * This method frees any messages queued for an existing child.
246      *
247      * @param[in]  aChild    A reference to the child.
248      * @param[in]  aSubType  The message sub-type to remove.
249      *                       Use Message::kSubTypeNone remove all messages for @p aChild.
250      *
251      */
252     void RemoveMessages(Child &aChild, Message::SubType aSubType);
253 #endif
254 
255     /**
256      * This method frees unicast/multicast MLE Data Responses from Send Message Queue if any.
257      *
258      */
259     void RemoveDataResponseMessages(void);
260 
261     /**
262      * This method evicts the message with lowest priority in the send queue.
263      *
264      * @param[in]  aPriority  The highest priority level of the evicted message.
265      *
266      * @retval kErrorNone       Successfully evicted a low priority message.
267      * @retval kErrorNotFound   No low priority messages available to evict.
268      *
269      */
270     Error EvictMessage(Message::Priority aPriority);
271 
272     /**
273      * This method returns a reference to the send queue.
274      *
275      * @returns  A reference to the send queue.
276      *
277      */
GetSendQueue(void) const278     const PriorityQueue &GetSendQueue(void) const { return mSendQueue; }
279 
280     /**
281      * This method returns a reference to the reassembly queue.
282      *
283      * @returns  A reference to the reassembly queue.
284      *
285      */
GetReassemblyQueue(void) const286     const MessageQueue &GetReassemblyQueue(void) const { return mReassemblyList; }
287 
288     /**
289      * This method returns a reference to the IP level counters.
290      *
291      * @returns A reference to the IP level counters.
292      *
293      */
GetCounters(void) const294     const otIpCounters &GetCounters(void) const { return mIpCounters; }
295 
296     /**
297      * This method resets the IP level counters.
298      *
299      */
ResetCounters(void)300     void ResetCounters(void) { memset(&mIpCounters, 0, sizeof(mIpCounters)); }
301 
302 #if OPENTHREAD_FTD
303     /**
304      * This method returns a reference to the resolving queue.
305      *
306      * @returns  A reference to the resolving queue.
307      *
308      */
GetResolvingQueue(void) const309     const PriorityQueue &GetResolvingQueue(void) const { return mResolvingQueue; }
310 #endif
311 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
312     /**
313      * This method handles a deferred ack.
314      *
315      * Some radio links can use deferred ack logic, where a tx request always report `HandleSentFrame()` quickly. The
316      * link layer would wait for the ack and report it at a later time using this method.
317      *
318      * The link layer is expected to call `HandleDeferredAck()` (with success or failure status) for every tx request
319      * on the radio link.
320      *
321      * @param[in] aNeighbor  The neighbor for which the deferred ack status is being reported.
322      * @param[in] aError     The deferred ack error status: `kErrorNone` to indicate a deferred ack was received,
323      *                       `kErrorNoAck` to indicate an ack timeout.
324      *
325      */
326     void HandleDeferredAck(Neighbor &aNeighbor, Error aError);
327 #endif
328 
329 private:
330     static constexpr uint8_t kReassemblyTimeout      = OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT; // in seconds.
331     static constexpr uint8_t kMeshHeaderFrameMtu     = OT_RADIO_FRAME_MAX_SIZE; // Max MTU with a Mesh Header frame.
332     static constexpr uint8_t kMeshHeaderFrameFcsSize = sizeof(uint16_t);        // Frame FCS size for Mesh Header frame.
333 
334     enum MessageAction : uint8_t
335     {
336         kMessageReceive,         // Indicates that the message was received.
337         kMessageTransmit,        // Indicates that the message was sent.
338         kMessagePrepareIndirect, // Indicates that the message is being prepared for indirect tx.
339         kMessageDrop,            // Indicates that the outbound message is being dropped (e.g., dst unknown).
340         kMessageReassemblyDrop,  // Indicates that the message is being dropped from reassembly list.
341         kMessageEvict,           // Indicates that the message was evicted.
342     };
343 
344     enum AnycastType : uint8_t
345     {
346         kAnycastDhcp6Agent,
347         kAnycastNeighborDiscoveryAgent,
348         kAnycastService,
349     };
350 
351 #if OPENTHREAD_FTD
352     class FragmentPriorityList : public Clearable<FragmentPriorityList>
353     {
354     public:
355         class Entry : public Clearable<Entry>
356         {
357             friend class FragmentPriorityList;
358 
359         public:
GetPriority(void) const360             Message::Priority GetPriority(void) const { return mPriority; }
IsExpired(void) const361             bool              IsExpired(void) const { return (mLifetime == 0); }
DecrementLifetime(void)362             void              DecrementLifetime(void) { mLifetime--; }
ResetLifetime(void)363             void              ResetLifetime(void) { mLifetime = kReassemblyTimeout; }
364 
Matches(uint16_t aSrcRloc16,uint16_t aTag) const365             bool Matches(uint16_t aSrcRloc16, uint16_t aTag) const
366             {
367                 return (mSrcRloc16 == aSrcRloc16) && (mDatagramTag == aTag);
368             }
369 
370         private:
371             uint16_t          mSrcRloc16;
372             uint16_t          mDatagramTag;
373             Message::Priority mPriority;
374             uint8_t           mLifetime;
375         };
376 
377         Entry *AllocateEntry(uint16_t aSrcRloc16, uint16_t aTag, Message::Priority aPriority);
378         Entry *FindEntry(uint16_t aSrcRloc16, uint16_t aTag);
379         bool   UpdateOnTimeTick(void);
380 
381     private:
382         static constexpr uint16_t kNumEntries = OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES;
383 
384         Entry mEntries[kNumEntries];
385     };
386 #endif // OPENTHREAD_FTD
387 
388     void  SendIcmpErrorIfDstUnreach(const Message &     aMessage,
389                                     const Mac::Address &aMacSource,
390                                     const Mac::Address &aMacDest);
391     Error CheckReachability(const uint8_t *     aFrame,
392                             uint16_t            aFrameLength,
393                             const Mac::Address &aMeshSource,
394                             const Mac::Address &aMeshDest);
395     void  UpdateRoutes(const uint8_t *     aFrame,
396                        uint16_t            aFrameLength,
397                        const Mac::Address &aMeshSource,
398                        const Mac::Address &aMeshDest);
399 
400     Error    DecompressIp6Header(const uint8_t *     aFrame,
401                                  uint16_t            aFrameLength,
402                                  const Mac::Address &aMacSource,
403                                  const Mac::Address &aMacDest,
404                                  Ip6::Header &       aIp6Header,
405                                  uint8_t &           aHeaderLength,
406                                  bool &              aNextHeaderCompressed);
407     Error    FrameToMessage(const uint8_t *     aFrame,
408                             uint16_t            aFrameLength,
409                             uint16_t            aDatagramSize,
410                             const Mac::Address &aMacSource,
411                             const Mac::Address &aMacDest,
412                             Message *&          aMessage);
413     Error    GetIp6Header(const uint8_t *     aFrame,
414                           uint16_t            aFrameLength,
415                           const Mac::Address &aMacSource,
416                           const Mac::Address &aMacDest,
417                           Ip6::Header &       aIp6Header);
418     void     GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
419     void     GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
420     Message *GetDirectTransmission(void);
421     void     HandleMesh(uint8_t *             aFrame,
422                         uint16_t              aFrameLength,
423                         const Mac::Address &  aMacSource,
424                         const ThreadLinkInfo &aLinkInfo);
425     void     HandleFragment(const uint8_t *       aFrame,
426                             uint16_t              aFrameLength,
427                             const Mac::Address &  aMacSource,
428                             const Mac::Address &  aMacDest,
429                             const ThreadLinkInfo &aLinkInfo);
430     void     HandleLowpanHC(const uint8_t *       aFrame,
431                             uint16_t              aFrameLength,
432                             const Mac::Address &  aMacSource,
433                             const Mac::Address &  aMacDest,
434                             const ThreadLinkInfo &aLinkInfo);
435     uint16_t PrepareDataFrame(Mac::TxFrame &      aFrame,
436                               Message &           aMessage,
437                               const Mac::Address &aMacSource,
438                               const Mac::Address &aMacDest,
439                               bool                aAddMeshHeader = false,
440                               uint16_t            aMeshSource    = 0xffff,
441                               uint16_t            aMeshDest      = 0xffff,
442                               bool                aAddFragHeader = false);
443     void     PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &aMacDest, bool aAckRequest);
444 
445     void  SendMesh(Message &aMessage, Mac::TxFrame &aFrame);
446     void  SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage);
447     Error UpdateIp6Route(Message &aMessage);
448     Error UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage);
449     void  EvaluateRoutingCost(uint16_t aDest, uint8_t &aBestCost, uint16_t &aBestDest) const;
450     Error AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, uint16_t &aMeshDest) const;
451     Error UpdateMeshRoute(Message &aMessage);
452     bool  UpdateReassemblyList(void);
453     void  UpdateFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
454                                  uint16_t                aFragmentLength,
455                                  uint16_t                aSrcRloc16,
456                                  Message::Priority       aPriority);
457     Error HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLinkInfo, const Mac::Address &aMacSource);
458     void  ClearReassemblyList(void);
459     void  RemoveMessage(Message &aMessage);
460     void  HandleDiscoverComplete(void);
461 
462     void          HandleReceivedFrame(Mac::RxFrame &aFrame);
463     Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
464     Neighbor *    UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame, Error aError, const Mac::Address &aMacDest);
465     void          UpdateNeighborLinkFailures(Neighbor &aNeighbor,
466                                              Error     aError,
467                                              bool      aAllowNeighborRemove,
468                                              uint8_t   aFailLimit = Mle::kFailedRouterTransmissions);
469     void          HandleSentFrame(Mac::TxFrame &aFrame, Error aError);
470     void          UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDest, Neighbor *aNeighbor);
471     void          RemoveMessageIfNoPendingTx(Message &aMessage);
472 
473     void        HandleTimeTick(void);
474     static void ScheduleTransmissionTask(Tasklet &aTasklet);
475     void        ScheduleTransmissionTask(void);
476 
477     Error GetFramePriority(const uint8_t *     aFrame,
478                            uint16_t            aFrameLength,
479                            const Mac::Address &aMacSource,
480                            const Mac::Address &aMacDest,
481                            Message::Priority & aPriority);
482     Error GetFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
483                               uint16_t                aSrcRloc16,
484                               Message::Priority &     aPriority);
485     void  GetForwardFramePriority(const uint8_t *     aFrame,
486                                   uint16_t            aFrameLength,
487                                   const Mac::Address &aMeshSource,
488                                   const Mac::Address &aMeshDest,
489                                   Message::Priority & aPriority);
490 
491     bool     CalcIePresent(const Message *aMessage);
492     uint16_t CalcFrameVersion(const Neighbor *aNeighbor, bool aIePresent);
493 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
494     void AppendHeaderIe(const Message *aMessage, Mac::TxFrame &aFrame);
495 #endif
496 
PauseMessageTransmissions(void)497     void PauseMessageTransmissions(void) { mTxPaused = true; }
498     void ResumeMessageTransmissions(void);
499 
500     void LogMessage(MessageAction aAction, const Message &aMessage, const Mac::Address *aAddress, Error aError);
501     void LogFrame(const char *aActionText, const Mac::Frame &aFrame, Error aError);
502     void LogFragmentFrameDrop(Error                         aError,
503                               uint16_t                      aFrameLength,
504                               const Mac::Address &          aMacSource,
505                               const Mac::Address &          aMacDest,
506                               const Lowpan::FragmentHeader &aFragmentHeader,
507                               bool                          aIsSecure);
508     void LogLowpanHcFrameDrop(Error               aError,
509                               uint16_t            aFrameLength,
510                               const Mac::Address &aMacSource,
511                               const Mac::Address &aMacDest,
512                               bool                aIsSecure);
513 
514     static Error ParseIp6UdpTcpHeader(const Message &aMessage,
515                                       Ip6::Header &  aIp6Header,
516                                       uint16_t &     aChecksum,
517                                       uint16_t &     aSourcePort,
518                                       uint16_t &     aDestPort);
519 
520 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
521     const char *MessageActionToString(MessageAction aAction, Error aError);
522     const char *MessagePriorityToString(const Message &aMessage);
523 
524 #if OPENTHREAD_FTD
525     Error DecompressIp6UdpTcpHeader(const Message &     aMessage,
526                                     uint16_t            aOffset,
527                                     const Mac::Address &aMeshSource,
528                                     const Mac::Address &aMeshDest,
529                                     Ip6::Header &       aIp6Header,
530                                     uint16_t &          aChecksum,
531                                     uint16_t &          aSourcePort,
532                                     uint16_t &          aDestPort);
533     Error LogMeshFragmentHeader(MessageAction       aAction,
534                                 const Message &     aMessage,
535                                 const Mac::Address *aMacAddress,
536                                 Error               aError,
537                                 uint16_t &          aOffset,
538                                 Mac::Address &      aMeshSource,
539                                 Mac::Address &      aMeshDest,
540                                 otLogLevel          aLogLevel);
541     void  LogMeshIpHeader(const Message &     aMessage,
542                           uint16_t            aOffset,
543                           const Mac::Address &aMeshSource,
544                           const Mac::Address &aMeshDest,
545                           otLogLevel          aLogLevel);
546     void  LogMeshMessage(MessageAction       aAction,
547                          const Message &     aMessage,
548                          const Mac::Address *aAddress,
549                          Error               aError,
550                          otLogLevel          aLogLevel);
551 #endif
552     void LogIp6SourceDestAddresses(Ip6::Header &aIp6Header,
553                                    uint16_t     aSourcePort,
554                                    uint16_t     aDestPort,
555                                    otLogLevel   aLogLevel);
556     void LogIp6Message(MessageAction       aAction,
557                        const Message &     aMessage,
558                        const Mac::Address *aAddress,
559                        Error               aError,
560                        otLogLevel          aLogLevel);
561 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
562 
563     PriorityQueue mSendQueue;
564     MessageQueue  mReassemblyList;
565     uint16_t      mFragTag;
566     uint16_t      mMessageNextOffset;
567 
568     Message *mSendMessage;
569 
570     Mac::Address mMacSource;
571     Mac::Address mMacDest;
572     uint16_t     mMeshSource;
573     uint16_t     mMeshDest;
574     bool         mAddMeshHeader : 1;
575     bool         mEnabled : 1;
576     bool         mTxPaused : 1;
577     bool         mSendBusy : 1;
578 
579     Tasklet mScheduleTransmissionTask;
580 
581     otIpCounters mIpCounters;
582 
583 #if OPENTHREAD_FTD
584     FragmentPriorityList mFragmentPriorityList;
585     PriorityQueue        mResolvingQueue;
586     IndirectSender       mIndirectSender;
587 #endif
588 
589     DataPollSender mDataPollSender;
590 };
591 
592 /**
593  * @}
594  *
595  */
596 
597 } // namespace ot
598 
599 #endif // MESH_FORWARDER_HPP_
600