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