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