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 IEEE 802.15.4 header generation and processing.
32 */
33
34 #include "mac_frame.hpp"
35
36 #include <stdio.h>
37
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/log.hpp"
41 #include "radio/trel_link.hpp"
42 #if !OPENTHREAD_RADIO || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
43 #include "crypto/aes_ccm.hpp"
44 #endif
45
46 namespace ot {
47 namespace Mac {
48
49 using ot::Encoding::LittleEndian::ReadUint16;
50 using ot::Encoding::LittleEndian::ReadUint32;
51 using ot::Encoding::LittleEndian::WriteUint16;
52 using ot::Encoding::LittleEndian::WriteUint32;
53
Init(uint16_t aId,uint8_t aLen)54 void HeaderIe::Init(uint16_t aId, uint8_t aLen)
55 {
56 Init();
57 SetId(aId);
58 SetLength(aLen);
59 }
60
InitMacHeader(uint16_t aFcf,uint8_t aSecurityControl)61 void Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
62 {
63 mLength = CalculateAddrFieldSize(aFcf);
64
65 OT_ASSERT(mLength != kInvalidSize);
66
67 WriteUint16(aFcf, mPsdu);
68
69 if (aFcf & kFcfSecurityEnabled)
70 {
71 mPsdu[mLength] = aSecurityControl;
72
73 mLength += CalculateSecurityHeaderSize(aSecurityControl);
74 mLength += CalculateMicSize(aSecurityControl);
75 }
76
77 if ((aFcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
78 {
79 mLength += kCommandIdSize;
80 }
81
82 mLength += GetFcsSize();
83 }
84
GetFrameControlField(void) const85 uint16_t Frame::GetFrameControlField(void) const
86 {
87 return ReadUint16(mPsdu);
88 }
89
ValidatePsdu(void) const90 Error Frame::ValidatePsdu(void) const
91 {
92 Error error = kErrorNone;
93 uint8_t index = FindPayloadIndex();
94
95 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
96 VerifyOrExit((index + GetFooterLength()) <= mLength, error = kErrorParse);
97
98 exit:
99 return error;
100 }
101
SetAckRequest(bool aAckRequest)102 void Frame::SetAckRequest(bool aAckRequest)
103 {
104 if (aAckRequest)
105 {
106 mPsdu[0] |= kFcfAckRequest;
107 }
108 else
109 {
110 mPsdu[0] &= ~kFcfAckRequest;
111 }
112 }
113
SetFramePending(bool aFramePending)114 void Frame::SetFramePending(bool aFramePending)
115 {
116 if (aFramePending)
117 {
118 mPsdu[0] |= kFcfFramePending;
119 }
120 else
121 {
122 mPsdu[0] &= ~kFcfFramePending;
123 }
124 }
125
FindDstPanIdIndex(void) const126 uint8_t Frame::FindDstPanIdIndex(void) const
127 {
128 uint8_t index;
129
130 VerifyOrExit(IsDstPanIdPresent(), index = kInvalidIndex);
131
132 index = kFcfSize + kDsnSize;
133
134 exit:
135 return index;
136 }
137
IsDstPanIdPresent(uint16_t aFcf)138 bool Frame::IsDstPanIdPresent(uint16_t aFcf)
139 {
140 bool present = true;
141
142 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
143 if (IsVersion2015(aFcf))
144 {
145 switch (aFcf & (kFcfDstAddrMask | kFcfSrcAddrMask | kFcfPanidCompression))
146 {
147 case (kFcfDstAddrNone | kFcfSrcAddrNone):
148 case (kFcfDstAddrExt | kFcfSrcAddrNone | kFcfPanidCompression):
149 case (kFcfDstAddrShort | kFcfSrcAddrNone | kFcfPanidCompression):
150 case (kFcfDstAddrNone | kFcfSrcAddrExt):
151 case (kFcfDstAddrNone | kFcfSrcAddrShort):
152 case (kFcfDstAddrNone | kFcfSrcAddrExt | kFcfPanidCompression):
153 case (kFcfDstAddrNone | kFcfSrcAddrShort | kFcfPanidCompression):
154 case (kFcfDstAddrExt | kFcfSrcAddrExt | kFcfPanidCompression):
155 present = false;
156 break;
157 default:
158 break;
159 }
160 }
161 else
162 #endif
163 {
164 present = IsDstAddrPresent(aFcf);
165 }
166
167 return present;
168 }
169
GetDstPanId(PanId & aPanId) const170 Error Frame::GetDstPanId(PanId &aPanId) const
171 {
172 Error error = kErrorNone;
173 uint8_t index = FindDstPanIdIndex();
174
175 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
176 aPanId = ReadUint16(&mPsdu[index]);
177
178 exit:
179 return error;
180 }
181
SetDstPanId(PanId aPanId)182 void Frame::SetDstPanId(PanId aPanId)
183 {
184 uint8_t index = FindDstPanIdIndex();
185
186 OT_ASSERT(index != kInvalidIndex);
187 WriteUint16(aPanId, &mPsdu[index]);
188 }
189
FindDstAddrIndex(void) const190 uint8_t Frame::FindDstAddrIndex(void) const
191 {
192 return kFcfSize + kDsnSize + (IsDstPanIdPresent() ? sizeof(PanId) : 0);
193 }
194
GetDstAddr(Address & aAddress) const195 Error Frame::GetDstAddr(Address &aAddress) const
196 {
197 Error error = kErrorNone;
198 uint8_t index = FindDstAddrIndex();
199
200 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
201
202 switch (GetFrameControlField() & kFcfDstAddrMask)
203 {
204 case kFcfDstAddrShort:
205 aAddress.SetShort(ReadUint16(&mPsdu[index]));
206 break;
207
208 case kFcfDstAddrExt:
209 aAddress.SetExtended(&mPsdu[index], ExtAddress::kReverseByteOrder);
210 break;
211
212 default:
213 aAddress.SetNone();
214 break;
215 }
216
217 exit:
218 return error;
219 }
220
SetDstAddr(ShortAddress aShortAddress)221 void Frame::SetDstAddr(ShortAddress aShortAddress)
222 {
223 OT_ASSERT((GetFrameControlField() & kFcfDstAddrMask) == kFcfDstAddrShort);
224 WriteUint16(aShortAddress, &mPsdu[FindDstAddrIndex()]);
225 }
226
SetDstAddr(const ExtAddress & aExtAddress)227 void Frame::SetDstAddr(const ExtAddress &aExtAddress)
228 {
229 uint8_t index = FindDstAddrIndex();
230
231 OT_ASSERT((GetFrameControlField() & kFcfDstAddrMask) == kFcfDstAddrExt);
232 OT_ASSERT(index != kInvalidIndex);
233
234 aExtAddress.CopyTo(&mPsdu[index], ExtAddress::kReverseByteOrder);
235 }
236
SetDstAddr(const Address & aAddress)237 void Frame::SetDstAddr(const Address &aAddress)
238 {
239 switch (aAddress.GetType())
240 {
241 case Address::kTypeShort:
242 SetDstAddr(aAddress.GetShort());
243 break;
244
245 case Address::kTypeExtended:
246 SetDstAddr(aAddress.GetExtended());
247 break;
248
249 default:
250 OT_ASSERT(false);
251 OT_UNREACHABLE_CODE(break);
252 }
253 }
254
FindSrcPanIdIndex(void) const255 uint8_t Frame::FindSrcPanIdIndex(void) const
256 {
257 uint8_t index = 0;
258 uint16_t fcf = GetFrameControlField();
259
260 VerifyOrExit(IsSrcPanIdPresent(), index = kInvalidIndex);
261
262 index += kFcfSize + kDsnSize;
263
264 if (IsDstPanIdPresent(fcf))
265 {
266 index += sizeof(PanId);
267 }
268
269 switch (fcf & kFcfDstAddrMask)
270 {
271 case kFcfDstAddrShort:
272 index += sizeof(ShortAddress);
273 break;
274
275 case kFcfDstAddrExt:
276 index += sizeof(ExtAddress);
277 break;
278 }
279
280 exit:
281 return index;
282 }
283
IsSrcPanIdPresent(uint16_t aFcf)284 bool Frame::IsSrcPanIdPresent(uint16_t aFcf)
285 {
286 bool srcPanIdPresent = false;
287
288 if ((aFcf & kFcfSrcAddrMask) != kFcfSrcAddrNone && (aFcf & kFcfPanidCompression) == 0)
289 {
290 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
291 // Handle a special case in IEEE 802.15.4-2015, when Pan ID Compression is 0, but Src Pan ID is not present:
292 // Dest Address: Extended
293 // Source Address: Extended
294 // Dest Pan ID: Present
295 // Src Pan ID: Not Present
296 // Pan ID Compression: 0
297 if (!IsVersion2015(aFcf) || (aFcf & kFcfDstAddrMask) != kFcfDstAddrExt ||
298 (aFcf & kFcfSrcAddrMask) != kFcfSrcAddrExt)
299 #endif
300 {
301 srcPanIdPresent = true;
302 }
303 }
304
305 return srcPanIdPresent;
306 }
307
GetSrcPanId(PanId & aPanId) const308 Error Frame::GetSrcPanId(PanId &aPanId) const
309 {
310 Error error = kErrorNone;
311 uint8_t index = FindSrcPanIdIndex();
312
313 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
314 aPanId = ReadUint16(&mPsdu[index]);
315
316 exit:
317 return error;
318 }
319
SetSrcPanId(PanId aPanId)320 Error Frame::SetSrcPanId(PanId aPanId)
321 {
322 Error error = kErrorNone;
323 uint8_t index = FindSrcPanIdIndex();
324
325 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
326 WriteUint16(aPanId, &mPsdu[index]);
327
328 exit:
329 return error;
330 }
331
FindSrcAddrIndex(void) const332 uint8_t Frame::FindSrcAddrIndex(void) const
333 {
334 uint8_t index = 0;
335 uint16_t fcf = GetFrameControlField();
336
337 index += kFcfSize + kDsnSize;
338
339 if (IsDstPanIdPresent(fcf))
340 {
341 index += sizeof(PanId);
342 }
343
344 switch (fcf & kFcfDstAddrMask)
345 {
346 case kFcfDstAddrShort:
347 index += sizeof(ShortAddress);
348 break;
349
350 case kFcfDstAddrExt:
351 index += sizeof(ExtAddress);
352 break;
353 }
354
355 if (IsSrcPanIdPresent(fcf))
356 {
357 index += sizeof(PanId);
358 }
359
360 return index;
361 }
362
GetSrcAddr(Address & aAddress) const363 Error Frame::GetSrcAddr(Address &aAddress) const
364 {
365 Error error = kErrorNone;
366 uint8_t index = FindSrcAddrIndex();
367 uint16_t fcf = GetFrameControlField();
368
369 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
370
371 switch (fcf & kFcfSrcAddrMask)
372 {
373 case kFcfSrcAddrShort:
374 aAddress.SetShort(ReadUint16(&mPsdu[index]));
375 break;
376
377 case kFcfSrcAddrExt:
378 aAddress.SetExtended(&mPsdu[index], ExtAddress::kReverseByteOrder);
379 break;
380
381 default:
382 aAddress.SetNone();
383 break;
384 }
385
386 exit:
387 return error;
388 }
389
SetSrcAddr(ShortAddress aShortAddress)390 void Frame::SetSrcAddr(ShortAddress aShortAddress)
391 {
392 uint8_t index = FindSrcAddrIndex();
393
394 OT_ASSERT((GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrShort);
395 OT_ASSERT(index != kInvalidIndex);
396
397 WriteUint16(aShortAddress, &mPsdu[index]);
398 }
399
SetSrcAddr(const ExtAddress & aExtAddress)400 void Frame::SetSrcAddr(const ExtAddress &aExtAddress)
401 {
402 uint8_t index = FindSrcAddrIndex();
403
404 OT_ASSERT((GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrExt);
405 OT_ASSERT(index != kInvalidIndex);
406
407 aExtAddress.CopyTo(&mPsdu[index], ExtAddress::kReverseByteOrder);
408 }
409
SetSrcAddr(const Address & aAddress)410 void Frame::SetSrcAddr(const Address &aAddress)
411 {
412 switch (aAddress.GetType())
413 {
414 case Address::kTypeShort:
415 SetSrcAddr(aAddress.GetShort());
416 break;
417
418 case Address::kTypeExtended:
419 SetSrcAddr(aAddress.GetExtended());
420 break;
421
422 default:
423 OT_ASSERT(false);
424 }
425 }
426
GetSecurityControlField(uint8_t & aSecurityControlField) const427 Error Frame::GetSecurityControlField(uint8_t &aSecurityControlField) const
428 {
429 Error error = kErrorNone;
430 uint8_t index = FindSecurityHeaderIndex();
431
432 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
433
434 aSecurityControlField = mPsdu[index];
435
436 exit:
437 return error;
438 }
439
SetSecurityControlField(uint8_t aSecurityControlField)440 void Frame::SetSecurityControlField(uint8_t aSecurityControlField)
441 {
442 uint8_t index = FindSecurityHeaderIndex();
443
444 OT_ASSERT(index != kInvalidIndex);
445
446 mPsdu[index] = aSecurityControlField;
447 }
448
FindSecurityHeaderIndex(void) const449 uint8_t Frame::FindSecurityHeaderIndex(void) const
450 {
451 uint8_t index;
452
453 VerifyOrExit(kFcfSize < mLength, index = kInvalidIndex);
454 VerifyOrExit(GetSecurityEnabled(), index = kInvalidIndex);
455 index = SkipAddrFieldIndex();
456
457 exit:
458 return index;
459 }
460
GetSecurityLevel(uint8_t & aSecurityLevel) const461 Error Frame::GetSecurityLevel(uint8_t &aSecurityLevel) const
462 {
463 Error error = kErrorNone;
464 uint8_t index = FindSecurityHeaderIndex();
465
466 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
467
468 aSecurityLevel = mPsdu[index] & kSecLevelMask;
469
470 exit:
471 return error;
472 }
473
GetKeyIdMode(uint8_t & aKeyIdMode) const474 Error Frame::GetKeyIdMode(uint8_t &aKeyIdMode) const
475 {
476 Error error = kErrorNone;
477 uint8_t index = FindSecurityHeaderIndex();
478
479 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
480
481 aKeyIdMode = mPsdu[index] & kKeyIdModeMask;
482
483 exit:
484 return error;
485 }
486
GetFrameCounter(uint32_t & aFrameCounter) const487 Error Frame::GetFrameCounter(uint32_t &aFrameCounter) const
488 {
489 Error error = kErrorNone;
490 uint8_t index = FindSecurityHeaderIndex();
491
492 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
493
494 // Security Control
495 index += kSecurityControlSize;
496
497 aFrameCounter = ReadUint32(&mPsdu[index]);
498
499 exit:
500 return error;
501 }
502
SetFrameCounter(uint32_t aFrameCounter)503 void Frame::SetFrameCounter(uint32_t aFrameCounter)
504 {
505 uint8_t index = FindSecurityHeaderIndex();
506
507 OT_ASSERT(index != kInvalidIndex);
508
509 // Security Control
510 index += kSecurityControlSize;
511
512 WriteUint32(aFrameCounter, &mPsdu[index]);
513
514 static_cast<Mac::TxFrame *>(this)->SetIsHeaderUpdated(true);
515 }
516
GetKeySource(void) const517 const uint8_t *Frame::GetKeySource(void) const
518 {
519 uint8_t index = FindSecurityHeaderIndex();
520
521 OT_ASSERT(index != kInvalidIndex);
522
523 return &mPsdu[index + kSecurityControlSize + kFrameCounterSize];
524 }
525
GetKeySourceLength(uint8_t aKeyIdMode)526 uint8_t Frame::GetKeySourceLength(uint8_t aKeyIdMode)
527 {
528 uint8_t len = 0;
529
530 switch (aKeyIdMode)
531 {
532 case kKeyIdMode0:
533 len = kKeySourceSizeMode0;
534 break;
535
536 case kKeyIdMode1:
537 len = kKeySourceSizeMode1;
538 break;
539
540 case kKeyIdMode2:
541 len = kKeySourceSizeMode2;
542 break;
543
544 case kKeyIdMode3:
545 len = kKeySourceSizeMode3;
546 break;
547 }
548
549 return len;
550 }
551
SetKeySource(const uint8_t * aKeySource)552 void Frame::SetKeySource(const uint8_t *aKeySource)
553 {
554 uint8_t keySourceLength;
555 uint8_t index = FindSecurityHeaderIndex();
556
557 OT_ASSERT(index != kInvalidIndex);
558
559 keySourceLength = GetKeySourceLength(mPsdu[index] & kKeyIdModeMask);
560
561 memcpy(&mPsdu[index + kSecurityControlSize + kFrameCounterSize], aKeySource, keySourceLength);
562 }
563
GetKeyId(uint8_t & aKeyId) const564 Error Frame::GetKeyId(uint8_t &aKeyId) const
565 {
566 Error error = kErrorNone;
567 uint8_t keySourceLength;
568 uint8_t index = FindSecurityHeaderIndex();
569
570 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
571
572 keySourceLength = GetKeySourceLength(mPsdu[index] & kKeyIdModeMask);
573
574 aKeyId = mPsdu[index + kSecurityControlSize + kFrameCounterSize + keySourceLength];
575
576 exit:
577 return error;
578 }
579
SetKeyId(uint8_t aKeyId)580 void Frame::SetKeyId(uint8_t aKeyId)
581 {
582 uint8_t keySourceLength;
583 uint8_t index = FindSecurityHeaderIndex();
584
585 OT_ASSERT(index != kInvalidIndex);
586
587 keySourceLength = GetKeySourceLength(mPsdu[index] & kKeyIdModeMask);
588
589 mPsdu[index + kSecurityControlSize + kFrameCounterSize + keySourceLength] = aKeyId;
590 }
591
GetCommandId(uint8_t & aCommandId) const592 Error Frame::GetCommandId(uint8_t &aCommandId) const
593 {
594 Error error = kErrorNone;
595 uint8_t index = FindPayloadIndex();
596
597 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
598
599 aCommandId = mPsdu[IsVersion2015() ? index : (index - 1)];
600
601 exit:
602 return error;
603 }
604
SetCommandId(uint8_t aCommandId)605 Error Frame::SetCommandId(uint8_t aCommandId)
606 {
607 Error error = kErrorNone;
608 uint8_t index = FindPayloadIndex();
609
610 VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
611
612 mPsdu[IsVersion2015() ? index : (index - 1)] = aCommandId;
613
614 exit:
615 return error;
616 }
617
IsDataRequestCommand(void) const618 bool Frame::IsDataRequestCommand(void) const
619 {
620 bool isDataRequest = false;
621 uint8_t commandId;
622
623 VerifyOrExit(GetType() == kFcfFrameMacCmd);
624 SuccessOrExit(GetCommandId(commandId));
625 isDataRequest = (commandId == kMacCmdDataRequest);
626
627 exit:
628 return isDataRequest;
629 }
630
GetHeaderLength(void) const631 uint8_t Frame::GetHeaderLength(void) const
632 {
633 return static_cast<uint8_t>(GetPayload() - mPsdu);
634 }
635
GetFooterLength(void) const636 uint8_t Frame::GetFooterLength(void) const
637 {
638 uint8_t footerLength = static_cast<uint8_t>(GetFcsSize());
639 uint8_t index = FindSecurityHeaderIndex();
640
641 VerifyOrExit(index != kInvalidIndex);
642 footerLength += CalculateMicSize(mPsdu[index]);
643
644 exit:
645 return footerLength;
646 }
647
CalculateMicSize(uint8_t aSecurityControl)648 uint8_t Frame::CalculateMicSize(uint8_t aSecurityControl)
649 {
650 uint8_t micSize = 0;
651
652 switch (aSecurityControl & kSecLevelMask)
653 {
654 case kSecNone:
655 case kSecEnc:
656 micSize = kMic0Size;
657 break;
658
659 case kSecMic32:
660 case kSecEncMic32:
661 micSize = kMic32Size;
662 break;
663
664 case kSecMic64:
665 case kSecEncMic64:
666 micSize = kMic64Size;
667 break;
668
669 case kSecMic128:
670 case kSecEncMic128:
671 micSize = kMic128Size;
672 break;
673 }
674
675 return micSize;
676 }
677
GetMaxPayloadLength(void) const678 uint16_t Frame::GetMaxPayloadLength(void) const
679 {
680 return GetMtu() - (GetHeaderLength() + GetFooterLength());
681 }
682
GetPayloadLength(void) const683 uint16_t Frame::GetPayloadLength(void) const
684 {
685 return mLength - (GetHeaderLength() + GetFooterLength());
686 }
687
SetPayloadLength(uint16_t aLength)688 void Frame::SetPayloadLength(uint16_t aLength)
689 {
690 mLength = GetHeaderLength() + GetFooterLength() + aLength;
691 }
692
SkipSecurityHeaderIndex(void) const693 uint8_t Frame::SkipSecurityHeaderIndex(void) const
694 {
695 uint8_t index = SkipAddrFieldIndex();
696
697 VerifyOrExit(index != kInvalidIndex);
698
699 if (GetSecurityEnabled())
700 {
701 uint8_t securityControl;
702 uint8_t headerSize;
703
704 VerifyOrExit(index < mLength, index = kInvalidIndex);
705 securityControl = mPsdu[index];
706
707 headerSize = CalculateSecurityHeaderSize(securityControl);
708 VerifyOrExit(headerSize != kInvalidSize, index = kInvalidIndex);
709
710 index += headerSize;
711
712 VerifyOrExit(index <= mLength, index = kInvalidIndex);
713 }
714
715 exit:
716 return index;
717 }
718
CalculateSecurityHeaderSize(uint8_t aSecurityControl)719 uint8_t Frame::CalculateSecurityHeaderSize(uint8_t aSecurityControl)
720 {
721 uint8_t size = kSecurityControlSize + kFrameCounterSize;
722
723 VerifyOrExit((aSecurityControl & kSecLevelMask) != kSecNone, size = kInvalidSize);
724
725 switch (aSecurityControl & kKeyIdModeMask)
726 {
727 case kKeyIdMode0:
728 size += kKeySourceSizeMode0;
729 break;
730
731 case kKeyIdMode1:
732 size += kKeySourceSizeMode1 + kKeyIndexSize;
733 break;
734
735 case kKeyIdMode2:
736 size += kKeySourceSizeMode2 + kKeyIndexSize;
737 break;
738
739 case kKeyIdMode3:
740 size += kKeySourceSizeMode3 + kKeyIndexSize;
741 break;
742 }
743
744 exit:
745 return size;
746 }
747
SkipAddrFieldIndex(void) const748 uint8_t Frame::SkipAddrFieldIndex(void) const
749 {
750 uint8_t index;
751
752 VerifyOrExit(kFcfSize + kDsnSize + GetFcsSize() <= mLength, index = kInvalidIndex);
753
754 index = CalculateAddrFieldSize(GetFrameControlField());
755
756 exit:
757 return index;
758 }
759
CalculateAddrFieldSize(uint16_t aFcf)760 uint8_t Frame::CalculateAddrFieldSize(uint16_t aFcf)
761 {
762 uint8_t size = kFcfSize + kDsnSize;
763
764 // This static method calculates the size (number of bytes) of
765 // Address header field for a given Frame Control `aFcf` value.
766 // The size includes the Frame Control and Sequence Number fields
767 // along with Destination and Source PAN ID and Short/Extended
768 // Addresses. If the `aFcf` is not valid, this method returns
769 // `kInvalidSize`.
770
771 if (IsDstPanIdPresent(aFcf))
772 {
773 size += sizeof(PanId);
774 }
775
776 switch (aFcf & kFcfDstAddrMask)
777 {
778 case kFcfDstAddrNone:
779 break;
780
781 case kFcfDstAddrShort:
782 size += sizeof(ShortAddress);
783 break;
784
785 case kFcfDstAddrExt:
786 size += sizeof(ExtAddress);
787 break;
788
789 default:
790 ExitNow(size = kInvalidSize);
791 }
792
793 if (IsSrcPanIdPresent(aFcf))
794 {
795 size += sizeof(PanId);
796 }
797
798 switch (aFcf & kFcfSrcAddrMask)
799 {
800 case kFcfSrcAddrNone:
801 break;
802
803 case kFcfSrcAddrShort:
804 size += sizeof(ShortAddress);
805 break;
806
807 case kFcfSrcAddrExt:
808 size += sizeof(ExtAddress);
809 break;
810
811 default:
812 ExitNow(size = kInvalidSize);
813 }
814
815 exit:
816 return size;
817 }
818
FindPayloadIndex(void) const819 uint8_t Frame::FindPayloadIndex(void) const
820 {
821 // We use `uint16_t` for `index` to handle its potential roll-over
822 // while parsing and verifying Header IE(s).
823
824 uint16_t index = SkipSecurityHeaderIndex();
825
826 VerifyOrExit(index != kInvalidIndex);
827
828 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
829 if (IsIePresent())
830 {
831 uint8_t footerLength = GetFooterLength();
832
833 do
834 {
835 const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
836
837 index += sizeof(HeaderIe);
838 VerifyOrExit(index + footerLength <= mLength, index = kInvalidIndex);
839
840 index += ie->GetLength();
841 VerifyOrExit(index + footerLength <= mLength, index = kInvalidIndex);
842
843 if (ie->GetId() == Termination2Ie::kHeaderIeId)
844 {
845 break;
846 }
847
848 // If the `index + footerLength == mLength`, we exit the `while()`
849 // loop. This covers the case where frame contains one or more
850 // Header IEs but no data payload. In this case, spec does not
851 // require Header IE termination to be included (it is optional)
852 // since the end of frame can be determined from frame length and
853 // footer length.
854
855 } while (index + footerLength < mLength);
856
857 // Assume no Payload IE in current implementation
858 }
859 #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
860
861 if (!IsVersion2015() && (GetFrameControlField() & kFcfFrameTypeMask) == kFcfFrameMacCmd)
862 {
863 index += kCommandIdSize;
864 }
865
866 exit:
867 return static_cast<uint8_t>(index);
868 }
869
GetPayload(void) const870 const uint8_t *Frame::GetPayload(void) const
871 {
872 uint8_t index = FindPayloadIndex();
873 const uint8_t *payload;
874
875 VerifyOrExit(index != kInvalidIndex, payload = nullptr);
876 payload = &mPsdu[index];
877
878 exit:
879 return payload;
880 }
881
GetFooter(void) const882 const uint8_t *Frame::GetFooter(void) const
883 {
884 return mPsdu + mLength - GetFooterLength();
885 }
886
887 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
FindHeaderIeIndex(void) const888 uint8_t Frame::FindHeaderIeIndex(void) const
889 {
890 uint8_t index;
891
892 VerifyOrExit(IsIePresent(), index = kInvalidIndex);
893
894 index = SkipSecurityHeaderIndex();
895
896 exit:
897 return index;
898 }
899
900 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
AppendHeaderIeAt(uint8_t & aIndex)901 template <typename IeType> Error Frame::AppendHeaderIeAt(uint8_t &aIndex)
902 {
903 Error error = kErrorNone;
904
905 SuccessOrExit(error = InitIeHeaderAt(aIndex, IeType::kHeaderIeId, IeType::kIeContentSize));
906
907 InitIeContentAt<IeType>(aIndex);
908
909 exit:
910 return error;
911 }
912
InitIeHeaderAt(uint8_t & aIndex,uint8_t ieId,uint8_t ieContentSize)913 Error Frame::InitIeHeaderAt(uint8_t &aIndex, uint8_t ieId, uint8_t ieContentSize)
914 {
915 Error error = kErrorNone;
916
917 if (aIndex == 0)
918 {
919 aIndex = FindHeaderIeIndex();
920 }
921
922 VerifyOrExit(aIndex != kInvalidIndex, error = kErrorNotFound);
923
924 reinterpret_cast<HeaderIe *>(mPsdu + aIndex)->Init(ieId, ieContentSize);
925 aIndex += sizeof(HeaderIe);
926
927 mLength += sizeof(HeaderIe) + ieContentSize;
928 exit:
929 return error;
930 }
931
932 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
InitIeContentAt(uint8_t & aIndex)933 template <> void Frame::InitIeContentAt<TimeIe>(uint8_t &aIndex)
934 {
935 reinterpret_cast<TimeIe *>(mPsdu + aIndex)->Init();
936 aIndex += sizeof(TimeIe);
937 }
938 #endif
939
940 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
InitIeContentAt(uint8_t & aIndex)941 template <> void Frame::InitIeContentAt<CslIe>(uint8_t &aIndex)
942 {
943 aIndex += sizeof(CslIe);
944 }
945 #endif
946
InitIeContentAt(uint8_t & aIndex)947 template <> void Frame::InitIeContentAt<Termination2Ie>(uint8_t &aIndex)
948 {
949 OT_UNUSED_VARIABLE(aIndex);
950 }
951 #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
952
GetHeaderIe(uint8_t aIeId) const953 const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
954 {
955 uint8_t index = FindHeaderIeIndex();
956 uint8_t payloadIndex = FindPayloadIndex();
957 const uint8_t *header = nullptr;
958
959 // `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
960 // are well-formed.
961
962 VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
963
964 while (index <= payloadIndex)
965 {
966 const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
967
968 if (ie->GetId() == aIeId)
969 {
970 header = &mPsdu[index];
971 ExitNow();
972 }
973
974 index += sizeof(HeaderIe) + ie->GetLength();
975 }
976
977 exit:
978 return header;
979 }
980
981 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
GetThreadIe(uint8_t aSubType) const982 const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const
983 {
984 uint8_t index = FindHeaderIeIndex();
985 uint8_t payloadIndex = FindPayloadIndex();
986 const uint8_t *header = nullptr;
987
988 // `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
989 // are well-formed.
990 VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
991
992 while (index <= payloadIndex)
993 {
994 const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
995
996 if (ie->GetId() == VendorIeHeader::kHeaderIeId)
997 {
998 const VendorIeHeader *vendorIe =
999 reinterpret_cast<const VendorIeHeader *>(reinterpret_cast<const uint8_t *>(ie) + sizeof(HeaderIe));
1000 if (vendorIe->GetVendorOui() == ThreadIe::kVendorOuiThreadCompanyId && vendorIe->GetSubType() == aSubType)
1001 {
1002 header = &mPsdu[index];
1003 ExitNow();
1004 }
1005 }
1006
1007 index += sizeof(HeaderIe) + ie->GetLength();
1008 }
1009
1010 exit:
1011 return header;
1012 }
1013 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1014
1015 #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
1016
1017 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
SetCslIe(uint16_t aCslPeriod,uint16_t aCslPhase)1018 void Frame::SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase)
1019 {
1020 uint8_t *cur = GetHeaderIe(CslIe::kHeaderIeId);
1021 CslIe * csl;
1022
1023 VerifyOrExit(cur != nullptr);
1024
1025 csl = reinterpret_cast<CslIe *>(cur + sizeof(HeaderIe));
1026 csl->SetPeriod(aCslPeriod);
1027 csl->SetPhase(aCslPhase);
1028 exit:
1029 return;
1030 }
1031 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1032
1033 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
SetEnhAckProbingIe(const uint8_t * aValue,uint8_t aLen)1034 void Frame::SetEnhAckProbingIe(const uint8_t *aValue, uint8_t aLen)
1035 {
1036 uint8_t *cur = GetThreadIe(ThreadIe::kEnhAckProbingIe);
1037
1038 OT_ASSERT(cur != nullptr);
1039
1040 memcpy(cur + sizeof(HeaderIe) + sizeof(VendorIeHeader), aValue, aLen);
1041 }
1042 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1043
1044 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
GetTimeIe(void) const1045 const TimeIe *Frame::GetTimeIe(void) const
1046 {
1047 const TimeIe * timeIe = nullptr;
1048 const uint8_t *cur = nullptr;
1049
1050 cur = GetHeaderIe(VendorIeHeader::kHeaderIeId);
1051 VerifyOrExit(cur != nullptr);
1052
1053 cur += sizeof(HeaderIe);
1054
1055 timeIe = reinterpret_cast<const TimeIe *>(cur);
1056 VerifyOrExit(timeIe->GetVendorOui() == TimeIe::kVendorOuiNest, timeIe = nullptr);
1057 VerifyOrExit(timeIe->GetSubType() == TimeIe::kVendorIeTime, timeIe = nullptr);
1058
1059 exit:
1060 return timeIe;
1061 }
1062 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1063
1064 #if OPENTHREAD_CONFIG_MULTI_RADIO
GetMtu(void) const1065 uint16_t Frame::GetMtu(void) const
1066 {
1067 uint16_t mtu = 0;
1068
1069 switch (GetRadioType())
1070 {
1071 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
1072 case kRadioTypeIeee802154:
1073 mtu = OT_RADIO_FRAME_MAX_SIZE;
1074 break;
1075 #endif
1076
1077 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
1078 case kRadioTypeTrel:
1079 mtu = Trel::Link::kMtuSize;
1080 break;
1081 #endif
1082 }
1083
1084 return mtu;
1085 }
1086
GetFcsSize(void) const1087 uint8_t Frame::GetFcsSize(void) const
1088 {
1089 uint8_t fcsSize = 0;
1090
1091 switch (GetRadioType())
1092 {
1093 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
1094 case kRadioTypeIeee802154:
1095 fcsSize = k154FcsSize;
1096 break;
1097 #endif
1098
1099 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
1100 case kRadioTypeTrel:
1101 fcsSize = Trel::Link::kFcsSize;
1102 break;
1103 #endif
1104 }
1105
1106 return fcsSize;
1107 }
1108
1109 #elif OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
GetMtu(void) const1110 uint16_t Frame::GetMtu(void) const
1111 {
1112 return Trel::Link::kMtuSize;
1113 }
1114
GetFcsSize(void) const1115 uint8_t Frame::GetFcsSize(void) const
1116 {
1117 return Trel::Link::kFcsSize;
1118 }
1119 #endif
1120
1121 // Explicit instantiation
1122 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
1123 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1124 template Error Frame::AppendHeaderIeAt<TimeIe>(uint8_t &aIndex);
1125 #endif
1126 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1127 template Error Frame::AppendHeaderIeAt<CslIe>(uint8_t &aIndex);
1128 #endif
1129 template Error Frame::AppendHeaderIeAt<Termination2Ie>(uint8_t &aIndex);
1130 #endif
1131
CopyFrom(const TxFrame & aFromFrame)1132 void TxFrame::CopyFrom(const TxFrame &aFromFrame)
1133 {
1134 uint8_t * psduBuffer = mPsdu;
1135 otRadioIeInfo *ieInfoBuffer = mInfo.mTxInfo.mIeInfo;
1136 #if OPENTHREAD_CONFIG_MULTI_RADIO
1137 uint8_t radioType = mRadioType;
1138 #endif
1139
1140 memcpy(this, &aFromFrame, sizeof(Frame));
1141
1142 // Set the original buffer pointers (and link type) back on
1143 // the frame (which were overwritten by above `memcpy()`).
1144
1145 mPsdu = psduBuffer;
1146 mInfo.mTxInfo.mIeInfo = ieInfoBuffer;
1147
1148 #if OPENTHREAD_CONFIG_MULTI_RADIO
1149 mRadioType = radioType;
1150 #endif
1151
1152 memcpy(mPsdu, aFromFrame.mPsdu, aFromFrame.mLength);
1153
1154 // mIeInfo may be null when TIME_SYNC is not enabled.
1155 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1156 memcpy(mInfo.mTxInfo.mIeInfo, aFromFrame.mInfo.mTxInfo.mIeInfo, sizeof(otRadioIeInfo));
1157 #endif
1158
1159 #if OPENTHREAD_CONFIG_MULTI_RADIO
1160 if (mRadioType != aFromFrame.GetRadioType())
1161 {
1162 // Frames associated with different radio link types can have
1163 // different FCS size. We adjust the PSDU length after the
1164 // copy to account for this.
1165
1166 SetLength(aFromFrame.GetPsduLength() - aFromFrame.GetFcsSize() + GetFcsSize());
1167 }
1168 #endif
1169 }
1170
ProcessTransmitAesCcm(const ExtAddress & aExtAddress)1171 void TxFrame::ProcessTransmitAesCcm(const ExtAddress &aExtAddress)
1172 {
1173 #if OPENTHREAD_RADIO && !OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
1174 OT_UNUSED_VARIABLE(aExtAddress);
1175 #else
1176 uint32_t frameCounter = 0;
1177 uint8_t securityLevel;
1178 uint8_t nonce[Crypto::AesCcm::kNonceSize];
1179 uint8_t tagLength;
1180 Crypto::AesCcm aesCcm;
1181
1182 VerifyOrExit(GetSecurityEnabled());
1183
1184 SuccessOrExit(GetSecurityLevel(securityLevel));
1185 SuccessOrExit(GetFrameCounter(frameCounter));
1186
1187 Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
1188
1189 aesCcm.SetKey(GetAesKey());
1190 tagLength = GetFooterLength() - GetFcsSize();
1191
1192 aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
1193 aesCcm.Header(GetHeader(), GetHeaderLength());
1194 aesCcm.Payload(GetPayload(), GetPayload(), GetPayloadLength(), Crypto::AesCcm::kEncrypt);
1195 aesCcm.Finalize(GetFooter());
1196
1197 SetIsSecurityProcessed(true);
1198
1199 exit:
1200 return;
1201 #endif // OPENTHREAD_RADIO && !OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
1202 }
1203
GenerateImmAck(const RxFrame & aFrame,bool aIsFramePending)1204 void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
1205 {
1206 uint16_t fcf = kFcfFrameAck | aFrame.GetVersion();
1207
1208 mChannel = aFrame.mChannel;
1209 memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo));
1210
1211 if (aIsFramePending)
1212 {
1213 fcf |= kFcfFramePending;
1214 }
1215 WriteUint16(fcf, mPsdu);
1216
1217 mPsdu[kSequenceIndex] = aFrame.GetSequence();
1218
1219 mLength = kImmAckLength;
1220 }
1221
1222 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
GenerateEnhAck(const RxFrame & aFrame,bool aIsFramePending,const uint8_t * aIeData,uint8_t aIeLength)1223 Error TxFrame::GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength)
1224 {
1225 Error error = kErrorNone;
1226
1227 uint16_t fcf = kFcfFrameAck | kFcfFrameVersion2015 | kFcfSrcAddrNone;
1228 Address address;
1229 PanId panId;
1230 uint8_t footerLength;
1231 uint8_t securityControlField;
1232 uint8_t keyId;
1233
1234 mChannel = aFrame.mChannel;
1235 memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo));
1236
1237 // Set frame control field
1238 if (aIsFramePending)
1239 {
1240 fcf |= kFcfFramePending;
1241 }
1242
1243 if (aFrame.GetSecurityEnabled())
1244 {
1245 fcf |= kFcfSecurityEnabled;
1246 }
1247
1248 if (aFrame.IsPanIdCompressed())
1249 {
1250 fcf |= kFcfPanidCompression;
1251 }
1252
1253 // Destination address mode
1254 if ((aFrame.GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrExt)
1255 {
1256 fcf |= kFcfDstAddrExt;
1257 }
1258 else if ((aFrame.GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrShort)
1259 {
1260 fcf |= kFcfDstAddrShort;
1261 }
1262 else
1263 {
1264 fcf |= kFcfDstAddrNone;
1265 }
1266
1267 if (aIeLength > 0)
1268 {
1269 fcf |= kFcfIePresent;
1270 }
1271
1272 WriteUint16(fcf, mPsdu);
1273
1274 // Set sequence number
1275 mPsdu[kSequenceIndex] = aFrame.GetSequence();
1276
1277 if (IsDstPanIdPresent())
1278 {
1279 // Set address field
1280 if (aFrame.IsSrcPanIdPresent())
1281 {
1282 SuccessOrExit(error = aFrame.GetSrcPanId(panId));
1283 }
1284 else if (aFrame.IsDstPanIdPresent())
1285 {
1286 SuccessOrExit(error = aFrame.GetDstPanId(panId));
1287 }
1288 else
1289 {
1290 ExitNow(error = kErrorParse);
1291 }
1292
1293 SetDstPanId(panId);
1294 }
1295
1296 if (aFrame.IsSrcAddrPresent())
1297 {
1298 SuccessOrExit(error = aFrame.GetSrcAddr(address));
1299 SetDstAddr(address);
1300 }
1301
1302 // At this time the length of ACK hasn't been determined, set it to
1303 // `kMaxPsduSize` to call methods that check frame length
1304 mLength = kMaxPsduSize;
1305
1306 // Set security header
1307 if (aFrame.GetSecurityEnabled())
1308 {
1309 SuccessOrExit(error = aFrame.GetSecurityControlField(securityControlField));
1310 SuccessOrExit(error = aFrame.GetKeyId(keyId));
1311
1312 SetSecurityControlField(securityControlField);
1313 SetKeyId(keyId);
1314 }
1315
1316 // Set header IE
1317 if (aIeLength > 0)
1318 {
1319 OT_ASSERT(aIeData != nullptr);
1320 memcpy(&mPsdu[FindHeaderIeIndex()], aIeData, aIeLength);
1321 }
1322
1323 // Set frame length
1324 footerLength = GetFooterLength();
1325 OT_ASSERT(footerLength != kInvalidIndex);
1326 mLength = SkipSecurityHeaderIndex() + aIeLength + footerLength;
1327
1328 exit:
1329 return error;
1330 }
1331 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
1332
ProcessReceiveAesCcm(const ExtAddress & aExtAddress,const KeyMaterial & aMacKey)1333 Error RxFrame::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey)
1334 {
1335 #if OPENTHREAD_RADIO
1336 OT_UNUSED_VARIABLE(aExtAddress);
1337 OT_UNUSED_VARIABLE(aMacKey);
1338
1339 return kErrorNone;
1340 #else
1341 Error error = kErrorSecurity;
1342 uint32_t frameCounter = 0;
1343 uint8_t securityLevel;
1344 uint8_t nonce[Crypto::AesCcm::kNonceSize];
1345 uint8_t tag[kMaxMicSize];
1346 uint8_t tagLength;
1347 Crypto::AesCcm aesCcm;
1348
1349 VerifyOrExit(GetSecurityEnabled(), error = kErrorNone);
1350
1351 SuccessOrExit(GetSecurityLevel(securityLevel));
1352 SuccessOrExit(GetFrameCounter(frameCounter));
1353
1354 Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
1355
1356 aesCcm.SetKey(aMacKey);
1357 tagLength = GetFooterLength() - GetFcsSize();
1358
1359 aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
1360 aesCcm.Header(GetHeader(), GetHeaderLength());
1361 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1362 aesCcm.Payload(GetPayload(), GetPayload(), GetPayloadLength(), Crypto::AesCcm::kDecrypt);
1363 #else
1364 // For fuzz tests, execute AES but do not alter the payload
1365 uint8_t fuzz[OT_RADIO_FRAME_MAX_SIZE];
1366 aesCcm.Payload(fuzz, GetPayload(), GetPayloadLength(), Crypto::AesCcm::kDecrypt);
1367 #endif
1368 aesCcm.Finalize(tag);
1369
1370 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1371 VerifyOrExit(memcmp(tag, GetFooter(), tagLength) == 0);
1372 #endif
1373
1374 error = kErrorNone;
1375
1376 exit:
1377 return error;
1378 #endif // OPENTHREAD_RADIO
1379 }
1380
1381 // LCOV_EXCL_START
1382
1383 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
1384
ToInfoString(void) const1385 Frame::InfoString Frame::ToInfoString(void) const
1386 {
1387 InfoString string;
1388 uint8_t commandId, type;
1389 Address src, dst;
1390
1391 string.Append("len:%d, seqnum:%d, type:", mLength, GetSequence());
1392
1393 type = GetType();
1394
1395 switch (type)
1396 {
1397 case kFcfFrameBeacon:
1398 string.Append("Beacon");
1399 break;
1400
1401 case kFcfFrameData:
1402 string.Append("Data");
1403 break;
1404
1405 case kFcfFrameAck:
1406 string.Append("Ack");
1407 break;
1408
1409 case kFcfFrameMacCmd:
1410 if (GetCommandId(commandId) != kErrorNone)
1411 {
1412 commandId = 0xff;
1413 }
1414
1415 switch (commandId)
1416 {
1417 case kMacCmdDataRequest:
1418 string.Append("Cmd(DataReq)");
1419 break;
1420
1421 case kMacCmdBeaconRequest:
1422 string.Append("Cmd(BeaconReq)");
1423 break;
1424
1425 default:
1426 string.Append("Cmd(%d)", commandId);
1427 break;
1428 }
1429
1430 break;
1431
1432 default:
1433 string.Append("%d", type);
1434 break;
1435 }
1436
1437 IgnoreError(GetSrcAddr(src));
1438 IgnoreError(GetDstAddr(dst));
1439
1440 string.Append(", src:%s, dst:%s, sec:%s, ackreq:%s", src.ToString().AsCString(), dst.ToString().AsCString(),
1441 ToYesNo(GetSecurityEnabled()), ToYesNo(GetAckRequest()));
1442
1443 #if OPENTHREAD_CONFIG_MULTI_RADIO
1444 string.Append(", radio:%s", RadioTypeToString(GetRadioType()));
1445 #endif
1446
1447 return string;
1448 }
1449
1450 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
1451
1452 // LCOV_EXCL_STOP
1453
1454 } // namespace Mac
1455 } // namespace ot
1456