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