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