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