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 implements the subset of IEEE 802.15.4 primitives required for Thread.
32  */
33 
34 #include "mac.hpp"
35 
36 #include <stdio.h>
37 
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/encoding.hpp"
41 #include "common/instance.hpp"
42 #include "common/locator_getters.hpp"
43 #include "common/logging.hpp"
44 #include "common/random.hpp"
45 #include "common/string.hpp"
46 #include "crypto/aes_ccm.hpp"
47 #include "crypto/sha256.hpp"
48 #include "mac/mac_frame.hpp"
49 #include "radio/radio.hpp"
50 #include "thread/child_table.hpp"
51 #include "thread/link_quality.hpp"
52 #include "thread/mle_router.hpp"
53 #include "thread/thread_netif.hpp"
54 #include "thread/topology.hpp"
55 
56 namespace ot {
57 namespace Mac {
58 
59 const otMacKey Mac::sMode2Key = {
60     {0x78, 0x58, 0x16, 0x86, 0xfd, 0xb4, 0x58, 0x0f, 0xb0, 0x92, 0x54, 0x6a, 0xec, 0xbd, 0x15, 0x66}};
61 
62 const otExtAddress Mac::sMode2ExtAddress = {
63     {0x35, 0x06, 0xfe, 0xb8, 0x23, 0xd4, 0x87, 0x12},
64 };
65 
66 const otExtendedPanId Mac::sExtendedPanidInit = {
67     {0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0xca, 0xfe},
68 };
69 
70 const char Mac::sNetworkNameInit[] = "OpenThread";
71 
72 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
73 const char Mac::sDomainNameInit[] = "DefaultDomain";
74 #endif
75 
Mac(Instance & aInstance)76 Mac::Mac(Instance &aInstance)
77     : InstanceLocator(aInstance)
78     , mEnabled(false)
79     , mPendingActiveScan(false)
80     , mPendingEnergyScan(false)
81     , mPendingTransmitBeacon(false)
82     , mPendingTransmitDataDirect(false)
83 #if OPENTHREAD_FTD
84     , mPendingTransmitDataIndirect(false)
85 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
86     , mPendingTransmitDataCsl(false)
87 #endif
88 #endif
89     , mPendingTransmitPoll(false)
90     , mPendingWaitingForData(false)
91     , mShouldTxPollBeforeData(false)
92     , mRxOnWhenIdle(false)
93     , mPromiscuous(false)
94     , mBeaconsEnabled(false)
95     , mUsingTemporaryChannel(false)
96 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
97     , mShouldDelaySleep(false)
98     , mDelayingSleep(false)
99 #endif
100     , mOperation(kOperationIdle)
101     , mBeaconSequence(Random::NonCrypto::GetUint8())
102     , mDataSequence(Random::NonCrypto::GetUint8())
103     , mBroadcastTransmitCount(0)
104     , mPanId(kPanIdBroadcast)
105     , mPanChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
106     , mRadioChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
107     , mSupportedChannelMask(Get<Radio>().GetSupportedChannelMask())
108     , mScanChannel(Radio::kChannelMin)
109     , mScanDuration(0)
110     , mMaxFrameRetriesDirect(kDefaultMaxFrameRetriesDirect)
111 #if OPENTHREAD_FTD
112     , mMaxFrameRetriesIndirect(kDefaultMaxFrameRetriesIndirect)
113 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
114     , mCslTxFireTime(TimeMilli::kMaxDuration)
115 #endif
116 #endif
117     , mActiveScanHandler(nullptr) // Initialize `mActiveScanHandler` and `mEnergyScanHandler` union
118     , mScanHandlerContext(nullptr)
119     , mLinks(aInstance)
120     , mOperationTask(aInstance, Mac::HandleOperationTask)
121     , mTimer(aInstance, Mac::HandleTimer)
122     , mKeyIdMode2FrameCounter(0)
123     , mCcaSampleCount(0)
124 #if OPENTHREAD_CONFIG_MULTI_RADIO
125     , mTxError(kErrorNone)
126 #endif
127 {
128     ExtAddress randomExtAddress;
129 
130     randomExtAddress.GenerateRandom();
131 
132     mCcaSuccessRateTracker.Clear();
133     ResetCounters();
134     mExtendedPanId.Clear();
135 
136     SetEnabled(true);
137     mLinks.Enable();
138 
139     Get<KeyManager>().UpdateKeyMaterial();
140     SetExtendedPanId(static_cast<const ExtendedPanId &>(sExtendedPanidInit));
141     IgnoreError(SetNetworkName(sNetworkNameInit));
142 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
143     IgnoreError(SetDomainName(sDomainNameInit));
144 #endif
145     SetPanId(mPanId);
146     SetExtAddress(randomExtAddress);
147     SetShortAddress(GetShortAddress());
148 }
149 
ActiveScan(uint32_t aScanChannels,uint16_t aScanDuration,ActiveScanHandler aHandler,void * aContext)150 Error Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext)
151 {
152     Error error = kErrorNone;
153 
154     VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
155     VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = kErrorBusy);
156 
157     mActiveScanHandler  = aHandler;
158     mScanHandlerContext = aContext;
159 
160     if (aScanDuration == 0)
161     {
162         aScanDuration = kScanDurationDefault;
163     }
164 
165     Scan(kOperationActiveScan, aScanChannels, aScanDuration);
166 
167 exit:
168     return error;
169 }
170 
EnergyScan(uint32_t aScanChannels,uint16_t aScanDuration,EnergyScanHandler aHandler,void * aContext)171 Error Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext)
172 {
173     Error error = kErrorNone;
174 
175     VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
176     VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = kErrorBusy);
177 
178     mEnergyScanHandler  = aHandler;
179     mScanHandlerContext = aContext;
180 
181     Scan(kOperationEnergyScan, aScanChannels, aScanDuration);
182 
183 exit:
184     return error;
185 }
186 
Scan(Operation aScanOperation,uint32_t aScanChannels,uint16_t aScanDuration)187 void Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration)
188 {
189     mScanDuration = aScanDuration;
190     mScanChannel  = ChannelMask::kChannelIteratorFirst;
191 
192     if (aScanChannels == 0)
193     {
194         aScanChannels = GetSupportedChannelMask().GetMask();
195     }
196 
197     mScanChannelMask.SetMask(aScanChannels);
198     mScanChannelMask.Intersect(mSupportedChannelMask);
199     StartOperation(aScanOperation);
200 }
201 
IsInTransmitState(void) const202 bool Mac::IsInTransmitState(void) const
203 {
204     bool retval = false;
205 
206     switch (mOperation)
207     {
208     case kOperationTransmitDataDirect:
209 #if OPENTHREAD_FTD
210     case kOperationTransmitDataIndirect:
211 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
212     case kOperationTransmitDataCsl:
213 #endif
214 #endif
215     case kOperationTransmitBeacon:
216     case kOperationTransmitPoll:
217         retval = true;
218         break;
219 
220     case kOperationIdle:
221     case kOperationActiveScan:
222     case kOperationEnergyScan:
223     case kOperationWaitingForData:
224         retval = false;
225         break;
226     }
227 
228     return retval;
229 }
230 
ConvertBeaconToActiveScanResult(const RxFrame * aBeaconFrame,ActiveScanResult & aResult)231 Error Mac::ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveScanResult &aResult)
232 {
233     Error                error = kErrorNone;
234     Address              address;
235     const Beacon *       beacon        = nullptr;
236     const BeaconPayload *beaconPayload = nullptr;
237     uint16_t             payloadLength;
238 
239     memset(&aResult, 0, sizeof(ActiveScanResult));
240 
241     VerifyOrExit(aBeaconFrame != nullptr, error = kErrorInvalidArgs);
242 
243     VerifyOrExit(aBeaconFrame->GetType() == Frame::kFcfFrameBeacon, error = kErrorParse);
244     SuccessOrExit(error = aBeaconFrame->GetSrcAddr(address));
245     VerifyOrExit(address.IsExtended(), error = kErrorParse);
246     aResult.mExtAddress = address.GetExtended();
247 
248     if (kErrorNone != aBeaconFrame->GetSrcPanId(aResult.mPanId))
249     {
250         IgnoreError(aBeaconFrame->GetDstPanId(aResult.mPanId));
251     }
252 
253     aResult.mChannel = aBeaconFrame->GetChannel();
254     aResult.mRssi    = aBeaconFrame->GetRssi();
255     aResult.mLqi     = aBeaconFrame->GetLqi();
256 
257     payloadLength = aBeaconFrame->GetPayloadLength();
258 
259     beacon        = reinterpret_cast<const Beacon *>(aBeaconFrame->GetPayload());
260     beaconPayload = reinterpret_cast<const BeaconPayload *>(beacon->GetPayload());
261 
262     if ((payloadLength >= (sizeof(*beacon) + sizeof(*beaconPayload))) && beacon->IsValid() && beaconPayload->IsValid())
263     {
264         aResult.mVersion    = beaconPayload->GetProtocolVersion();
265         aResult.mIsJoinable = beaconPayload->IsJoiningPermitted();
266         aResult.mIsNative   = beaconPayload->IsNative();
267         IgnoreError(static_cast<NetworkName &>(aResult.mNetworkName).Set(beaconPayload->GetNetworkName()));
268         VerifyOrExit(IsValidUtf8String(aResult.mNetworkName.m8), error = kErrorParse);
269         aResult.mExtendedPanId = beaconPayload->GetExtendedPanId();
270     }
271 
272     LogBeacon("Received", *beaconPayload);
273 
274 exit:
275     return error;
276 }
277 
UpdateScanChannel(void)278 Error Mac::UpdateScanChannel(void)
279 {
280     Error error;
281 
282     VerifyOrExit(IsEnabled(), error = kErrorAbort);
283 
284     error = mScanChannelMask.GetNextChannel(mScanChannel);
285 
286 exit:
287     return error;
288 }
289 
PerformActiveScan(void)290 void Mac::PerformActiveScan(void)
291 {
292     if (UpdateScanChannel() == kErrorNone)
293     {
294         // If there are more channels to scan, send the beacon request.
295         BeginTransmit();
296     }
297     else
298     {
299         mLinks.SetPanId(mPanId);
300         FinishOperation();
301         ReportActiveScanResult(nullptr);
302         PerformNextOperation();
303     }
304 }
305 
ReportActiveScanResult(const RxFrame * aBeaconFrame)306 void Mac::ReportActiveScanResult(const RxFrame *aBeaconFrame)
307 {
308     VerifyOrExit(mActiveScanHandler != nullptr);
309 
310     if (aBeaconFrame == nullptr)
311     {
312         mActiveScanHandler(nullptr, mScanHandlerContext);
313     }
314     else
315     {
316         ActiveScanResult result;
317 
318         SuccessOrExit(ConvertBeaconToActiveScanResult(aBeaconFrame, result));
319         mActiveScanHandler(&result, mScanHandlerContext);
320     }
321 
322 exit:
323     return;
324 }
325 
PerformEnergyScan(void)326 void Mac::PerformEnergyScan(void)
327 {
328     Error error = kErrorNone;
329 
330     SuccessOrExit(error = UpdateScanChannel());
331 
332     if (mScanDuration == 0)
333     {
334         while (true)
335         {
336             mLinks.Receive(mScanChannel);
337             ReportEnergyScanResult(mLinks.GetRssi());
338             SuccessOrExit(error = UpdateScanChannel());
339         }
340     }
341     else
342     {
343         error = mLinks.EnergyScan(mScanChannel, mScanDuration);
344     }
345 
346 exit:
347 
348     if (error != kErrorNone)
349     {
350         FinishOperation();
351 
352         if (mEnergyScanHandler != nullptr)
353         {
354             mEnergyScanHandler(nullptr, mScanHandlerContext);
355         }
356 
357         PerformNextOperation();
358     }
359 }
360 
ReportEnergyScanResult(int8_t aRssi)361 void Mac::ReportEnergyScanResult(int8_t aRssi)
362 {
363     EnergyScanResult result;
364 
365     VerifyOrExit((mEnergyScanHandler != nullptr) && (aRssi != kInvalidRssiValue));
366 
367     result.mChannel = mScanChannel;
368     result.mMaxRssi = aRssi;
369 
370     mEnergyScanHandler(&result, mScanHandlerContext);
371 
372 exit:
373     return;
374 }
375 
EnergyScanDone(int8_t aEnergyScanMaxRssi)376 void Mac::EnergyScanDone(int8_t aEnergyScanMaxRssi)
377 {
378     ReportEnergyScanResult(aEnergyScanMaxRssi);
379     PerformEnergyScan();
380 }
381 
SetRxOnWhenIdle(bool aRxOnWhenIdle)382 void Mac::SetRxOnWhenIdle(bool aRxOnWhenIdle)
383 {
384     VerifyOrExit(mRxOnWhenIdle != aRxOnWhenIdle);
385 
386     mRxOnWhenIdle = aRxOnWhenIdle;
387 
388     // If the new value for `mRxOnWhenIdle` is `true` (i.e., radio should
389     // remain in Rx while idle) we stop any ongoing or pending `WaitingForData`
390     // operation (since this operation only applies to sleepy devices).
391 
392     if (mRxOnWhenIdle)
393     {
394         if (mPendingWaitingForData)
395         {
396             mTimer.Stop();
397             mPendingWaitingForData = false;
398         }
399 
400         if (mOperation == kOperationWaitingForData)
401         {
402             mTimer.Stop();
403             FinishOperation();
404             mOperationTask.Post();
405         }
406 
407 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
408         mDelayingSleep    = false;
409         mShouldDelaySleep = false;
410 #endif
411     }
412 
413     mLinks.SetRxOnWhenBackoff(mRxOnWhenIdle || mPromiscuous);
414     UpdateIdleMode();
415 
416 exit:
417     return;
418 }
419 
SetPanChannel(uint8_t aChannel)420 Error Mac::SetPanChannel(uint8_t aChannel)
421 {
422     Error error = kErrorNone;
423 
424     VerifyOrExit(mSupportedChannelMask.ContainsChannel(aChannel), error = kErrorInvalidArgs);
425 
426     SuccessOrExit(Get<Notifier>().Update(mPanChannel, aChannel, kEventThreadChannelChanged));
427 
428     mCcaSuccessRateTracker.Clear();
429 
430     VerifyOrExit(!mUsingTemporaryChannel);
431 
432     mRadioChannel = mPanChannel;
433 
434     UpdateIdleMode();
435 
436 exit:
437     return error;
438 }
439 
SetTemporaryChannel(uint8_t aChannel)440 Error Mac::SetTemporaryChannel(uint8_t aChannel)
441 {
442     Error error = kErrorNone;
443 
444     VerifyOrExit(mSupportedChannelMask.ContainsChannel(aChannel), error = kErrorInvalidArgs);
445 
446     mUsingTemporaryChannel = true;
447     mRadioChannel          = aChannel;
448 
449     UpdateIdleMode();
450 
451 exit:
452     return error;
453 }
454 
ClearTemporaryChannel(void)455 void Mac::ClearTemporaryChannel(void)
456 {
457     if (mUsingTemporaryChannel)
458     {
459         mUsingTemporaryChannel = false;
460         mRadioChannel          = mPanChannel;
461         UpdateIdleMode();
462     }
463 }
464 
SetSupportedChannelMask(const ChannelMask & aMask)465 void Mac::SetSupportedChannelMask(const ChannelMask &aMask)
466 {
467     ChannelMask newMask = aMask;
468 
469     newMask.Intersect(ChannelMask(Get<Radio>().GetSupportedChannelMask()));
470     IgnoreError(Get<Notifier>().Update(mSupportedChannelMask, newMask, kEventSupportedChannelMaskChanged));
471 }
472 
SetNetworkName(const char * aNameString)473 Error Mac::SetNetworkName(const char *aNameString)
474 {
475     return SignalNetworkNameChange(mNetworkName.Set(aNameString));
476 }
477 
SetNetworkName(const NameData & aNameData)478 Error Mac::SetNetworkName(const NameData &aNameData)
479 {
480     return SignalNetworkNameChange(mNetworkName.Set(aNameData));
481 }
482 
SignalNetworkNameChange(Error aError)483 Error Mac::SignalNetworkNameChange(Error aError)
484 {
485     switch (aError)
486     {
487     case kErrorNone:
488         Get<Notifier>().Signal(kEventThreadNetworkNameChanged);
489         break;
490 
491     case kErrorAlready:
492         Get<Notifier>().SignalIfFirst(kEventThreadNetworkNameChanged);
493         aError = kErrorNone;
494         break;
495 
496     default:
497         break;
498     }
499 
500     return aError;
501 }
502 
503 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
SetDomainName(const char * aNameString)504 Error Mac::SetDomainName(const char *aNameString)
505 {
506     Error error = mDomainName.Set(aNameString);
507 
508     return (error == kErrorAlready) ? kErrorNone : error;
509 }
510 
SetDomainName(const NameData & aNameData)511 Error Mac::SetDomainName(const NameData &aNameData)
512 {
513     Error error = mDomainName.Set(aNameData);
514 
515     return (error == kErrorAlready) ? kErrorNone : error;
516 }
517 #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
518 
SetPanId(PanId aPanId)519 void Mac::SetPanId(PanId aPanId)
520 {
521     SuccessOrExit(Get<Notifier>().Update(mPanId, aPanId, kEventThreadPanIdChanged));
522     mLinks.SetPanId(mPanId);
523 
524 exit:
525     return;
526 }
527 
SetExtendedPanId(const ExtendedPanId & aExtendedPanId)528 void Mac::SetExtendedPanId(const ExtendedPanId &aExtendedPanId)
529 {
530     IgnoreError(Get<Notifier>().Update(mExtendedPanId, aExtendedPanId, kEventThreadExtPanIdChanged));
531 }
532 
RequestDirectFrameTransmission(void)533 void Mac::RequestDirectFrameTransmission(void)
534 {
535     VerifyOrExit(IsEnabled());
536     VerifyOrExit(!mPendingTransmitDataDirect && (mOperation != kOperationTransmitDataDirect));
537 
538     StartOperation(kOperationTransmitDataDirect);
539 
540 exit:
541     return;
542 }
543 
544 #if OPENTHREAD_FTD
RequestIndirectFrameTransmission(void)545 void Mac::RequestIndirectFrameTransmission(void)
546 {
547     VerifyOrExit(IsEnabled());
548     VerifyOrExit(!mPendingTransmitDataIndirect && (mOperation != kOperationTransmitDataIndirect));
549 
550     StartOperation(kOperationTransmitDataIndirect);
551 
552 exit:
553     return;
554 }
555 
556 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
RequestCslFrameTransmission(uint32_t aDelay)557 void Mac::RequestCslFrameTransmission(uint32_t aDelay)
558 {
559     VerifyOrExit(mEnabled);
560 
561     mCslTxFireTime = TimerMilli::GetNow() + aDelay;
562 
563     StartOperation(kOperationTransmitDataCsl);
564 
565 exit:
566     return;
567 }
568 #endif
569 #endif // OPENTHREAD_FTD
570 
RequestDataPollTransmission(void)571 Error Mac::RequestDataPollTransmission(void)
572 {
573     Error error = kErrorNone;
574 
575     VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
576     VerifyOrExit(!mPendingTransmitPoll && (mOperation != kOperationTransmitPoll), error = kErrorAlready);
577 
578     // We ensure data frame and data poll tx requests are handled in the
579     // order they are requested. So if we have a pending direct data frame
580     // tx request, it should be sent before the poll frame.
581 
582     mShouldTxPollBeforeData = !mPendingTransmitDataDirect;
583 
584     StartOperation(kOperationTransmitPoll);
585 
586 exit:
587     return error;
588 }
589 
UpdateIdleMode(void)590 void Mac::UpdateIdleMode(void)
591 {
592     bool shouldSleep = !mRxOnWhenIdle && !mPromiscuous;
593 
594     VerifyOrExit(mOperation == kOperationIdle);
595 
596     if (!mRxOnWhenIdle)
597     {
598 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
599         if (mShouldDelaySleep)
600         {
601             mTimer.Start(kSleepDelay);
602             mShouldDelaySleep = false;
603             mDelayingSleep    = true;
604             otLogDebgMac("Idle mode: Sleep delayed");
605         }
606 
607         if (mDelayingSleep)
608         {
609             shouldSleep = false;
610         }
611 #endif
612     }
613 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
614     else if (mPendingTransmitDataCsl)
615     {
616         mTimer.FireAt(mCslTxFireTime);
617     }
618 #endif
619 
620     if (shouldSleep)
621     {
622 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
623         if (IsCslEnabled())
624         {
625             mLinks.CslSample(mRadioChannel);
626             ExitNow();
627         }
628 #endif
629         mLinks.Sleep();
630         otLogDebgMac("Idle mode: Radio sleeping");
631     }
632     else
633     {
634         mLinks.Receive(mRadioChannel);
635         otLogDebgMac("Idle mode: Radio receiving on channel %d", mRadioChannel);
636     }
637 
638 exit:
639     return;
640 }
641 
StartOperation(Operation aOperation)642 void Mac::StartOperation(Operation aOperation)
643 {
644     if (aOperation != kOperationIdle)
645     {
646         otLogDebgMac("Request to start operation \"%s\"", OperationToString(aOperation));
647 
648 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
649         if (mDelayingSleep)
650         {
651             otLogDebgMac("Canceling sleep delay");
652             mTimer.Stop();
653             mDelayingSleep    = false;
654             mShouldDelaySleep = false;
655         }
656 #endif
657     }
658 
659     switch (aOperation)
660     {
661     case kOperationIdle:
662         break;
663 
664     case kOperationActiveScan:
665         mPendingActiveScan = true;
666         break;
667 
668     case kOperationEnergyScan:
669         mPendingEnergyScan = true;
670         break;
671 
672     case kOperationTransmitBeacon:
673         mPendingTransmitBeacon = true;
674         break;
675 
676     case kOperationTransmitDataDirect:
677         mPendingTransmitDataDirect = true;
678         break;
679 
680 #if OPENTHREAD_FTD
681     case kOperationTransmitDataIndirect:
682         mPendingTransmitDataIndirect = true;
683         break;
684 
685 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
686     case kOperationTransmitDataCsl:
687         mPendingTransmitDataCsl = true;
688         break;
689 #endif
690 #endif
691 
692     case kOperationTransmitPoll:
693         mPendingTransmitPoll = true;
694         break;
695 
696     case kOperationWaitingForData:
697         mPendingWaitingForData = true;
698         break;
699     }
700 
701     if (mOperation == kOperationIdle)
702     {
703         mOperationTask.Post();
704     }
705 }
706 
HandleOperationTask(Tasklet & aTasklet)707 void Mac::HandleOperationTask(Tasklet &aTasklet)
708 {
709     aTasklet.Get<Mac>().PerformNextOperation();
710 }
711 
PerformNextOperation(void)712 void Mac::PerformNextOperation(void)
713 {
714     VerifyOrExit(mOperation == kOperationIdle);
715 
716     if (!IsEnabled())
717     {
718         mPendingWaitingForData     = false;
719         mPendingActiveScan         = false;
720         mPendingEnergyScan         = false;
721         mPendingTransmitBeacon     = false;
722         mPendingTransmitDataDirect = false;
723 #if OPENTHREAD_FTD
724         mPendingTransmitDataIndirect = false;
725 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
726         mPendingTransmitDataCsl = false;
727 #endif
728 #endif
729         mPendingTransmitPoll = false;
730         mTimer.Stop();
731 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
732         mDelayingSleep    = false;
733         mShouldDelaySleep = false;
734 #endif
735         ExitNow();
736     }
737 
738     // `WaitingForData` should be checked before any other pending
739     // operations since radio should remain in receive mode after
740     // a data poll ack indicating a pending frame from parent.
741     if (mPendingWaitingForData)
742     {
743         mPendingWaitingForData = false;
744         mOperation             = kOperationWaitingForData;
745     }
746 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
747     else if (mPendingTransmitDataCsl && TimerMilli::GetNow() >= mCslTxFireTime)
748     {
749         mPendingTransmitDataCsl = false;
750         mOperation              = kOperationTransmitDataCsl;
751     }
752 #endif
753     else if (mPendingActiveScan)
754     {
755         mPendingActiveScan = false;
756         mOperation         = kOperationActiveScan;
757     }
758     else if (mPendingEnergyScan)
759     {
760         mPendingEnergyScan = false;
761         mOperation         = kOperationEnergyScan;
762     }
763     else if (mPendingTransmitBeacon)
764     {
765         mPendingTransmitBeacon = false;
766         mOperation             = kOperationTransmitBeacon;
767     }
768 #if OPENTHREAD_FTD
769     else if (mPendingTransmitDataIndirect)
770     {
771         mPendingTransmitDataIndirect = false;
772         mOperation                   = kOperationTransmitDataIndirect;
773     }
774 #endif // OPENTHREAD_FTD
775     else if (mPendingTransmitPoll && (!mPendingTransmitDataDirect || mShouldTxPollBeforeData))
776     {
777         mPendingTransmitPoll = false;
778         mOperation           = kOperationTransmitPoll;
779     }
780     else if (mPendingTransmitDataDirect)
781     {
782         mPendingTransmitDataDirect = false;
783         mOperation                 = kOperationTransmitDataDirect;
784 
785         if (mPendingTransmitPoll)
786         {
787             // Ensure that a pending "transmit poll" operation request
788             // is prioritized over any future "transmit data" requests.
789             mShouldTxPollBeforeData = true;
790         }
791     }
792 
793     if (mOperation != kOperationIdle)
794     {
795         otLogDebgMac("Starting operation \"%s\"", OperationToString(mOperation));
796         mTimer.Stop(); // Stop the timer before any non-idle operation, have the operation itself be responsible to
797                        // start the timer (if it wants to).
798     }
799 
800     switch (mOperation)
801     {
802     case kOperationIdle:
803         UpdateIdleMode();
804         break;
805 
806     case kOperationActiveScan:
807         PerformActiveScan();
808         break;
809 
810     case kOperationEnergyScan:
811         PerformEnergyScan();
812         break;
813 
814     case kOperationTransmitBeacon:
815     case kOperationTransmitDataDirect:
816 #if OPENTHREAD_FTD
817     case kOperationTransmitDataIndirect:
818 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
819     case kOperationTransmitDataCsl:
820 #endif
821 #endif
822     case kOperationTransmitPoll:
823         BeginTransmit();
824         break;
825 
826     case kOperationWaitingForData:
827         mLinks.Receive(mRadioChannel);
828         mTimer.Start(kDataPollTimeout);
829         break;
830     }
831 
832 exit:
833     return;
834 }
835 
FinishOperation(void)836 void Mac::FinishOperation(void)
837 {
838     otLogDebgMac("Finishing operation \"%s\"", OperationToString(mOperation));
839     mOperation = kOperationIdle;
840 }
841 
PrepareBeaconRequest(void)842 TxFrame *Mac::PrepareBeaconRequest(void)
843 {
844     TxFrame &frame = mLinks.GetTxFrames().GetBroadcastTxFrame();
845     uint16_t fcf   = Frame::kFcfFrameMacCmd | Frame::kFcfDstAddrShort | Frame::kFcfSrcAddrNone;
846 
847     frame.InitMacHeader(fcf, Frame::kSecNone);
848     frame.SetDstPanId(kShortAddrBroadcast);
849     frame.SetDstAddr(kShortAddrBroadcast);
850     IgnoreError(frame.SetCommandId(Frame::kMacCmdBeaconRequest));
851 
852     otLogInfoMac("Sending Beacon Request");
853 
854     return &frame;
855 }
856 
PrepareBeacon(void)857 TxFrame *Mac::PrepareBeacon(void)
858 {
859     TxFrame *      frame;
860     uint8_t        beaconLength;
861     uint16_t       fcf;
862     Beacon *       beacon        = nullptr;
863     BeaconPayload *beaconPayload = nullptr;
864 
865 #if OPENTHREAD_CONFIG_MULTI_RADIO
866     OT_ASSERT(!mTxBeaconRadioLinks.IsEmpty());
867     frame = &mLinks.GetTxFrames().GetTxFrame(mTxBeaconRadioLinks);
868     mTxBeaconRadioLinks.Clear();
869 #else
870     frame = &mLinks.GetTxFrames().GetBroadcastTxFrame();
871 #endif
872 
873     fcf = Frame::kFcfFrameBeacon | Frame::kFcfDstAddrNone | Frame::kFcfSrcAddrExt;
874     frame->InitMacHeader(fcf, Frame::kSecNone);
875     IgnoreError(frame->SetSrcPanId(mPanId));
876     frame->SetSrcAddr(GetExtAddress());
877 
878     beacon = reinterpret_cast<Beacon *>(frame->GetPayload());
879     beacon->Init();
880     beaconLength = sizeof(*beacon);
881 
882     beaconPayload = reinterpret_cast<BeaconPayload *>(beacon->GetPayload());
883 
884     if (Get<KeyManager>().GetSecurityPolicy().mBeaconsEnabled)
885     {
886         beaconPayload->Init();
887 
888         if (IsJoinable())
889         {
890             beaconPayload->SetJoiningPermitted();
891         }
892         else
893         {
894             beaconPayload->ClearJoiningPermitted();
895         }
896 
897         beaconPayload->SetNetworkName(mNetworkName.GetAsData());
898         beaconPayload->SetExtendedPanId(mExtendedPanId);
899 
900         beaconLength += sizeof(*beaconPayload);
901     }
902 
903     frame->SetPayloadLength(beaconLength);
904 
905     LogBeacon("Sending", *beaconPayload);
906 
907     return frame;
908 }
909 
ShouldSendBeacon(void) const910 bool Mac::ShouldSendBeacon(void) const
911 {
912     bool shouldSend = false;
913 
914     VerifyOrExit(IsEnabled());
915 
916     shouldSend = IsBeaconEnabled();
917 
918 #if OPENTHREAD_CONFIG_MAC_BEACON_RSP_WHEN_JOINABLE_ENABLE
919     if (!shouldSend)
920     {
921         // When `ENABLE_BEACON_RSP_WHEN_JOINABLE` feature is enabled,
922         // the device should transmit IEEE 802.15.4 Beacons in response
923         // to IEEE 802.15.4 Beacon Requests even while the device is not
924         // router capable and detached (i.e., `IsBeaconEnabled()` is
925         // false) but only if it is in joinable state (unsecure port
926         // list is not empty).
927 
928         shouldSend = IsJoinable();
929     }
930 #endif
931 
932 exit:
933     return shouldSend;
934 }
935 
IsJoinable(void) const936 bool Mac::IsJoinable(void) const
937 {
938     uint8_t numUnsecurePorts;
939 
940     Get<Ip6::Filter>().GetUnsecurePorts(numUnsecurePorts);
941 
942     return (numUnsecurePorts != 0);
943 }
944 
ProcessTransmitSecurity(TxFrame & aFrame)945 void Mac::ProcessTransmitSecurity(TxFrame &aFrame)
946 {
947     KeyManager &      keyManager = Get<KeyManager>();
948     uint8_t           keyIdMode;
949     const ExtAddress *extAddress = nullptr;
950 
951     VerifyOrExit(aFrame.GetSecurityEnabled());
952 
953     IgnoreError(aFrame.GetKeyIdMode(keyIdMode));
954 
955     switch (keyIdMode)
956     {
957     case Frame::kKeyIdMode0:
958         aFrame.SetAesKey(keyManager.GetKek());
959         extAddress = &GetExtAddress();
960 
961         if (!aFrame.IsHeaderUpdated())
962         {
963             aFrame.SetFrameCounter(keyManager.GetKekFrameCounter());
964             keyManager.IncrementKekFrameCounter();
965         }
966 
967         break;
968 
969     case Frame::kKeyIdMode1:
970 
971         // For 15.4 radio link, the AES CCM* and frame security counter (under MAC
972         // key ID mode 1) are managed by `SubMac` or `Radio` modules.
973 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
974 #if !OPENTHREAD_CONFIG_MULTI_RADIO
975         ExitNow();
976 #else
977         VerifyOrExit(aFrame.GetRadioType() != kRadioTypeIeee802154);
978 #endif
979 #endif
980 
981 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
982         aFrame.SetAesKey(*mLinks.GetCurrentMacKey(aFrame));
983         extAddress = &GetExtAddress();
984 
985         // If the frame header is marked as updated, `MeshForwarder` which
986         // prepared the frame should set the frame counter and key id to the
987         // same values used in the earlier transmit attempt. For a new frame (header
988         // not updated), we get a new frame counter and key id from the key
989         // manager.
990 
991         if (!aFrame.IsHeaderUpdated())
992         {
993             mLinks.SetMacFrameCounter(aFrame);
994             aFrame.SetKeyId((keyManager.GetCurrentKeySequence() & 0x7f) + 1);
995         }
996 #endif
997         break;
998 
999     case Frame::kKeyIdMode2:
1000     {
1001         const uint8_t keySource[] = {0xff, 0xff, 0xff, 0xff};
1002         aFrame.SetAesKey(static_cast<const Key &>(sMode2Key));
1003         mKeyIdMode2FrameCounter++;
1004         aFrame.SetFrameCounter(mKeyIdMode2FrameCounter);
1005         aFrame.SetKeySource(keySource);
1006         aFrame.SetKeyId(0xff);
1007         extAddress = static_cast<const ExtAddress *>(&sMode2ExtAddress);
1008         break;
1009     }
1010 
1011     default:
1012         OT_ASSERT(false);
1013         OT_UNREACHABLE_CODE(break);
1014     }
1015 
1016 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1017     // Transmit security will be processed after time IE content is updated.
1018     VerifyOrExit(aFrame.GetTimeIeOffset() == 0);
1019 #endif
1020 
1021 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1022     // Transmit security will be processed after time IE content is updated.
1023     VerifyOrExit(aFrame.mInfo.mTxInfo.mCslPresent == 0);
1024 #endif
1025 
1026     aFrame.ProcessTransmitAesCcm(*extAddress);
1027 
1028 exit:
1029     return;
1030 }
1031 
BeginTransmit(void)1032 void Mac::BeginTransmit(void)
1033 {
1034     TxFrame * frame    = nullptr;
1035     TxFrames &txFrames = mLinks.GetTxFrames();
1036     Address   dstAddr;
1037 
1038     txFrames.Clear();
1039 
1040 #if OPENTHREAD_CONFIG_MULTI_RADIO
1041     mTxPendingRadioLinks.Clear();
1042     mTxError = kErrorAbort;
1043 #endif
1044 
1045     VerifyOrExit(IsEnabled());
1046 
1047     switch (mOperation)
1048     {
1049     case kOperationActiveScan:
1050         mLinks.SetPanId(kPanIdBroadcast);
1051         frame = PrepareBeaconRequest();
1052         VerifyOrExit(frame != nullptr);
1053         frame->SetChannel(mScanChannel);
1054         frame->SetSequence(0);
1055         frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
1056         frame->SetMaxFrameRetries(mMaxFrameRetriesDirect);
1057         break;
1058 
1059     case kOperationTransmitBeacon:
1060         frame = PrepareBeacon();
1061         VerifyOrExit(frame != nullptr);
1062         frame->SetChannel(mRadioChannel);
1063         frame->SetSequence(mBeaconSequence++);
1064         frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
1065         frame->SetMaxFrameRetries(mMaxFrameRetriesDirect);
1066         break;
1067 
1068     case kOperationTransmitPoll:
1069         txFrames.SetChannel(mRadioChannel);
1070         txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
1071         txFrames.SetMaxFrameRetries(mMaxFrameRetriesDirect);
1072         frame = Get<DataPollSender>().PrepareDataRequest(txFrames);
1073         VerifyOrExit(frame != nullptr);
1074         frame->SetSequence(mDataSequence++);
1075         break;
1076 
1077     case kOperationTransmitDataDirect:
1078         // Set channel and retry counts on all TxFrames before asking
1079         // the next layer (`MeshForwarder`) to prepare the frame. This
1080         // allows next layer to possibility change these parameters.
1081         txFrames.SetChannel(mRadioChannel);
1082         txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
1083         txFrames.SetMaxFrameRetries(mMaxFrameRetriesDirect);
1084         frame = Get<MeshForwarder>().HandleFrameRequest(txFrames);
1085         VerifyOrExit(frame != nullptr);
1086         frame->SetSequence(mDataSequence++);
1087         break;
1088 
1089 #if OPENTHREAD_FTD
1090     case kOperationTransmitDataIndirect:
1091         txFrames.SetChannel(mRadioChannel);
1092         txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsIndirect);
1093         txFrames.SetMaxFrameRetries(mMaxFrameRetriesIndirect);
1094         frame = Get<DataPollHandler>().HandleFrameRequest(txFrames);
1095         VerifyOrExit(frame != nullptr);
1096 
1097         // If the frame is marked as retransmission, then data sequence number is already set.
1098         if (!frame->IsARetransmission())
1099         {
1100             frame->SetSequence(mDataSequence++);
1101         }
1102         break;
1103 
1104 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1105     case kOperationTransmitDataCsl:
1106         txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsCsl);
1107         txFrames.SetMaxFrameRetries(kMaxFrameRetriesCsl);
1108         frame = Get<CslTxScheduler>().HandleFrameRequest(txFrames);
1109         VerifyOrExit(frame != nullptr);
1110 
1111         // If the frame is marked as retransmission, then data sequence number is already set.
1112         if (!frame->IsARetransmission())
1113         {
1114             frame->SetSequence(mDataSequence++);
1115         }
1116 
1117         break;
1118 
1119 #endif
1120 #endif // OPENTHREAD_FTD
1121 
1122     default:
1123         OT_ASSERT(false);
1124         OT_UNREACHABLE_CODE(break);
1125     }
1126 
1127 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1128     {
1129         uint8_t timeIeOffset = GetTimeIeOffset(*frame);
1130 
1131         frame->SetTimeIeOffset(timeIeOffset);
1132 
1133         if (timeIeOffset != 0)
1134         {
1135             frame->SetTimeSyncSeq(Get<TimeSync>().GetTimeSyncSeq());
1136             frame->SetNetworkTimeOffset(Get<TimeSync>().GetNetworkTimeOffset());
1137         }
1138     }
1139 #endif
1140 
1141     if (!frame->IsSecurityProcessed())
1142     {
1143 #if OPENTHREAD_CONFIG_MULTI_RADIO
1144         // Go through all selected radio link types for this tx and
1145         // copy the frame into correct `TxFrame` for each radio type
1146         // (if it is not already prepared).
1147 
1148         for (uint8_t index = 0; index < OT_ARRAY_LENGTH(RadioTypes::kAllRadioTypes); index++)
1149         {
1150             RadioType radio = RadioTypes::kAllRadioTypes[index];
1151 
1152             if (txFrames.GetSelectedRadioTypes().Contains(radio))
1153             {
1154                 TxFrame &txFrame = txFrames.GetTxFrame(radio);
1155 
1156                 if (txFrame.IsEmpty())
1157                 {
1158                     txFrame.CopyFrom(*frame);
1159                 }
1160             }
1161         }
1162 
1163         // Go through all selected radio link types for this tx and
1164         // process security for each radio type separately. This
1165         // allows radio links to handle security differently, e.g.,
1166         // with different keys or link frame counters.
1167         for (uint8_t index = 0; index < OT_ARRAY_LENGTH(RadioTypes::kAllRadioTypes); index++)
1168         {
1169             RadioType radio = RadioTypes::kAllRadioTypes[index];
1170 
1171             if (txFrames.GetSelectedRadioTypes().Contains(radio))
1172             {
1173                 ProcessTransmitSecurity(txFrames.GetTxFrame(radio));
1174             }
1175         }
1176 #else
1177         ProcessTransmitSecurity(*frame);
1178 #endif
1179     }
1180 
1181     mBroadcastTransmitCount = 0;
1182 
1183 #if OPENTHREAD_CONFIG_MULTI_RADIO
1184     mTxPendingRadioLinks = txFrames.GetSelectedRadioTypes();
1185 
1186     // If the "required radio type set" is empty,`mTxError` starts as
1187     // `kErrorAbort`. In this case, successful tx over any radio
1188     // link is sufficient for overall tx to be considered successful.
1189     // When the "required radio type set" is not empty, `mTxError`
1190     // starts as `kErrorNone` and we update it if tx over any link
1191     // in the required set fails.
1192 
1193     if (!txFrames.GetRequiredRadioTypes().IsEmpty())
1194     {
1195         mTxError = kErrorNone;
1196     }
1197 #endif
1198 
1199 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
1200     if (!mRxOnWhenIdle && !mPromiscuous)
1201     {
1202         mShouldDelaySleep = frame->GetFramePending();
1203         otLogDebgMac("Delay sleep for pending tx");
1204     }
1205 #endif
1206 
1207 #if OPENTHREAD_CONFIG_MULTI_RADIO
1208     mLinks.Send(*frame, mTxPendingRadioLinks);
1209 #else
1210     mLinks.Send();
1211 #endif
1212 
1213 exit:
1214 
1215     if (frame == nullptr)
1216     {
1217         // If the frame could not be prepared and the tx is being
1218         // aborted, we set the frame length to zero to mark it as empty.
1219         // The empty frame helps differentiate between an aborted tx due
1220         // to OpenThread itself not being able to prepare the frame, versus
1221         // the radio platform aborting the tx operation.
1222 
1223         frame = &txFrames.GetBroadcastTxFrame();
1224         frame->SetLength(0);
1225         HandleTransmitDone(*frame, nullptr, kErrorAbort);
1226     }
1227 }
1228 
RecordCcaStatus(bool aCcaSuccess,uint8_t aChannel)1229 void Mac::RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel)
1230 {
1231     if (!aCcaSuccess)
1232     {
1233         mCounters.mTxErrCca++;
1234     }
1235 
1236     // Only track the CCA success rate for frame transmissions
1237     // on the PAN channel.
1238 
1239     if (aChannel == mPanChannel)
1240     {
1241         if (mCcaSampleCount < kMaxCcaSampleCount)
1242         {
1243             mCcaSampleCount++;
1244         }
1245 
1246         mCcaSuccessRateTracker.AddSample(aCcaSuccess, mCcaSampleCount);
1247     }
1248 }
1249 
RecordFrameTransmitStatus(const TxFrame & aFrame,const RxFrame * aAckFrame,Error aError,uint8_t aRetryCount,bool aWillRetx)1250 void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame,
1251                                     const RxFrame *aAckFrame,
1252                                     Error          aError,
1253                                     uint8_t        aRetryCount,
1254                                     bool           aWillRetx)
1255 {
1256     bool      ackRequested = aFrame.GetAckRequest();
1257     Address   dstAddr;
1258     Neighbor *neighbor;
1259 
1260     VerifyOrExit(!aFrame.IsEmpty());
1261 
1262     IgnoreError(aFrame.GetDstAddr(dstAddr));
1263     neighbor = Get<NeighborTable>().FindNeighbor(dstAddr);
1264 
1265     // Record frame transmission success/failure state (for a neighbor).
1266 
1267     if ((neighbor != nullptr) && ackRequested)
1268     {
1269         bool frameTxSuccess = true;
1270 
1271         // CCA or abort errors are excluded from frame tx error
1272         // rate tracking, since when they occur, the frame is
1273         // not actually sent over the air.
1274 
1275         switch (aError)
1276         {
1277         case kErrorNoAck:
1278             frameTxSuccess = false;
1279 
1280             OT_FALL_THROUGH;
1281 
1282         case kErrorNone:
1283             neighbor->GetLinkInfo().AddFrameTxStatus(frameTxSuccess);
1284             break;
1285 
1286         default:
1287             break;
1288         }
1289     }
1290 
1291     // Log frame transmission failure.
1292 
1293     if (aError != kErrorNone)
1294     {
1295         LogFrameTxFailure(aFrame, aError, aRetryCount, aWillRetx);
1296         otDumpDebgMac("TX ERR", aFrame.GetHeader(), 16);
1297 
1298         if (aWillRetx)
1299         {
1300             mCounters.mTxRetry++;
1301 
1302             // Since this failed transmission will be retried by `SubMac` layer
1303             // there is no need to update any other MAC counter. MAC counters
1304             // are updated on the final transmission attempt.
1305 
1306             ExitNow();
1307         }
1308     }
1309 
1310     // Update neighbor's RSSI link info from the received Ack.
1311 
1312     if ((aError == kErrorNone) && ackRequested && (aAckFrame != nullptr) && (neighbor != nullptr))
1313     {
1314         neighbor->GetLinkInfo().AddRss(aAckFrame->GetRssi());
1315 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1316         neighbor->AggregateLinkMetrics(/* aSeriesId */ 0, aAckFrame->GetType(), aAckFrame->GetLqi(),
1317                                        aAckFrame->GetRssi());
1318         ProcessEnhAckProbing(*aAckFrame, *neighbor);
1319 #endif
1320 #if OPENTHREAD_FTD
1321         if (aAckFrame->GetVersion() == Frame::kFcfFrameVersion2015)
1322         {
1323 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1324             ProcessCsl(*aAckFrame, dstAddr);
1325 #endif
1326         }
1327 #endif // OPENTHREAD_FTD
1328     }
1329 
1330     // Update MAC counters.
1331 
1332     mCounters.mTxTotal++;
1333 
1334     if (aError == kErrorAbort)
1335     {
1336         mCounters.mTxErrAbort++;
1337     }
1338 
1339     if (aError == kErrorChannelAccessFailure)
1340     {
1341         mCounters.mTxErrBusyChannel++;
1342     }
1343 
1344     if (ackRequested)
1345     {
1346         mCounters.mTxAckRequested++;
1347 
1348         if (aError == kErrorNone)
1349         {
1350             mCounters.mTxAcked++;
1351         }
1352     }
1353     else
1354     {
1355         mCounters.mTxNoAckRequested++;
1356     }
1357 
1358     if (dstAddr.IsBroadcast())
1359     {
1360         mCounters.mTxBroadcast++;
1361     }
1362     else
1363     {
1364         mCounters.mTxUnicast++;
1365     }
1366 
1367 exit:
1368     return;
1369 }
1370 
HandleTransmitDone(TxFrame & aFrame,RxFrame * aAckFrame,Error aError)1371 void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
1372 {
1373 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
1374     if (!aFrame.IsEmpty()
1375 #if OPENTHREAD_CONFIG_MULTI_RADIO
1376         && (aFrame.GetRadioType() == kRadioTypeIeee802154)
1377 #endif
1378     )
1379     {
1380         Address dstAddr;
1381 
1382         // Determine whether to re-transmit a broadcast frame.
1383 
1384         IgnoreError(aFrame.GetDstAddr(dstAddr));
1385 
1386         if (dstAddr.IsBroadcast())
1387         {
1388             mBroadcastTransmitCount++;
1389 
1390             if (mBroadcastTransmitCount < kTxNumBcast)
1391             {
1392 #if OPENTHREAD_CONFIG_MULTI_RADIO
1393                 {
1394                     RadioTypes radioTypes;
1395                     radioTypes.Add(kRadioTypeIeee802154);
1396                     mLinks.Send(aFrame, radioTypes);
1397                 }
1398 #else
1399                 mLinks.Send();
1400 #endif
1401                 ExitNow();
1402             }
1403 
1404             mBroadcastTransmitCount = 0;
1405         }
1406 
1407 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
1408         // Verify Enh-ACK integrity by checking its MIC
1409         if ((aError == kErrorNone) && (aAckFrame != nullptr) &&
1410             (ProcessEnhAckSecurity(aFrame, *aAckFrame) != kErrorNone))
1411         {
1412             aError = kErrorNoAck;
1413         }
1414 #endif
1415     }
1416 #endif // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
1417 
1418 #if OPENTHREAD_CONFIG_MULTI_RADIO
1419     if (!aFrame.IsEmpty())
1420     {
1421         RadioType  radio          = aFrame.GetRadioType();
1422         RadioTypes requriedRadios = mLinks.GetTxFrames().GetRequiredRadioTypes();
1423 
1424         Get<RadioSelector>().UpdateOnSendDone(aFrame, aError);
1425 
1426         if (requriedRadios.IsEmpty())
1427         {
1428             // If the "required radio type set" is empty, successful
1429             // tx over any radio link is sufficient for overall tx to
1430             // be considered successful. In this case `mTxError`
1431             // starts as `kErrorAbort` and we update it only when
1432             // it is not already `kErrorNone`.
1433 
1434             if (mTxError != kErrorNone)
1435             {
1436                 mTxError = aError;
1437             }
1438         }
1439         else
1440         {
1441             // When the "required radio type set" is not empty we
1442             // expect the successful frame tx on all links in this set
1443             // to consider the overall tx successful. In this case,
1444             // `mTxError` starts as `kErrorNone` and we update it
1445             // if tx over any link in the set fails.
1446 
1447             if (requriedRadios.Contains(radio) && (aError != kErrorNone))
1448             {
1449                 otLogDebgMac("Frame tx failed on required radio link %s with error %s", RadioTypeToString(radio),
1450                              ErrorToString(aError));
1451 
1452                 mTxError = aError;
1453             }
1454         }
1455 
1456         // Keep track of radio links on which the frame is sent
1457         // and wait for all radio links to finish.
1458         mTxPendingRadioLinks.Remove(radio);
1459 
1460         VerifyOrExit(mTxPendingRadioLinks.IsEmpty());
1461 
1462         aError = mTxError;
1463     }
1464 #endif
1465 
1466     // Determine next action based on current operation.
1467 
1468     switch (mOperation)
1469     {
1470     case kOperationActiveScan:
1471         mCounters.mTxBeaconRequest++;
1472         mTimer.Start(mScanDuration);
1473         break;
1474 
1475     case kOperationTransmitBeacon:
1476         mCounters.mTxBeacon++;
1477         FinishOperation();
1478         PerformNextOperation();
1479         break;
1480 
1481     case kOperationTransmitPoll:
1482         OT_ASSERT(aFrame.IsEmpty() || aFrame.GetAckRequest());
1483 
1484         if ((aError == kErrorNone) && (aAckFrame != nullptr))
1485         {
1486             bool framePending = aAckFrame->GetFramePending();
1487 
1488             if (IsEnabled() && framePending)
1489             {
1490                 StartOperation(kOperationWaitingForData);
1491             }
1492 
1493             otLogInfoMac("Sent data poll, fp:%s", framePending ? "yes" : "no");
1494         }
1495 
1496         mCounters.mTxDataPoll++;
1497         FinishOperation();
1498         Get<DataPollSender>().HandlePollSent(aFrame, aError);
1499         PerformNextOperation();
1500         break;
1501 
1502     case kOperationTransmitDataDirect:
1503         mCounters.mTxData++;
1504 
1505         if (aError != kErrorNone)
1506         {
1507             mCounters.mTxDirectMaxRetryExpiry++;
1508         }
1509 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
1510         else if (mLinks.GetTransmitRetries() < OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT)
1511         {
1512             mRetryHistogram.mTxDirectRetrySuccess[mLinks.GetTransmitRetries()]++;
1513         }
1514 #endif
1515 
1516         otDumpDebgMac("TX", aFrame.GetHeader(), aFrame.GetLength());
1517         FinishOperation();
1518         Get<MeshForwarder>().HandleSentFrame(aFrame, aError);
1519 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
1520         Get<DataPollSender>().ProcessTxDone(aFrame, aAckFrame, aError);
1521 #endif
1522         PerformNextOperation();
1523         break;
1524 
1525 #if OPENTHREAD_FTD
1526 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1527     case kOperationTransmitDataCsl:
1528         mCounters.mTxData++;
1529 
1530         otDumpDebgMac("TX", aFrame.GetHeader(), aFrame.GetLength());
1531         FinishOperation();
1532         Get<CslTxScheduler>().HandleSentFrame(aFrame, aError);
1533         PerformNextOperation();
1534 
1535         break;
1536 #endif
1537     case kOperationTransmitDataIndirect:
1538         mCounters.mTxData++;
1539 
1540         if (aError != kErrorNone)
1541         {
1542             mCounters.mTxIndirectMaxRetryExpiry++;
1543         }
1544 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
1545         else if (mLinks.GetTransmitRetries() < OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT)
1546         {
1547             mRetryHistogram.mTxIndirectRetrySuccess[mLinks.GetTransmitRetries()]++;
1548         }
1549 #endif
1550 
1551         otDumpDebgMac("TX", aFrame.GetHeader(), aFrame.GetLength());
1552         FinishOperation();
1553         Get<DataPollHandler>().HandleSentFrame(aFrame, aError);
1554         PerformNextOperation();
1555         break;
1556 #endif
1557 
1558     default:
1559         OT_ASSERT(false);
1560         OT_UNREACHABLE_CODE(ExitNow()); // Added to suppress "unused label exit" warning (in TREL radio only).
1561         OT_UNREACHABLE_CODE(break);
1562     }
1563 
1564 exit:
1565     return;
1566 }
1567 
HandleTimer(Timer & aTimer)1568 void Mac::HandleTimer(Timer &aTimer)
1569 {
1570     aTimer.Get<Mac>().HandleTimer();
1571 }
1572 
HandleTimer(void)1573 void Mac::HandleTimer(void)
1574 {
1575     switch (mOperation)
1576     {
1577     case kOperationActiveScan:
1578         PerformActiveScan();
1579         break;
1580 
1581     case kOperationWaitingForData:
1582         otLogDebgMac("Data poll timeout");
1583         FinishOperation();
1584         Get<DataPollSender>().HandlePollTimeout();
1585         PerformNextOperation();
1586         break;
1587 
1588     case kOperationIdle:
1589         if (!mRxOnWhenIdle)
1590         {
1591 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
1592             if (mDelayingSleep)
1593             {
1594                 otLogDebgMac("Sleep delay timeout expired");
1595                 mDelayingSleep = false;
1596                 UpdateIdleMode();
1597             }
1598 #endif
1599         }
1600 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1601         else if (mPendingTransmitDataCsl)
1602         {
1603             PerformNextOperation();
1604         }
1605 #endif
1606         break;
1607 
1608     default:
1609         OT_ASSERT(false);
1610         OT_UNREACHABLE_CODE(break);
1611     }
1612 }
1613 
ProcessReceiveSecurity(RxFrame & aFrame,const Address & aSrcAddr,Neighbor * aNeighbor)1614 Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neighbor *aNeighbor)
1615 {
1616     KeyManager &      keyManager = Get<KeyManager>();
1617     Error             error      = kErrorSecurity;
1618     uint8_t           securityLevel;
1619     uint8_t           keyIdMode;
1620     uint32_t          frameCounter;
1621     uint8_t           keyid;
1622     uint32_t          keySequence = 0;
1623     const Key *       macKey;
1624     const ExtAddress *extAddress;
1625 
1626     VerifyOrExit(aFrame.GetSecurityEnabled(), error = kErrorNone);
1627 
1628     IgnoreError(aFrame.GetSecurityLevel(securityLevel));
1629     VerifyOrExit(securityLevel == Frame::kSecEncMic32);
1630 
1631     IgnoreError(aFrame.GetFrameCounter(frameCounter));
1632     otLogDebgMac("Rx security - frame counter %u", frameCounter);
1633 
1634     IgnoreError(aFrame.GetKeyIdMode(keyIdMode));
1635 
1636     switch (keyIdMode)
1637     {
1638     case Frame::kKeyIdMode0:
1639         macKey     = &keyManager.GetKek();
1640         extAddress = &aSrcAddr.GetExtended();
1641         break;
1642 
1643     case Frame::kKeyIdMode1:
1644         VerifyOrExit(aNeighbor != nullptr);
1645 
1646         IgnoreError(aFrame.GetKeyId(keyid));
1647         keyid--;
1648 
1649         if (keyid == (keyManager.GetCurrentKeySequence() & 0x7f))
1650         {
1651             keySequence = keyManager.GetCurrentKeySequence();
1652             macKey      = mLinks.GetCurrentMacKey(aFrame);
1653         }
1654         else if (keyid == ((keyManager.GetCurrentKeySequence() - 1) & 0x7f))
1655         {
1656             keySequence = keyManager.GetCurrentKeySequence() - 1;
1657             macKey      = mLinks.GetTemporaryMacKey(aFrame, keySequence);
1658         }
1659         else if (keyid == ((keyManager.GetCurrentKeySequence() + 1) & 0x7f))
1660         {
1661             keySequence = keyManager.GetCurrentKeySequence() + 1;
1662             macKey      = mLinks.GetTemporaryMacKey(aFrame, keySequence);
1663         }
1664         else
1665         {
1666             ExitNow();
1667         }
1668 
1669         // If the frame is from a neighbor not in valid state (e.g., it is from a child being
1670         // restored), skip the key sequence and frame counter checks but continue to verify
1671         // the tag/MIC. Such a frame is later filtered in `RxDoneTask` which only allows MAC
1672         // Data Request frames from a child being restored.
1673 
1674         if (aNeighbor->IsStateValid())
1675         {
1676             VerifyOrExit(keySequence >= aNeighbor->GetKeySequence());
1677 
1678             if (keySequence == aNeighbor->GetKeySequence())
1679             {
1680                 uint32_t neighborFrameCounter;
1681 
1682 #if OPENTHREAD_CONFIG_MULTI_RADIO
1683                 neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get(aFrame.GetRadioType());
1684 #else
1685                 neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get();
1686 #endif
1687 
1688                 // If frame counter is one off, then frame is a duplicate.
1689                 VerifyOrExit((frameCounter + 1) != neighborFrameCounter, error = kErrorDuplicated);
1690 
1691                 VerifyOrExit(frameCounter >= neighborFrameCounter);
1692             }
1693         }
1694 
1695         extAddress = &aSrcAddr.GetExtended();
1696 
1697         break;
1698 
1699     case Frame::kKeyIdMode2:
1700         macKey     = static_cast<const Key *>(&sMode2Key);
1701         extAddress = static_cast<const ExtAddress *>(&sMode2ExtAddress);
1702         break;
1703 
1704     default:
1705         ExitNow();
1706         OT_UNREACHABLE_CODE(break);
1707     }
1708 
1709     SuccessOrExit(aFrame.ProcessReceiveAesCcm(*extAddress, *macKey));
1710 
1711     if ((keyIdMode == Frame::kKeyIdMode1) && aNeighbor->IsStateValid())
1712     {
1713         if (aNeighbor->GetKeySequence() != keySequence)
1714         {
1715             aNeighbor->SetKeySequence(keySequence);
1716             aNeighbor->SetMleFrameCounter(0);
1717         }
1718 
1719 #if OPENTHREAD_CONFIG_MULTI_RADIO
1720         aNeighbor->GetLinkFrameCounters().Set(aFrame.GetRadioType(), frameCounter + 1);
1721 #else
1722         aNeighbor->GetLinkFrameCounters().Set(frameCounter + 1);
1723 #endif
1724 
1725 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
1726 #if OPENTHREAD_CONFIG_MULTI_RADIO
1727         if (aFrame.GetRadioType() == kRadioTypeIeee802154)
1728 #endif
1729         {
1730             if ((frameCounter + 1) > aNeighbor->GetLinkAckFrameCounter())
1731             {
1732                 aNeighbor->SetLinkAckFrameCounter(frameCounter + 1);
1733             }
1734         }
1735 #endif
1736 
1737         if (keySequence > keyManager.GetCurrentKeySequence())
1738         {
1739             keyManager.SetCurrentKeySequence(keySequence);
1740         }
1741     }
1742 
1743     error = kErrorNone;
1744 
1745 exit:
1746     return error;
1747 }
1748 
1749 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
ProcessEnhAckSecurity(TxFrame & aTxFrame,RxFrame & aAckFrame)1750 Error Mac::ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame)
1751 {
1752     Error       error = kErrorSecurity;
1753     uint8_t     securityLevel;
1754     uint8_t     txKeyId;
1755     uint8_t     ackKeyId;
1756     uint8_t     keyIdMode;
1757     uint32_t    frameCounter;
1758     Address     srcAddr;
1759     Address     dstAddr;
1760     Neighbor *  neighbor   = nullptr;
1761     KeyManager &keyManager = Get<KeyManager>();
1762     const Key * macKey;
1763 
1764     VerifyOrExit(aAckFrame.GetSecurityEnabled(), error = kErrorNone);
1765     VerifyOrExit(aAckFrame.IsVersion2015());
1766 
1767     IgnoreError(aAckFrame.GetSecurityLevel(securityLevel));
1768     VerifyOrExit(securityLevel == Frame::kSecEncMic32);
1769 
1770     IgnoreError(aAckFrame.GetKeyIdMode(keyIdMode));
1771     VerifyOrExit(keyIdMode == Frame::kKeyIdMode1, error = kErrorNone);
1772 
1773     IgnoreError(aTxFrame.GetKeyId(txKeyId));
1774     IgnoreError(aAckFrame.GetKeyId(ackKeyId));
1775 
1776     VerifyOrExit(txKeyId == ackKeyId);
1777 
1778     IgnoreError(aAckFrame.GetFrameCounter(frameCounter));
1779     otLogDebgMac("Rx security - Ack frame counter %u", frameCounter);
1780 
1781     IgnoreError(aAckFrame.GetSrcAddr(srcAddr));
1782 
1783     if (!srcAddr.IsNone())
1784     {
1785         neighbor = Get<NeighborTable>().FindNeighbor(srcAddr);
1786     }
1787     else
1788     {
1789         IgnoreError(aTxFrame.GetDstAddr(dstAddr));
1790 
1791         if (!dstAddr.IsNone())
1792         {
1793             // Get neighbor from destination address of transmitted frame
1794             neighbor = Get<NeighborTable>().FindNeighbor(dstAddr);
1795         }
1796     }
1797 
1798     if (!srcAddr.IsExtended() && neighbor != nullptr)
1799     {
1800         srcAddr.SetExtended(neighbor->GetExtAddress());
1801     }
1802 
1803     VerifyOrExit(srcAddr.IsExtended() && neighbor != nullptr);
1804 
1805     ackKeyId--;
1806 
1807     if (ackKeyId == (keyManager.GetCurrentKeySequence() & 0x7f))
1808     {
1809         macKey = &mLinks.GetSubMac().GetCurrentMacKey();
1810     }
1811     else if (ackKeyId == ((keyManager.GetCurrentKeySequence() - 1) & 0x7f))
1812     {
1813         macKey = &mLinks.GetSubMac().GetPreviousMacKey();
1814     }
1815     else if (ackKeyId == ((keyManager.GetCurrentKeySequence() + 1) & 0x7f))
1816     {
1817         macKey = &mLinks.GetSubMac().GetNextMacKey();
1818     }
1819     else
1820     {
1821         ExitNow();
1822     }
1823 
1824     if (neighbor->IsStateValid())
1825     {
1826         VerifyOrExit(frameCounter >= neighbor->GetLinkAckFrameCounter());
1827     }
1828 
1829     error = aAckFrame.ProcessReceiveAesCcm(srcAddr.GetExtended(), *macKey);
1830     SuccessOrExit(error);
1831 
1832     if (neighbor->IsStateValid())
1833     {
1834         neighbor->SetLinkAckFrameCounter(frameCounter + 1);
1835     }
1836 
1837 exit:
1838     if (error != kErrorNone)
1839     {
1840         otLogInfoMac("Frame tx attempt failed, error: Enh-ACK security check fail");
1841     }
1842 
1843     return error;
1844 }
1845 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
1846 
HandleReceivedFrame(RxFrame * aFrame,Error aError)1847 void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError)
1848 {
1849     Address   srcaddr;
1850     Address   dstaddr;
1851     PanId     panid;
1852     Neighbor *neighbor;
1853     Error     error = aError;
1854 
1855     mCounters.mRxTotal++;
1856 
1857     SuccessOrExit(error);
1858     VerifyOrExit(aFrame != nullptr, error = kErrorNoFrameReceived);
1859     VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
1860 
1861     // Ensure we have a valid frame before attempting to read any contents of
1862     // the buffer received from the radio.
1863     SuccessOrExit(error = aFrame->ValidatePsdu());
1864 
1865     IgnoreError(aFrame->GetSrcAddr(srcaddr));
1866     IgnoreError(aFrame->GetDstAddr(dstaddr));
1867     neighbor = Get<NeighborTable>().FindNeighbor(srcaddr);
1868 
1869     // Destination Address Filtering
1870     switch (dstaddr.GetType())
1871     {
1872     case Address::kTypeNone:
1873         break;
1874 
1875     case Address::kTypeShort:
1876         VerifyOrExit((mRxOnWhenIdle && dstaddr.IsBroadcast()) || dstaddr.GetShort() == GetShortAddress(),
1877                      error = kErrorDestinationAddressFiltered);
1878 
1879 #if OPENTHREAD_FTD
1880         // Allow multicasts from neighbor routers if FTD
1881         if (neighbor == nullptr && dstaddr.IsBroadcast() && Get<Mle::MleRouter>().IsFullThreadDevice())
1882         {
1883             neighbor = Get<NeighborTable>().FindRxOnlyNeighborRouter(srcaddr);
1884         }
1885 #endif
1886 
1887         break;
1888 
1889     case Address::kTypeExtended:
1890         VerifyOrExit(dstaddr.GetExtended() == GetExtAddress(), error = kErrorDestinationAddressFiltered);
1891         break;
1892     }
1893 
1894     // Verify destination PAN ID if present
1895     if (kErrorNone == aFrame->GetDstPanId(panid))
1896     {
1897         VerifyOrExit(panid == kShortAddrBroadcast || panid == mPanId, error = kErrorDestinationAddressFiltered);
1898     }
1899 
1900     // Source Address Filtering
1901     switch (srcaddr.GetType())
1902     {
1903     case Address::kTypeNone:
1904         break;
1905 
1906     case Address::kTypeShort:
1907         otLogDebgMac("Received frame from short address 0x%04x", srcaddr.GetShort());
1908 
1909         VerifyOrExit(neighbor != nullptr, error = kErrorUnknownNeighbor);
1910 
1911         srcaddr.SetExtended(neighbor->GetExtAddress());
1912 
1913         OT_FALL_THROUGH;
1914 
1915     case Address::kTypeExtended:
1916 
1917         // Duplicate Address Protection
1918         VerifyOrExit(srcaddr.GetExtended() != GetExtAddress(), error = kErrorInvalidSourceAddress);
1919 
1920 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
1921         {
1922             int8_t fixedRss;
1923 
1924             SuccessOrExit(error = mFilter.Apply(srcaddr.GetExtended(), fixedRss));
1925 
1926             if (fixedRss != Filter::kFixedRssDisabled)
1927             {
1928                 aFrame->SetRssi(fixedRss);
1929 
1930                 // Clear any previous link info to ensure the fixed RSSI
1931                 // value takes effect quickly.
1932                 if (neighbor != nullptr)
1933                 {
1934                     neighbor->GetLinkInfo().Clear();
1935                 }
1936             }
1937         }
1938 #endif
1939 
1940         break;
1941     }
1942 
1943     if (dstaddr.IsBroadcast())
1944     {
1945         mCounters.mRxBroadcast++;
1946     }
1947     else
1948     {
1949         mCounters.mRxUnicast++;
1950     }
1951 
1952     error = ProcessReceiveSecurity(*aFrame, srcaddr, neighbor);
1953 
1954     switch (error)
1955     {
1956     case kErrorDuplicated:
1957 
1958         // Allow a duplicate received frame pass, only if the
1959         // current operation is `kOperationWaitingForData` (i.e.,
1960         // the sleepy device is waiting to receive a frame after
1961         // a data poll ack from parent indicating there is a
1962         // pending frame for it). This ensures that the sleepy
1963         // device goes to sleep faster and avoids a data poll
1964         // timeout.
1965         //
1966         // Note that `error` is checked again later after the
1967         // operation `kOperationWaitingForData` is processed
1968         // so the duplicate frame will not be passed to next
1969         // layer (`MeshForwarder`).
1970 
1971         VerifyOrExit(mOperation == kOperationWaitingForData);
1972 
1973         OT_FALL_THROUGH;
1974 
1975     case kErrorNone:
1976         break;
1977 
1978     default:
1979         ExitNow();
1980     }
1981 
1982 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1983     if (aFrame->GetVersion() == Frame::kFcfFrameVersion2015)
1984     {
1985         ProcessCsl(*aFrame, srcaddr);
1986     }
1987 #endif
1988 
1989     Get<DataPollSender>().ProcessRxFrame(*aFrame);
1990 
1991     if (neighbor != nullptr)
1992     {
1993         neighbor->GetLinkInfo().AddRss(aFrame->GetRssi());
1994 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1995         neighbor->AggregateLinkMetrics(/* aSeriesId */ 0, aFrame->GetType(), aFrame->GetLqi(), aFrame->GetRssi());
1996 #endif
1997 
1998         if (aFrame->GetSecurityEnabled())
1999         {
2000             uint8_t keyIdMode;
2001 
2002             IgnoreError(aFrame->GetKeyIdMode(keyIdMode));
2003 
2004             if (keyIdMode == Frame::kKeyIdMode1)
2005             {
2006                 switch (neighbor->GetState())
2007                 {
2008                 case Neighbor::kStateValid:
2009                     break;
2010 
2011                 case Neighbor::kStateRestored:
2012                 case Neighbor::kStateChildUpdateRequest:
2013 
2014                     // Only accept a "MAC Data Request" frame from a child being restored.
2015                     VerifyOrExit(aFrame->IsDataRequestCommand(), error = kErrorDrop);
2016                     break;
2017 
2018                 default:
2019                     ExitNow(error = kErrorUnknownNeighbor);
2020                 }
2021 
2022 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 && OPENTHREAD_FTD
2023                 // From Thread 1.2, MAC Data Frame can also act as keep-alive message if child supports
2024                 if (aFrame->GetType() == Frame::kFcfFrameData && !neighbor->IsRxOnWhenIdle() &&
2025                     neighbor->IsEnhancedKeepAliveSupported())
2026                 {
2027                     neighbor->SetLastHeard(TimerMilli::GetNow());
2028                 }
2029 #endif
2030             }
2031 
2032 #if OPENTHREAD_CONFIG_MULTI_RADIO
2033             Get<RadioSelector>().UpdateOnReceive(*neighbor, aFrame->GetRadioType(), /* aIsDuplicate */ false);
2034 #endif
2035         }
2036     }
2037 
2038     switch (mOperation)
2039     {
2040     case kOperationActiveScan:
2041 
2042         if (aFrame->GetType() == Frame::kFcfFrameBeacon)
2043         {
2044             mCounters.mRxBeacon++;
2045             ReportActiveScanResult(aFrame);
2046             ExitNow();
2047         }
2048 
2049         OT_FALL_THROUGH;
2050 
2051     case kOperationEnergyScan:
2052 
2053         // We can possibly receive a data frame while either active or
2054         // energy scan is ongoing. We continue to process the frame only
2055         // if the current scan channel matches `mPanChannel`.
2056 
2057         VerifyOrExit(mScanChannel == mPanChannel, mCounters.mRxOther++);
2058         break;
2059 
2060     case kOperationWaitingForData:
2061 
2062         if (!dstaddr.IsNone())
2063         {
2064             mTimer.Stop();
2065 
2066 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
2067             if (!mRxOnWhenIdle && !mPromiscuous && aFrame->GetFramePending())
2068             {
2069                 mShouldDelaySleep = true;
2070                 otLogDebgMac("Delay sleep for pending rx");
2071             }
2072 #endif
2073             FinishOperation();
2074             PerformNextOperation();
2075         }
2076 
2077         SuccessOrExit(error);
2078 
2079         break;
2080 
2081     default:
2082         break;
2083     }
2084 
2085     switch (aFrame->GetType())
2086     {
2087     case Frame::kFcfFrameMacCmd:
2088         if (HandleMacCommand(*aFrame)) // returns `true` when handled
2089         {
2090             ExitNow(error = kErrorNone);
2091         }
2092 
2093         break;
2094 
2095     case Frame::kFcfFrameBeacon:
2096         mCounters.mRxBeacon++;
2097         break;
2098 
2099     case Frame::kFcfFrameData:
2100         mCounters.mRxData++;
2101         break;
2102 
2103     default:
2104         mCounters.mRxOther++;
2105         ExitNow();
2106     }
2107 
2108     otDumpDebgMac("RX", aFrame->GetHeader(), aFrame->GetLength());
2109     Get<MeshForwarder>().HandleReceivedFrame(*aFrame);
2110 
2111     UpdateIdleMode();
2112 
2113 exit:
2114 
2115     if (error != kErrorNone)
2116     {
2117         LogFrameRxFailure(aFrame, error);
2118 
2119         switch (error)
2120         {
2121         case kErrorSecurity:
2122             mCounters.mRxErrSec++;
2123             break;
2124 
2125         case kErrorFcs:
2126             mCounters.mRxErrFcs++;
2127             break;
2128 
2129         case kErrorNoFrameReceived:
2130             mCounters.mRxErrNoFrame++;
2131             break;
2132 
2133         case kErrorUnknownNeighbor:
2134             mCounters.mRxErrUnknownNeighbor++;
2135             break;
2136 
2137         case kErrorInvalidSourceAddress:
2138             mCounters.mRxErrInvalidSrcAddr++;
2139             break;
2140 
2141         case kErrorAddressFiltered:
2142             mCounters.mRxAddressFiltered++;
2143             break;
2144 
2145         case kErrorDestinationAddressFiltered:
2146             mCounters.mRxDestAddrFiltered++;
2147             break;
2148 
2149         case kErrorDuplicated:
2150             mCounters.mRxDuplicated++;
2151             break;
2152 
2153         default:
2154             mCounters.mRxErrOther++;
2155             break;
2156         }
2157     }
2158 }
2159 
HandleMacCommand(RxFrame & aFrame)2160 bool Mac::HandleMacCommand(RxFrame &aFrame)
2161 {
2162     bool    didHandle = false;
2163     uint8_t commandId;
2164 
2165     IgnoreError(aFrame.GetCommandId(commandId));
2166 
2167     switch (commandId)
2168     {
2169     case Frame::kMacCmdBeaconRequest:
2170         mCounters.mRxBeaconRequest++;
2171         otLogInfoMac("Received Beacon Request");
2172 
2173         if (ShouldSendBeacon())
2174         {
2175 #if OPENTHREAD_CONFIG_MULTI_RADIO
2176             mTxBeaconRadioLinks.Add(aFrame.GetRadioType());
2177 #endif
2178             StartOperation(kOperationTransmitBeacon);
2179         }
2180 
2181         didHandle = true;
2182         break;
2183 
2184     case Frame::kMacCmdDataRequest:
2185         mCounters.mRxDataPoll++;
2186 #if OPENTHREAD_FTD
2187         Get<DataPollHandler>().HandleDataPoll(aFrame);
2188         didHandle = true;
2189 #endif
2190         break;
2191 
2192     default:
2193         mCounters.mRxOther++;
2194         break;
2195     }
2196 
2197     return didHandle;
2198 }
2199 
SetPromiscuous(bool aPromiscuous)2200 void Mac::SetPromiscuous(bool aPromiscuous)
2201 {
2202     mPromiscuous = aPromiscuous;
2203     Get<Radio>().SetPromiscuous(aPromiscuous);
2204 
2205 #if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
2206     mDelayingSleep    = false;
2207     mShouldDelaySleep = false;
2208 #endif
2209 
2210     mLinks.SetRxOnWhenBackoff(mRxOnWhenIdle || mPromiscuous);
2211     UpdateIdleMode();
2212 }
2213 
2214 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
GetDirectRetrySuccessHistogram(uint8_t & aNumberOfEntries)2215 const uint32_t *Mac::GetDirectRetrySuccessHistogram(uint8_t &aNumberOfEntries)
2216 {
2217     if (mMaxFrameRetriesDirect >= OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT)
2218     {
2219         aNumberOfEntries = OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT;
2220     }
2221     else
2222     {
2223         aNumberOfEntries = mMaxFrameRetriesDirect + 1;
2224     }
2225 
2226     return mRetryHistogram.mTxDirectRetrySuccess;
2227 }
2228 
2229 #if OPENTHREAD_FTD
GetIndirectRetrySuccessHistogram(uint8_t & aNumberOfEntries)2230 const uint32_t *Mac::GetIndirectRetrySuccessHistogram(uint8_t &aNumberOfEntries)
2231 {
2232     if (mMaxFrameRetriesIndirect >= OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT)
2233     {
2234         aNumberOfEntries = OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT;
2235     }
2236     else
2237     {
2238         aNumberOfEntries = mMaxFrameRetriesIndirect + 1;
2239     }
2240 
2241     return mRetryHistogram.mTxIndirectRetrySuccess;
2242 }
2243 #endif
2244 
ResetRetrySuccessHistogram()2245 void Mac::ResetRetrySuccessHistogram()
2246 {
2247     memset(&mRetryHistogram, 0, sizeof(mRetryHistogram));
2248 }
2249 #endif // OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
2250 
2251 // LCOV_EXCL_START
2252 
2253 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
2254 
OperationToString(Operation aOperation)2255 const char *Mac::OperationToString(Operation aOperation)
2256 {
2257     static const char *const kOperationStrings[] = {
2258         "Idle",               // (0) kOperationIdle
2259         "ActiveScan",         // (1) kOperationActiveScan
2260         "EnergyScan",         // (2) kOperationEnergyScan
2261         "TransmitBeacon",     // (3) kOperationTransmitBeacon
2262         "TransmitDataDirect", // (4) kOperationTransmitDataDirect
2263         "TransmitPoll",       // (5) kOperationTransmitPoll
2264         "WaitingForData",     // (6) kOperationWaitingForData
2265 #if OPENTHREAD_FTD
2266         "TransmitDataIndirect", // (7) kOperationTransmitDataIndirect
2267 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2268         "TransmitDataCsl", // (8) kOperationTransmitDataCsl
2269 #endif
2270 #endif
2271     };
2272 
2273     static_assert(kOperationIdle == 0, "kOperationIdle value is incorrect");
2274     static_assert(kOperationActiveScan == 1, "kOperationActiveScan value is incorrect");
2275     static_assert(kOperationEnergyScan == 2, "kOperationEnergyScan value is incorrect");
2276     static_assert(kOperationTransmitBeacon == 3, "kOperationTransmitBeacon value is incorrect");
2277     static_assert(kOperationTransmitDataDirect == 4, "kOperationTransmitDataDirect value is incorrect");
2278     static_assert(kOperationTransmitPoll == 5, "kOperationTransmitPoll value is incorrect");
2279     static_assert(kOperationWaitingForData == 6, "kOperationWaitingForData value is incorrect");
2280 #if OPENTHREAD_FTD
2281     static_assert(kOperationTransmitDataIndirect == 7, "kOperationTransmitDataIndirect value is incorrect");
2282 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2283     static_assert(kOperationTransmitDataCsl == 8, "TransmitDataCsl value is incorrect");
2284 #endif
2285 #endif
2286 
2287     return kOperationStrings[aOperation];
2288 }
2289 
LogFrameRxFailure(const RxFrame * aFrame,Error aError) const2290 void Mac::LogFrameRxFailure(const RxFrame *aFrame, Error aError) const
2291 {
2292     otLogLevel logLevel;
2293 
2294     switch (aError)
2295     {
2296     case kErrorAbort:
2297     case kErrorNoFrameReceived:
2298     case kErrorDestinationAddressFiltered:
2299         logLevel = OT_LOG_LEVEL_DEBG;
2300         break;
2301 
2302     default:
2303         logLevel = OT_LOG_LEVEL_INFO;
2304         break;
2305     }
2306 
2307     if (aFrame == nullptr)
2308     {
2309         otLogMac(logLevel, "Frame rx failed, error:%s", ErrorToString(aError));
2310     }
2311     else
2312     {
2313         otLogMac(logLevel, "Frame rx failed, error:%s, %s", ErrorToString(aError), aFrame->ToInfoString().AsCString());
2314     }
2315 }
2316 
LogFrameTxFailure(const TxFrame & aFrame,Error aError,uint8_t aRetryCount,bool aWillRetx) const2317 void Mac::LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) const
2318 {
2319 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE && OPENTHREAD_CONFIG_MULTI_RADIO
2320     if (aFrame.GetRadioType() == kRadioTypeIeee802154)
2321 #elif OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
2322     if (true)
2323 #else
2324     if (false)
2325 #endif
2326     {
2327         uint8_t maxAttempts = aFrame.GetMaxFrameRetries() + 1;
2328         uint8_t curAttempt  = aWillRetx ? (aRetryCount + 1) : maxAttempts;
2329 
2330         otLogInfoMac("Frame tx attempt %d/%d failed, error:%s, %s", curAttempt, maxAttempts, ErrorToString(aError),
2331                      aFrame.ToInfoString().AsCString());
2332     }
2333     else
2334     {
2335         otLogInfoMac("Frame tx failed, error:%s, %s", ErrorToString(aError), aFrame.ToInfoString().AsCString());
2336     }
2337 }
2338 
LogBeacon(const char * aActionText,const BeaconPayload & aBeaconPayload) const2339 void Mac::LogBeacon(const char *aActionText, const BeaconPayload &aBeaconPayload) const
2340 {
2341     otLogInfoMac("%s Beacon, %s", aActionText, aBeaconPayload.ToInfoString().AsCString());
2342 }
2343 
2344 #else // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
2345 
LogFrameRxFailure(const RxFrame *,Error) const2346 void Mac::LogFrameRxFailure(const RxFrame *, Error) const
2347 {
2348 }
2349 
LogBeacon(const char *,const BeaconPayload &) const2350 void Mac::LogBeacon(const char *, const BeaconPayload &) const
2351 {
2352 }
2353 
LogFrameTxFailure(const TxFrame &,Error,uint8_t,bool) const2354 void Mac::LogFrameTxFailure(const TxFrame &, Error, uint8_t, bool) const
2355 {
2356 }
2357 
2358 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
2359 
2360 // LCOV_EXCL_STOP
2361 
2362 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
GetTimeIeOffset(const Frame & aFrame)2363 uint8_t Mac::GetTimeIeOffset(const Frame &aFrame)
2364 {
2365     uint8_t        offset = 0;
2366     const uint8_t *base   = aFrame.GetPsdu();
2367     const uint8_t *cur    = nullptr;
2368 
2369     cur = reinterpret_cast<const uint8_t *>(aFrame.GetTimeIe());
2370     VerifyOrExit(cur != nullptr);
2371 
2372     cur += sizeof(VendorIeHeader);
2373     offset = static_cast<uint8_t>(cur - base);
2374 
2375 exit:
2376     return offset;
2377 }
2378 #endif
2379 
2380 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
SetCslChannel(uint8_t aChannel)2381 void Mac::SetCslChannel(uint8_t aChannel)
2382 {
2383     VerifyOrExit(GetCslChannel() != aChannel);
2384 
2385     mLinks.GetSubMac().SetCslChannel(aChannel);
2386     mLinks.GetSubMac().SetCslChannelSpecified(aChannel != 0);
2387 
2388     if (IsCslEnabled())
2389     {
2390         Get<Mle::Mle>().ScheduleChildUpdateRequest();
2391     }
2392 exit:
2393     return;
2394 }
2395 
SetCslPeriod(uint16_t aPeriod)2396 void Mac::SetCslPeriod(uint16_t aPeriod)
2397 {
2398     mLinks.GetSubMac().SetCslPeriod(aPeriod);
2399 
2400     Get<DataPollSender>().RecalculatePollPeriod();
2401 
2402     if ((GetCslPeriod() == 0) || IsCslEnabled())
2403     {
2404         IgnoreError(Get<Radio>().EnableCsl(GetCslPeriod(), Get<Mle::Mle>().GetParent().GetRloc16(),
2405                                            &Get<Mle::Mle>().GetParent().GetExtAddress()));
2406     }
2407 
2408     if (IsCslEnabled())
2409     {
2410         Get<Mle::Mle>().ScheduleChildUpdateRequest();
2411     }
2412 
2413     UpdateIdleMode();
2414 }
2415 
IsCslEnabled(void) const2416 bool Mac::IsCslEnabled(void) const
2417 {
2418     return !GetRxOnWhenIdle() && IsCslCapable();
2419 }
2420 
IsCslCapable(void) const2421 bool Mac::IsCslCapable(void) const
2422 {
2423     return (GetCslPeriod() > 0) && Get<Mle::MleRouter>().IsChild() &&
2424            Get<Mle::Mle>().GetParent().IsEnhancedKeepAliveSupported();
2425 }
2426 
2427 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
2428 
2429 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
ProcessCsl(const RxFrame & aFrame,const Address & aSrcAddr)2430 void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr)
2431 {
2432     const uint8_t *cur   = aFrame.GetHeaderIe(CslIe::kHeaderIeId);
2433     Child *        child = Get<ChildTable>().FindChild(aSrcAddr, Child::kInStateAnyExceptInvalid);
2434     const CslIe *  csl;
2435 
2436     VerifyOrExit(cur != nullptr && child != nullptr && aFrame.GetSecurityEnabled());
2437 
2438     csl = reinterpret_cast<const CslIe *>(cur + sizeof(HeaderIe));
2439 
2440     child->SetCslPeriod(csl->GetPeriod());
2441     // Use ceiling to ensure the the time diff will be within kUsPerTenSymbols
2442     child->SetCslPhase(csl->GetPhase());
2443     child->SetCslSynchronized(true);
2444     child->SetCslLastHeard(TimerMilli::GetNow());
2445     child->SetLastRxTimestamp(aFrame.GetTimestamp());
2446     otLogDebgMac("Timestamp=%u Sequence=%u CslPeriod=%hu CslPhase=%hu TransmitPhase=%hu",
2447                  static_cast<uint32_t>(aFrame.GetTimestamp()), aFrame.GetSequence(), csl->GetPeriod(), csl->GetPhase(),
2448                  child->GetCslPhase());
2449 
2450     Get<CslTxScheduler>().Update();
2451 
2452 exit:
2453     return;
2454 }
2455 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2456 
2457 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
ProcessEnhAckProbing(const RxFrame & aFrame,const Neighbor & aNeighbor)2458 void Mac::ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor)
2459 {
2460     constexpr uint8_t kEnhAckProbingIeMaxLen = 2;
2461 
2462     const HeaderIe *enhAckProbingIe =
2463         reinterpret_cast<const HeaderIe *>(aFrame.GetThreadIe(ThreadIe::kEnhAckProbingIe));
2464     const uint8_t *data =
2465         reinterpret_cast<const uint8_t *>(enhAckProbingIe) + sizeof(HeaderIe) + sizeof(VendorIeHeader);
2466     uint8_t dataLen = 0;
2467 
2468     VerifyOrExit(enhAckProbingIe != nullptr);
2469 
2470     dataLen = enhAckProbingIe->GetLength() - sizeof(VendorIeHeader);
2471     VerifyOrExit(dataLen <= kEnhAckProbingIeMaxLen);
2472 
2473     Get<LinkMetrics::LinkMetrics>().ProcessEnhAckIeData(data, dataLen, aNeighbor);
2474 exit:
2475     return;
2476 }
2477 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
2478 
2479 } // namespace Mac
2480 } // namespace ot
2481