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