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 the IEEE 802.15.4 MAC.
32  */
33 
34 #ifndef MAC_HPP_
35 #define MAC_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/platform/radio.h>
40 #include <openthread/platform/time.h>
41 
42 #include "common/locator.hpp"
43 #include "common/non_copyable.hpp"
44 #include "common/tasklet.hpp"
45 #include "common/time.hpp"
46 #include "common/timer.hpp"
47 #include "mac/channel_mask.hpp"
48 #include "mac/mac_filter.hpp"
49 #include "mac/mac_frame.hpp"
50 #include "mac/mac_links.hpp"
51 #include "mac/mac_types.hpp"
52 #include "mac/sub_mac.hpp"
53 #include "radio/trel_link.hpp"
54 #include "thread/key_manager.hpp"
55 #include "thread/link_quality.hpp"
56 
57 namespace ot {
58 
59 class Neighbor;
60 
61 /**
62  * @addtogroup core-mac
63  *
64  * @brief
65  *   This module includes definitions for the IEEE 802.15.4 MAC
66  *
67  * @{
68  *
69  */
70 
71 namespace Mac {
72 
73 constexpr uint32_t kDataPollTimeout = 100; ///< Timeout for receiving Data Frame (in msec).
74 constexpr uint32_t kSleepDelay      = 300; ///< Max sleep delay when frame is pending (in msec).
75 
76 constexpr uint16_t kScanDurationDefault = OPENTHREAD_CONFIG_MAC_SCAN_DURATION; ///< Duration per channel (in msec).
77 
78 constexpr uint8_t kMaxCsmaBackoffsDirect   = OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT;
79 constexpr uint8_t kMaxCsmaBackoffsIndirect = OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_INDIRECT;
80 constexpr uint8_t kMaxCsmaBackoffsCsl      = 0;
81 
82 constexpr uint8_t kDefaultMaxFrameRetriesDirect   = OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT;
83 constexpr uint8_t kDefaultMaxFrameRetriesIndirect = OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT;
84 constexpr uint8_t kMaxFrameRetriesCsl             = 0;
85 
86 constexpr uint8_t kTxNumBcast = OPENTHREAD_CONFIG_MAC_TX_NUM_BCAST; ///< Num of times broadcast frame is tx.
87 
88 /**
89  * This type defines the function pointer called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
90  *
91  */
92 typedef otHandleActiveScanResult ActiveScanHandler;
93 
94 /**
95  * This type defines an Active Scan result.
96  *
97  */
98 typedef otActiveScanResult ActiveScanResult;
99 
100 /**
101  * This type defines the function pointer which is called during an Energy Scan when the scan result for a channel is
102  * ready or when the scan completes.
103  *
104  */
105 typedef otHandleEnergyScanResult EnergyScanHandler;
106 
107 /**
108  * This type defines an Energy Scan result.
109  *
110  */
111 typedef otEnergyScanResult EnergyScanResult;
112 
113 /**
114  * This class implements the IEEE 802.15.4 MAC.
115  *
116  */
117 class Mac : public InstanceLocator, private NonCopyable
118 {
119     friend class ot::Instance;
120 
121 public:
122     /**
123      * This constructor initializes the MAC object.
124      *
125      * @param[in]  aInstance  A reference to the OpenThread instance.
126      *
127      */
128     explicit Mac(Instance &aInstance);
129 
130     /**
131      * This method starts an IEEE 802.15.4 Active Scan.
132      *
133      * @param[in]  aScanChannels  A bit vector indicating which channels to scan. Zero is mapped to all channels.
134      * @param[in]  aScanDuration  The time in milliseconds to spend scanning each channel. Zero duration maps to
135      *                            default value `kScanDurationDefault` = 300 ms.
136      * @param[in]  aHandler       A pointer to a function that is called on receiving an IEEE 802.15.4 Beacon.
137      * @param[in]  aContext       A pointer to an arbitrary context (used when invoking `aHandler` callback).
138      *
139      * @retval kErrorNone  Successfully scheduled the Active Scan request.
140      * @retval kErrorBusy  Could not schedule the scan (a scan is ongoing or scheduled).
141      *
142      */
143     Error ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext);
144 
145     /**
146      * This method starts an IEEE 802.15.4 Energy Scan.
147      *
148      * @param[in]  aScanChannels     A bit vector indicating on which channels to scan. Zero is mapped to all channels.
149      * @param[in]  aScanDuration     The time in milliseconds to spend scanning each channel. If the duration is set to
150      *                               zero, a single RSSI sample will be taken per channel.
151      * @param[in]  aHandler          A pointer to a function called to pass on scan result or indicate scan completion.
152      * @param[in]  aContext          A pointer to an arbitrary context (used when invoking @p aHandler callback).
153      *
154      * @retval kErrorNone  Accepted the Energy Scan request.
155      * @retval kErrorBusy  Could not start the energy scan.
156      *
157      */
158     Error EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext);
159 
160     /**
161      * This method indicates the energy scan for the current channel is complete.
162      *
163      * @param[in]  aEnergyScanMaxRssi  The maximum RSSI encountered on the scanned channel.
164      *
165      */
166     void EnergyScanDone(int8_t aEnergyScanMaxRssi);
167 
168     /**
169      * This method indicates whether or not IEEE 802.15.4 Beacon transmissions are enabled.
170      *
171      * @retval TRUE   If IEEE 802.15.4 Beacon transmissions are enabled.
172      * @retval FALSE  If IEEE 802.15.4 Beacon transmissions are not enabled.
173      *
174      */
IsBeaconEnabled(void) const175     bool IsBeaconEnabled(void) const { return mBeaconsEnabled; }
176 
177     /**
178      * This method enables/disables IEEE 802.15.4 Beacon transmissions.
179      *
180      * @param[in]  aEnabled  TRUE to enable IEEE 802.15.4 Beacon transmissions, FALSE otherwise.
181      *
182      */
SetBeaconEnabled(bool aEnabled)183     void SetBeaconEnabled(bool aEnabled) { mBeaconsEnabled = aEnabled; }
184 
185     /**
186      * This method indicates whether or not rx-on-when-idle is enabled.
187      *
188      * @retval TRUE   If rx-on-when-idle is enabled.
189      * @retval FALSE  If rx-on-when-idle is not enabled.
190      */
GetRxOnWhenIdle(void) const191     bool GetRxOnWhenIdle(void) const { return mRxOnWhenIdle; }
192 
193     /**
194      * This method sets the rx-on-when-idle mode.
195      *
196      * @param[in]  aRxOnWhenIdle  The rx-on-when-idle mode.
197      *
198      */
199     void SetRxOnWhenIdle(bool aRxOnWhenIdle);
200 
201     /**
202      * This method requests a direct data frame transmission.
203      *
204      */
205     void RequestDirectFrameTransmission(void);
206 
207 #if OPENTHREAD_FTD
208     /**
209      * This method requests an indirect data frame transmission.
210      *
211      */
212     void RequestIndirectFrameTransmission(void);
213 
214 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
215     /**
216      * This method requests `Mac` to start a CSL tx operation after a delay of @p aDelay time.
217      *
218      * @param[in]  aDelay  Delay time for `Mac` to start a CSL tx, in units of milliseconds.
219      *
220      */
221     void RequestCslFrameTransmission(uint32_t aDelay);
222 #endif
223 
224 #endif
225 
226     /**
227      * This method requests transmission of a data poll (MAC Data Request) frame.
228      *
229      * @retval kErrorNone          Data poll transmission request is scheduled successfully.
230      * @retval kErrorAlready       MAC is busy sending earlier poll transmission request.
231      * @retval kErrorInvalidState  The MAC layer is not enabled.
232      *
233      */
234     Error RequestDataPollTransmission(void);
235 
236     /**
237      * This method returns a reference to the IEEE 802.15.4 Extended Address.
238      *
239      * @returns A pointer to the IEEE 802.15.4 Extended Address.
240      *
241      */
GetExtAddress(void) const242     const ExtAddress &GetExtAddress(void) const { return mLinks.GetExtAddress(); }
243 
244     /**
245      * This method sets the IEEE 802.15.4 Extended Address.
246      *
247      * @param[in]  aExtAddress  A reference to the IEEE 802.15.4 Extended Address.
248      *
249      */
SetExtAddress(const ExtAddress & aExtAddress)250     void SetExtAddress(const ExtAddress &aExtAddress) { mLinks.SetExtAddress(aExtAddress); }
251 
252     /**
253      * This method returns the IEEE 802.15.4 Short Address.
254      *
255      * @returns The IEEE 802.15.4 Short Address.
256      *
257      */
GetShortAddress(void) const258     ShortAddress GetShortAddress(void) const { return mLinks.GetShortAddress(); }
259 
260     /**
261      * This method sets the IEEE 802.15.4 Short Address.
262      *
263      * @param[in]  aShortAddress  The IEEE 802.15.4 Short Address.
264      *
265      */
SetShortAddress(ShortAddress aShortAddress)266     void SetShortAddress(ShortAddress aShortAddress) { mLinks.SetShortAddress(aShortAddress); }
267 
268     /**
269      * This method returns the IEEE 802.15.4 PAN Channel.
270      *
271      * @returns The IEEE 802.15.4 PAN Channel.
272      *
273      */
GetPanChannel(void) const274     uint8_t GetPanChannel(void) const { return mPanChannel; }
275 
276     /**
277      * This method sets the IEEE 802.15.4 PAN Channel.
278      *
279      * @param[in]  aChannel  The IEEE 802.15.4 PAN Channel.
280      *
281      * @retval kErrorNone          Successfully set the IEEE 802.15.4 PAN Channel.
282      * @retval kErrorInvalidArgs   The @p aChannel is not in the supported channel mask.
283      *
284      */
285     Error SetPanChannel(uint8_t aChannel);
286 
287     /**
288      * This method sets the temporary IEEE 802.15.4 radio channel.
289      *
290      * This method allows user to temporarily change the radio channel and use a different channel (during receive)
291      * instead of the PAN channel (from `SetPanChannel()`). A call to `ClearTemporaryChannel()` would clear the
292      * temporary channel and adopt the PAN channel again. The `SetTemporaryChannel()` can be used multiple times in row
293      * (before a call to `ClearTemporaryChannel()`) to change the temporary channel.
294      *
295      * @param[in]  aChannel            A IEEE 802.15.4 channel.
296      *
297      * @retval kErrorNone          Successfully set the temporary channel
298      * @retval kErrorInvalidArgs   The @p aChannel is not in the supported channel mask.
299      *
300      */
301     Error SetTemporaryChannel(uint8_t aChannel);
302 
303     /**
304      * This method clears the use of a previously set temporary channel and adopts the PAN channel.
305      *
306      */
307     void ClearTemporaryChannel(void);
308 
309     /**
310      * This method returns the supported channel mask.
311      *
312      * @returns The supported channel mask.
313      *
314      */
GetSupportedChannelMask(void) const315     const ChannelMask &GetSupportedChannelMask(void) const { return mSupportedChannelMask; }
316 
317     /**
318      * This method sets the supported channel mask
319      *
320      * @param[in] aMask   The supported channel mask.
321      *
322      */
323     void SetSupportedChannelMask(const ChannelMask &aMask);
324 
325     /**
326      * This method returns the IEEE 802.15.4 Network Name.
327      *
328      * @returns The IEEE 802.15.4 Network Name.
329      *
330      */
GetNetworkName(void) const331     const NetworkName &GetNetworkName(void) const { return mNetworkName; }
332 
333     /**
334      * This method sets the IEEE 802.15.4 Network Name.
335      *
336      * @param[in]  aNameString   A pointer to a string character array. Must be null terminated.
337      *
338      * @retval kErrorNone          Successfully set the IEEE 802.15.4 Network Name.
339      * @retval kErrorInvalidArgs   Given name is too long.
340      *
341      */
342     Error SetNetworkName(const char *aNameString);
343 
344     /**
345      * This method sets the IEEE 802.15.4 Network Name.
346      *
347      * @param[in]  aNameData     A name data (pointer to char buffer and length).
348      *
349      * @retval kErrorNone          Successfully set the IEEE 802.15.4 Network Name.
350      * @retval kErrorInvalidArgs   Given name is too long.
351      *
352      */
353     Error SetNetworkName(const NameData &aNameData);
354 
355 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
356     /**
357      * This method returns the Thread Domain Name.
358      *
359      * @returns The Thread Domain Name.
360      *
361      */
GetDomainName(void) const362     const DomainName &GetDomainName(void) const { return mDomainName; }
363 
364     /**
365      * This method sets the Thread Domain Name.
366      *
367      * @param[in]  aNameString   A pointer to a string character array. Must be null terminated.
368      *
369      * @retval kErrorNone          Successfully set the Thread Domain Name.
370      * @retval kErrorInvalidArgs   Given name is too long.
371      *
372      */
373     Error SetDomainName(const char *aNameString);
374 
375     /**
376      * This method sets the Thread Domain Name.
377      *
378      * @param[in]  aNameData     A name data (pointer to char buffer and length).
379      *
380      * @retval kErrorNone          Successfully set the Thread Domain Name.
381      * @retval kErrorInvalidArgs   Given name is too long.
382      *
383      */
384     Error SetDomainName(const NameData &aNameData);
385 #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
386 
387     /**
388      * This method returns the IEEE 802.15.4 PAN ID.
389      *
390      * @returns The IEEE 802.15.4 PAN ID.
391      *
392      */
GetPanId(void) const393     PanId GetPanId(void) const { return mPanId; }
394 
395     /**
396      * This method sets the IEEE 802.15.4 PAN ID.
397      *
398      * @param[in]  aPanId  The IEEE 802.15.4 PAN ID.
399      *
400      */
401     void SetPanId(PanId aPanId);
402 
403     /**
404      * This method returns the IEEE 802.15.4 Extended PAN Identifier.
405      *
406      * @returns The IEEE 802.15.4 Extended PAN Identifier.
407      *
408      */
GetExtendedPanId(void) const409     const ExtendedPanId &GetExtendedPanId(void) const { return mExtendedPanId; }
410 
411     /**
412      * This method sets the IEEE 802.15.4 Extended PAN Identifier.
413      *
414      * @param[in]  aExtendedPanId  The IEEE 802.15.4 Extended PAN Identifier.
415      *
416      */
417     void SetExtendedPanId(const ExtendedPanId &aExtendedPanId);
418 
419     /**
420      * This method returns the maximum number of frame retries during direct transmission.
421      *
422      * @returns The maximum number of retries during direct transmission.
423      *
424      */
GetMaxFrameRetriesDirect(void) const425     uint8_t GetMaxFrameRetriesDirect(void) const { return mMaxFrameRetriesDirect; }
426 
427     /**
428      * This method sets the maximum number of frame retries during direct transmission.
429      *
430      * @param[in]  aMaxFrameRetriesDirect  The maximum number of retries during direct transmission.
431      *
432      */
SetMaxFrameRetriesDirect(uint8_t aMaxFrameRetriesDirect)433     void SetMaxFrameRetriesDirect(uint8_t aMaxFrameRetriesDirect) { mMaxFrameRetriesDirect = aMaxFrameRetriesDirect; }
434 
435 #if OPENTHREAD_FTD
436     /**
437      * This method returns the maximum number of frame retries during indirect transmission.
438      *
439      * @returns The maximum number of retries during indirect transmission.
440      *
441      */
GetMaxFrameRetriesIndirect(void) const442     uint8_t GetMaxFrameRetriesIndirect(void) const { return mMaxFrameRetriesIndirect; }
443 
444     /**
445      * This method sets the maximum number of frame retries during indirect transmission.
446      *
447      * @param[in]  aMaxFrameRetriesIndirect  The maximum number of retries during indirect transmission.
448      *
449      */
SetMaxFrameRetriesIndirect(uint8_t aMaxFrameRetriesIndirect)450     void SetMaxFrameRetriesIndirect(uint8_t aMaxFrameRetriesIndirect)
451     {
452         mMaxFrameRetriesIndirect = aMaxFrameRetriesIndirect;
453     }
454 #endif
455 
456     /**
457      * This method is called to handle a received frame.
458      *
459      * @param[in]  aFrame  A pointer to the received frame, or nullptr if the receive operation was aborted.
460      * @param[in]  aError  kErrorNone when successfully received a frame,
461      *                     kErrorAbort when reception was aborted and a frame was not received.
462      *
463      */
464     void HandleReceivedFrame(RxFrame *aFrame, Error aError);
465 
466     /**
467      * This method records CCA status (success/failure) for a frame transmission attempt.
468      *
469      * @param[in] aCcaSuccess   TRUE if the CCA succeeded, FALSE otherwise.
470      * @param[in] aChannel      The channel on which CCA was performed.
471      *
472      */
473     void RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel);
474 
475     /**
476      * This method records the status of a frame transmission attempt, updating MAC counters.
477      *
478      * Unlike `HandleTransmitDone` which is called after all transmission attempts of frame to indicate final status
479      * of a frame transmission request, this method is invoked on all frame transmission attempts.
480      *
481      * @param[in] aFrame      The transmitted frame.
482      * @param[in] aAckFrame   A pointer to the ACK frame, or nullptr if no ACK was received.
483      * @param[in] aError      kErrorNone when the frame was transmitted successfully,
484      *                        kErrorNoAck when the frame was transmitted but no ACK was received,
485      *                        kErrorChannelAccessFailure tx failed due to activity on the channel,
486      *                        kErrorAbort when transmission was aborted for other reasons.
487      * @param[in] aRetryCount Indicates number of transmission retries for this frame.
488      * @param[in] aWillRetx   Indicates whether frame will be retransmitted or not. This is applicable only
489      *                        when there was an error in transmission (i.e., `aError` is not NONE).
490      *
491      */
492     void RecordFrameTransmitStatus(const TxFrame &aFrame,
493                                    const RxFrame *aAckFrame,
494                                    Error          aError,
495                                    uint8_t        aRetryCount,
496                                    bool           aWillRetx);
497 
498     /**
499      * This method is called to handle transmit events.
500      *
501      * @param[in]  aFrame      The frame that was transmitted.
502      * @param[in]  aAckFrame   A pointer to the ACK frame, nullptr if no ACK was received.
503      * @param[in]  aError      kErrorNone when the frame was transmitted successfully,
504      *                         kErrorNoAck when the frame was transmitted but no ACK was received,
505      *                         kErrorChannelAccessFailure when the tx failed due to activity on the channel,
506      *                         kErrorAbort when transmission was aborted for other reasons.
507      *
508      */
509     void HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
510 
511     /**
512      * This method returns if an active scan is in progress.
513      *
514      */
IsActiveScanInProgress(void) const515     bool IsActiveScanInProgress(void) const { return (mOperation == kOperationActiveScan) || (mPendingActiveScan); }
516 
517     /**
518      * This method returns if an energy scan is in progress.
519      *
520      */
IsEnergyScanInProgress(void) const521     bool IsEnergyScanInProgress(void) const { return (mOperation == kOperationEnergyScan) || (mPendingEnergyScan); }
522 
523 #if OPENTHREAD_FTD
524     /**
525      * This method indicates whether the MAC layer is performing an indirect transmission (in middle of a tx).
526      *
527      * @returns TRUE if in middle of an indirect transmission, FALSE otherwise.
528      *
529      */
IsPerformingIndirectTransmit(void) const530     bool IsPerformingIndirectTransmit(void) const { return (mOperation == kOperationTransmitDataIndirect); }
531 #endif
532 
533     /**
534      * This method returns if the MAC layer is in transmit state.
535      *
536      * The MAC layer is in transmit state during CSMA/CA, CCA, transmission of Data, Beacon or Data Request frames and
537      * receiving of ACK frames. The MAC layer is not in transmit state during transmission of ACK frames or Beacon
538      * Requests.
539      *
540      */
541     bool IsInTransmitState(void) const;
542 
543     /**
544      * This method registers a callback to provide received raw IEEE 802.15.4 frames.
545      *
546      * @param[in]  aPcapCallback     A pointer to a function that is called when receiving an IEEE 802.15.4 link frame
547      * or nullptr to disable the callback.
548      * @param[in]  aCallbackContext  A pointer to application-specific context.
549      *
550      */
SetPcapCallback(otLinkPcapCallback aPcapCallback,void * aCallbackContext)551     void SetPcapCallback(otLinkPcapCallback aPcapCallback, void *aCallbackContext)
552     {
553         mLinks.SetPcapCallback(aPcapCallback, aCallbackContext);
554     }
555 
556     /**
557      * This method indicates whether or not promiscuous mode is enabled at the link layer.
558      *
559      * @retval true   Promiscuous mode is enabled.
560      * @retval false  Promiscuous mode is not enabled.
561      *
562      */
IsPromiscuous(void) const563     bool IsPromiscuous(void) const { return mPromiscuous; }
564 
565     /**
566      * This method enables or disables the link layer promiscuous mode.
567      *
568      * Promiscuous mode keeps the receiver enabled, overriding the value of mRxOnWhenIdle.
569      *
570      * @param[in]  aPromiscuous  true to enable promiscuous mode, or false otherwise.
571      *
572      */
573     void SetPromiscuous(bool aPromiscuous);
574 
575     /**
576      * This method resets mac counters
577      *
578      */
ResetCounters(void)579     void ResetCounters(void) { memset(&mCounters, 0, sizeof(mCounters)); }
580 
581     /**
582      * This method returns the MAC counter.
583      *
584      * @returns A reference to the MAC counter.
585      *
586      */
GetCounters(void)587     otMacCounters &GetCounters(void) { return mCounters; }
588 
589 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
590     /**
591      * This method returns the MAC retry histogram for direct transmission.
592      *
593      * @param[out]  aNumberOfEntries    A reference to where the size of returned histogram array is placed.
594      *
595      * @returns     A pointer to the histogram of retries (in a form of an array).
596      *              The n-th element indicates that the packet has been sent with n-th retry.
597      *
598      */
599     const uint32_t *GetDirectRetrySuccessHistogram(uint8_t &aNumberOfEntries);
600 
601 #if OPENTHREAD_FTD
602     /**
603      * This method returns the MAC retry histogram for indirect transmission.
604      *
605      * @param[out]  aNumberOfEntries    A reference to where the size of returned histogram array is placed.
606      *
607      * @returns     A pointer to the histogram of retries (in a form of an array).
608      *              The n-th element indicates that the packet has been sent with n-th retry.
609      *
610      */
611     const uint32_t *GetIndirectRetrySuccessHistogram(uint8_t &aNumberOfEntries);
612 #endif
613 
614     /**
615      * This method resets MAC retry histogram.
616      *
617      */
618     void ResetRetrySuccessHistogram(void);
619 #endif // OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
620 
621     /**
622      * This method returns the noise floor value (currently use the radio receive sensitivity value).
623      *
624      * @returns The noise floor value in dBm.
625      *
626      */
GetNoiseFloor(void)627     int8_t GetNoiseFloor(void) { return mLinks.GetNoiseFloor(); }
628 
629     /**
630      * This method returns the current CCA (Clear Channel Assessment) failure rate.
631      *
632      * The rate is maintained over a window of (roughly) last `OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW`
633      * frame transmissions.
634      *
635      * @returns The CCA failure rate with maximum value `0xffff` corresponding to 100% failure rate.
636      *
637      */
GetCcaFailureRate(void) const638     uint16_t GetCcaFailureRate(void) const { return mCcaSuccessRateTracker.GetFailureRate(); }
639 
640     /**
641      * This method Starts/Stops the Link layer. It may only be used when the Netif Interface is down.
642      *
643      * @param[in]  aEnable The requested State for the MAC layer. true - Start, false - Stop.
644      *
645      */
SetEnabled(bool aEnable)646     void SetEnabled(bool aEnable) { mEnabled = aEnable; }
647 
648     /**
649      * This method indicates whether or not the link layer is enabled.
650      *
651      * @retval true   Link layer is enabled.
652      * @retval false  Link layer is not enabled.
653      *
654      */
IsEnabled(void) const655     bool IsEnabled(void) const { return mEnabled; }
656 
657 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
658     /**
659      * This method gets the CSL channel.
660      *
661      * @returns CSL channel.
662      *
663      */
GetCslChannel(void) const664     uint8_t GetCslChannel(void) const { return mLinks.GetSubMac().GetCslChannel(); }
665 
666     /**
667      * This method sets the CSL channel.
668      *
669      * @param[in]  aChannel  The CSL channel.
670      *
671      */
672     void SetCslChannel(uint8_t aChannel);
673 
674     /**
675      * This method indicates if CSL channel has been explicitly specified by the upper layer.
676      *
677      * @returns If CSL channel has been specified.
678      *
679      */
IsCslChannelSpecified(void) const680     bool IsCslChannelSpecified(void) const { return mLinks.GetSubMac().IsCslChannelSpecified(); }
681 
682     /**
683      * This method gets the CSL period.
684      *
685      * @returns CSL period in units of 10 symbols.
686      *
687      */
GetCslPeriod(void) const688     uint16_t GetCslPeriod(void) const { return mLinks.GetSubMac().GetCslPeriod(); }
689 
690     /**
691      * This method sets the CSL period.
692      *
693      * @param[in]  aPeriod  The CSL period in 10 symbols.
694      *
695      */
696     void SetCslPeriod(uint16_t aPeriod);
697 
698     /**
699      * This method indicates whether CSL is started at the moment.
700      *
701      * @retval TRUE   If CSL is enabled.
702      * @retval FALSE  If CSL is not enabled.
703      *
704      */
705     bool IsCslEnabled(void) const;
706 
707     /**
708      * This method indicates whether Link is capable of starting CSL.
709      *
710      * @retval TRUE   If Link is capable of starting CSL.
711      * @retval FALSE  If link is not capable of starting CSL.
712      *
713      */
714     bool IsCslCapable(void) const;
715 
716     /**
717      * This method returns CSL parent clock accuracy, in ± ppm.
718      *
719      * @retval CSL parent clock accuracy, in ± ppm.
720      *
721      */
GetCslParentClockAccuracy(void) const722     uint8_t GetCslParentClockAccuracy(void) const { return mLinks.GetSubMac().GetCslParentClockAccuracy(); }
723 
724     /**
725      * This method sets CSL parent clock accuracy, in ± ppm.
726      *
727      * @param[in] aCslParentAccuracy CSL parent clock accuracy, in ± ppm.
728      *
729      */
SetCslParentClockAccuracy(uint8_t aCslParentAccuracy)730     void SetCslParentClockAccuracy(uint8_t aCslParentAccuracy)
731     {
732         mLinks.GetSubMac().SetCslParentClockAccuracy(aCslParentAccuracy);
733     }
734 
735     /**
736      * This method returns CSL parent uncertainty, in ±10 us units.
737      *
738      * @retval CSL parent uncertainty, in ±10 us units.
739      *
740      */
GetCslParentUncertainty(void) const741     uint8_t GetCslParentUncertainty(void) const { return mLinks.GetSubMac().GetCslParentUncertainty(); }
742 
743     /**
744      * This method returns CSL parent uncertainty, in ±10 us units.
745      *
746      * @param[in] aCslParentUncert  CSL parent uncertainty, in ±10 us units.
747      *
748      */
SetCslParentUncertainty(uint8_t aCslParentUncert)749     void SetCslParentUncertainty(uint8_t aCslParentUncert)
750     {
751         mLinks.GetSubMac().SetCslParentUncertainty(aCslParentUncert);
752     }
753 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
754 
755 private:
756     static constexpr int8_t   kInvalidRssiValue  = SubMac::kInvalidRssiValue;
757     static constexpr uint16_t kMaxCcaSampleCount = OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW;
758 
759     enum Operation : uint8_t
760     {
761         kOperationIdle = 0,
762         kOperationActiveScan,
763         kOperationEnergyScan,
764         kOperationTransmitBeacon,
765         kOperationTransmitDataDirect,
766         kOperationTransmitPoll,
767         kOperationWaitingForData,
768 #if OPENTHREAD_FTD
769         kOperationTransmitDataIndirect,
770 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
771         kOperationTransmitDataCsl,
772 #endif
773 #endif
774     };
775 
776 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
777     struct RetryHistogram
778     {
779         /**
780          * Histogram of number of retries for a single direct packet until success
781          * [0 retry: packet count, 1 retry: packet count, 2 retry : packet count ...
782          *  until max retry limit: packet count]
783          *
784          *  The size of the array is OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT.
785          */
786         uint32_t mTxDirectRetrySuccess[OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT];
787 
788         /**
789          * Histogram of number of retries for a single indirect packet until success
790          * [0 retry: packet count, 1 retry: packet count, 2 retry : packet count ...
791          *  until max retry limit: packet count]
792          *
793          *  The size of the array is OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT.
794          */
795         uint32_t mTxIndirectRetrySuccess[OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT];
796     };
797 #endif // OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
798 
799     Error ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neighbor *aNeighbor);
800     void  ProcessTransmitSecurity(TxFrame &aFrame);
801 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
802     Error ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame);
803 #endif
804 
805     void     UpdateIdleMode(void);
806     void     StartOperation(Operation aOperation);
807     void     FinishOperation(void);
808     void     PerformNextOperation(void);
809     TxFrame *PrepareBeaconRequest(void);
810     TxFrame *PrepareBeacon(void);
811     bool     ShouldSendBeacon(void) const;
812     bool     IsJoinable(void) const;
813     void     BeginTransmit(void);
814     bool     HandleMacCommand(RxFrame &aFrame);
815 
816     static void HandleTimer(Timer &aTimer);
817     void        HandleTimer(void);
818     static void HandleOperationTask(Tasklet &aTasklet);
819 
820     void  Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration);
821     Error UpdateScanChannel(void);
822     void  PerformActiveScan(void);
823     void  ReportActiveScanResult(const RxFrame *aBeaconFrame);
824     Error ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveScanResult &aResult);
825     void  PerformEnergyScan(void);
826     void  ReportEnergyScanResult(int8_t aRssi);
827     Error SignalNetworkNameChange(Error aError);
828 
829     void LogFrameRxFailure(const RxFrame *aFrame, Error aError) const;
830     void LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) const;
831     void LogBeacon(const char *aActionText, const BeaconPayload &aBeaconPayload) const;
832 
833 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
834     uint8_t GetTimeIeOffset(const Frame &aFrame);
835 #endif
836 
837 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
838     void ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr);
839 #endif
840 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
841     void ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor);
842 #endif
843     static const char *OperationToString(Operation aOperation);
844 
845     static const otMacKey        sMode2Key;
846     static const otExtAddress    sMode2ExtAddress;
847     static const otExtendedPanId sExtendedPanidInit;
848     static const char            sNetworkNameInit[];
849     static const char            sDomainNameInit[];
850 
851     bool mEnabled : 1;
852     bool mPendingActiveScan : 1;
853     bool mPendingEnergyScan : 1;
854     bool mPendingTransmitBeacon : 1;
855     bool mPendingTransmitDataDirect : 1;
856 #if OPENTHREAD_FTD
857     bool mPendingTransmitDataIndirect : 1;
858 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
859     bool mPendingTransmitDataCsl : 1;
860 #endif
861 #endif
862     bool mPendingTransmitPoll : 1;
863     bool mPendingWaitingForData : 1;
864     bool mShouldTxPollBeforeData : 1;
865     bool mRxOnWhenIdle : 1;
866     bool mPromiscuous : 1;
867     bool mBeaconsEnabled : 1;
868     bool mUsingTemporaryChannel : 1;
869 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
870     bool mShouldDelaySleep : 1;
871     bool mDelayingSleep : 1;
872 #endif
873 
874     Operation     mOperation;
875     uint8_t       mBeaconSequence;
876     uint8_t       mDataSequence;
877     uint8_t       mBroadcastTransmitCount;
878     PanId         mPanId;
879     uint8_t       mPanChannel;
880     uint8_t       mRadioChannel;
881     ChannelMask   mSupportedChannelMask;
882     ExtendedPanId mExtendedPanId;
883     NetworkName   mNetworkName;
884 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
885     DomainName mDomainName;
886 #endif
887     uint8_t     mScanChannel;
888     uint16_t    mScanDuration;
889     ChannelMask mScanChannelMask;
890     uint8_t     mMaxFrameRetriesDirect;
891 #if OPENTHREAD_FTD
892     uint8_t mMaxFrameRetriesIndirect;
893 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
894     TimeMilli mCslTxFireTime;
895 #endif
896 #endif
897 
898     union
899     {
900         ActiveScanHandler mActiveScanHandler;
901         EnergyScanHandler mEnergyScanHandler;
902     };
903 
904     void *mScanHandlerContext;
905 
906     Links              mLinks;
907     Tasklet            mOperationTask;
908     TimerMilli         mTimer;
909     otMacCounters      mCounters;
910     uint32_t           mKeyIdMode2FrameCounter;
911     SuccessRateTracker mCcaSuccessRateTracker;
912     uint16_t           mCcaSampleCount;
913 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
914     RetryHistogram mRetryHistogram;
915 #endif
916 
917 #if OPENTHREAD_CONFIG_MULTI_RADIO
918     RadioTypes mTxPendingRadioLinks;
919     RadioTypes mTxBeaconRadioLinks;
920     Error      mTxError;
921 #endif
922 
923 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
924     Filter mFilter;
925 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
926 };
927 
928 /**
929  * @}
930  *
931  */
932 
933 } // namespace Mac
934 } // namespace ot
935 
936 #endif // MAC_HPP_
937