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