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