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