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