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