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