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