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