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 #include "common/code_utils.hpp"
30 #include "common/debug.hpp"
31 #include "mac/mac.hpp"
32 #include "mac/mac_frame.hpp"
33 #include "radio/radio.hpp"
34 
35 #include "test_platform.h"
36 #include "test_util.hpp"
37 
38 namespace ot {
39 
CompareReversed(const uint8_t * aFirst,const uint8_t * aSecond,uint16_t aLength)40 bool CompareReversed(const uint8_t *aFirst, const uint8_t *aSecond, uint16_t aLength)
41 {
42     bool matches = true;
43 
44     for (uint16_t i = 0; i < aLength; i++)
45     {
46         if (aFirst[i] != aSecond[aLength - 1 - i])
47         {
48             matches = false;
49             break;
50         }
51     }
52 
53     return matches;
54 }
55 
CompareAddresses(const Mac::Address & aFirst,const Mac::Address & aSecond)56 bool CompareAddresses(const Mac::Address &aFirst, const Mac::Address &aSecond)
57 {
58     bool matches = false;
59 
60     VerifyOrExit(aFirst.GetType() == aSecond.GetType());
61 
62     switch (aFirst.GetType())
63     {
64     case Mac::Address::kTypeNone:
65         break;
66     case Mac::Address::kTypeShort:
67         VerifyOrExit(aFirst.GetShort() == aSecond.GetShort());
68         break;
69     case Mac::Address::kTypeExtended:
70         VerifyOrExit(aFirst.GetExtended() == aSecond.GetExtended());
71         break;
72     }
73 
74     matches = true;
75 
76 exit:
77     return matches;
78 }
79 
TestMacAddress(void)80 void TestMacAddress(void)
81 {
82     const uint8_t           kExtAddr[OT_EXT_ADDRESS_SIZE] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
83     const Mac::ShortAddress kShortAddr                    = 0x1234;
84 
85     Instance       *instance;
86     Mac::Address    addr;
87     Mac::ExtAddress extAddr;
88     uint8_t         buffer[OT_EXT_ADDRESS_SIZE];
89 
90     instance = testInitInstance();
91     VerifyOrQuit(instance != nullptr, "nullptr instance\n");
92 
93     // Mac::ExtAddress
94 
95     extAddr.GenerateRandom();
96     VerifyOrQuit(extAddr.IsLocal(), "Random Extended Address should have its Local bit set");
97     VerifyOrQuit(!extAddr.IsGroup(), "Random Extended Address should not have its Group bit set");
98 
99     extAddr.CopyTo(buffer);
100     VerifyOrQuit(memcmp(extAddr.m8, buffer, OT_EXT_ADDRESS_SIZE) == 0);
101 
102     extAddr.CopyTo(buffer, Mac::ExtAddress::kReverseByteOrder);
103     VerifyOrQuit(CompareReversed(extAddr.m8, buffer, OT_EXT_ADDRESS_SIZE));
104 
105     extAddr.Set(kExtAddr);
106     VerifyOrQuit(memcmp(extAddr.m8, kExtAddr, OT_EXT_ADDRESS_SIZE) == 0);
107 
108     extAddr.Set(kExtAddr, Mac::ExtAddress::kReverseByteOrder);
109     VerifyOrQuit(CompareReversed(extAddr.m8, kExtAddr, OT_EXT_ADDRESS_SIZE));
110 
111     extAddr.SetLocal(true);
112     VerifyOrQuit(extAddr.IsLocal());
113     extAddr.SetLocal(false);
114     VerifyOrQuit(!extAddr.IsLocal());
115     extAddr.ToggleLocal();
116     VerifyOrQuit(extAddr.IsLocal());
117     extAddr.ToggleLocal();
118     VerifyOrQuit(!extAddr.IsLocal());
119 
120     extAddr.SetGroup(true);
121     VerifyOrQuit(extAddr.IsGroup());
122     extAddr.SetGroup(false);
123     VerifyOrQuit(!extAddr.IsGroup());
124     extAddr.ToggleGroup();
125     VerifyOrQuit(extAddr.IsGroup());
126     extAddr.ToggleGroup();
127     VerifyOrQuit(!extAddr.IsGroup());
128 
129     // Mac::Address
130 
131     VerifyOrQuit(addr.IsNone(), "Address constructor failed");
132     VerifyOrQuit(addr.GetType() == Mac::Address::kTypeNone);
133 
134     addr.SetShort(kShortAddr);
135     VerifyOrQuit(addr.GetType() == Mac::Address::kTypeShort);
136     VerifyOrQuit(addr.IsShort(), "Address::SetShort() failed");
137     VerifyOrQuit(!addr.IsExtended(), "Address::SetShort() failed");
138     VerifyOrQuit(addr.GetShort() == kShortAddr);
139 
140     addr.SetExtended(extAddr);
141     VerifyOrQuit(addr.GetType() == Mac::Address::kTypeExtended);
142     VerifyOrQuit(!addr.IsShort(), "Address::SetExtended() failed");
143     VerifyOrQuit(addr.IsExtended(), "Address::SetExtended() failed");
144     VerifyOrQuit(addr.GetExtended() == extAddr);
145 
146     addr.SetExtended(extAddr.m8, Mac::ExtAddress::kReverseByteOrder);
147     VerifyOrQuit(addr.GetType() == Mac::Address::kTypeExtended);
148     VerifyOrQuit(!addr.IsShort(), "Address::SetExtended() failed");
149     VerifyOrQuit(addr.IsExtended(), "Address::SetExtended() failed");
150     VerifyOrQuit(CompareReversed(addr.GetExtended().m8, extAddr.m8, OT_EXT_ADDRESS_SIZE),
151                  "Address::SetExtended() reverse byte order failed");
152 
153     addr.SetNone();
154     VerifyOrQuit(addr.GetType() == Mac::Address::kTypeNone);
155     VerifyOrQuit(addr.IsNone(), "Address:SetNone() failed");
156     VerifyOrQuit(!addr.IsShort(), "Address::SetNone() failed");
157     VerifyOrQuit(!addr.IsExtended(), "Address::SetNone() failed");
158 
159     VerifyOrQuit(!addr.IsBroadcast(), "Address:SetNone() failed");
160     VerifyOrQuit(!addr.IsShortAddrInvalid());
161 
162     addr.SetExtended(extAddr);
163     VerifyOrQuit(!addr.IsBroadcast());
164     VerifyOrQuit(!addr.IsShortAddrInvalid());
165 
166     addr.SetShort(kShortAddr);
167     VerifyOrQuit(!addr.IsBroadcast());
168     VerifyOrQuit(!addr.IsShortAddrInvalid());
169 
170     addr.SetShort(Mac::kShortAddrBroadcast);
171     VerifyOrQuit(addr.IsBroadcast());
172     VerifyOrQuit(!addr.IsShortAddrInvalid());
173 
174     addr.SetShort(Mac::kShortAddrInvalid);
175     VerifyOrQuit(!addr.IsBroadcast());
176     VerifyOrQuit(addr.IsShortAddrInvalid());
177 
178     testFreeInstance(instance);
179 }
180 
TestMacHeader(void)181 void TestMacHeader(void)
182 {
183     enum AddrType : uint8_t
184     {
185         kNoneAddr,
186         kShrtAddr,
187         kExtdAddr,
188     };
189 
190     enum PanIdMode
191     {
192         kNoPanId,
193         kUsePanId1,
194         kUsePanId2,
195     };
196 
197     struct TestCase
198     {
199         Mac::Frame::Version       mVersion;
200         AddrType                  mSrcAddrType;
201         PanIdMode                 mSrcPanIdMode;
202         AddrType                  mDstAddrType;
203         PanIdMode                 mDstPanIdMode;
204         Mac::Frame::SecurityLevel mSecurity;
205         Mac::Frame::KeyIdMode     mKeyIdMode;
206         uint8_t                   mHeaderLength;
207         uint8_t                   mFooterLength;
208         bool                      mSuppressSequence;
209     };
210 
211     static constexpr Mac::Frame::Version kVer2006 = Mac::Frame::kVersion2006;
212     static constexpr Mac::Frame::Version kVer2015 = Mac::Frame::kVersion2015;
213 
214     static constexpr Mac::Frame::SecurityLevel kNoSec = Mac::Frame::kSecurityNone;
215     static constexpr Mac::Frame::SecurityLevel kMic32 = Mac::Frame::kSecurityMic32;
216 
217     static constexpr Mac::Frame::KeyIdMode kModeId1 = Mac::Frame::kKeyIdMode1;
218     static constexpr Mac::Frame::KeyIdMode kModeId2 = Mac::Frame::kKeyIdMode2;
219 
220     static const char *kAddrTypeStrings[]  = {"None", "Short", "Extd"};
221     static const char *kPanIdModeStrings[] = {"No", "Id1", "Id2"};
222 
223     static constexpr TestCase kTestCases[] = {
224         {kVer2006, kNoneAddr, kNoPanId, kNoneAddr, kNoPanId, kNoSec, kModeId1, 3, 2},
225         {kVer2006, kShrtAddr, kUsePanId1, kNoneAddr, kNoPanId, kNoSec, kModeId1, 7, 2},
226         {kVer2006, kExtdAddr, kUsePanId1, kNoneAddr, kNoPanId, kNoSec, kModeId1, 13, 2},
227         {kVer2006, kNoneAddr, kNoPanId, kShrtAddr, kUsePanId1, kNoSec, kModeId1, 7, 2},
228         {kVer2006, kNoneAddr, kNoPanId, kExtdAddr, kUsePanId1, kNoSec, kModeId1, 13, 2},
229         {kVer2006, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId2, kNoSec, kModeId1, 11, 2},
230         {kVer2006, kShrtAddr, kUsePanId1, kExtdAddr, kUsePanId2, kNoSec, kModeId1, 17, 2},
231         {kVer2006, kExtdAddr, kUsePanId1, kShrtAddr, kUsePanId2, kNoSec, kModeId1, 17, 2},
232         {kVer2006, kExtdAddr, kUsePanId1, kExtdAddr, kUsePanId2, kNoSec, kModeId1, 23, 2},
233         {kVer2006, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId1, kNoSec, kModeId1, 9, 2},
234         {kVer2006, kShrtAddr, kUsePanId1, kExtdAddr, kUsePanId1, kNoSec, kModeId1, 15, 2},
235         {kVer2006, kExtdAddr, kUsePanId1, kShrtAddr, kUsePanId1, kNoSec, kModeId1, 15, 2},
236         {kVer2006, kExtdAddr, kUsePanId1, kExtdAddr, kUsePanId1, kNoSec, kModeId1, 21, 2},
237         {kVer2006, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId1, kMic32, kModeId1, 15, 6},
238         {kVer2006, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId1, kMic32, kModeId2, 19, 6},
239 
240         {kVer2015, kNoneAddr, kNoPanId, kNoneAddr, kNoPanId, kNoSec, kModeId1, 3, 2},
241         {kVer2015, kShrtAddr, kUsePanId1, kNoneAddr, kNoPanId, kNoSec, kModeId1, 7, 2},
242         {kVer2015, kExtdAddr, kUsePanId1, kNoneAddr, kNoPanId, kNoSec, kModeId1, 13, 2},
243         {kVer2015, kNoneAddr, kNoPanId, kShrtAddr, kUsePanId1, kNoSec, kModeId1, 7, 2},
244         {kVer2015, kNoneAddr, kNoPanId, kExtdAddr, kUsePanId1, kNoSec, kModeId1, 13, 2},
245         {kVer2015, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId2, kNoSec, kModeId1, 11, 2},
246         {kVer2015, kShrtAddr, kUsePanId1, kExtdAddr, kUsePanId2, kNoSec, kModeId1, 17, 2},
247         {kVer2015, kExtdAddr, kUsePanId1, kShrtAddr, kUsePanId2, kNoSec, kModeId1, 17, 2},
248         {kVer2015, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId1, kNoSec, kModeId1, 9, 2},
249         {kVer2015, kShrtAddr, kUsePanId1, kExtdAddr, kUsePanId1, kNoSec, kModeId1, 15, 2},
250         {kVer2015, kExtdAddr, kUsePanId1, kShrtAddr, kUsePanId1, kNoSec, kModeId1, 15, 2},
251         {kVer2015, kExtdAddr, kUsePanId1, kExtdAddr, kUsePanId1, kNoSec, kModeId1, 21, 2},
252         {kVer2015, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId1, kMic32, kModeId1, 15, 6},
253         {kVer2015, kShrtAddr, kUsePanId1, kShrtAddr, kUsePanId1, kMic32, kModeId2, 19, 6},
254 
255         {kVer2015, kNoneAddr, kNoPanId, kShrtAddr, kNoPanId, kNoSec, kModeId1, 5, 2},
256         {kVer2015, kNoneAddr, kNoPanId, kShrtAddr, kNoPanId, kMic32, kModeId1, 11, 6},
257         {kVer2015, kNoneAddr, kNoPanId, kNoneAddr, kUsePanId1, kNoSec, kModeId1, 5, 2},
258         {kVer2015, kNoneAddr, kNoPanId, kNoneAddr, kUsePanId1, kMic32, kModeId1, 11, 6},
259         {kVer2015, kNoneAddr, kNoPanId, kShrtAddr, kNoPanId, kNoSec, kModeId1, 5, 2},
260         {kVer2015, kNoneAddr, kNoPanId, kExtdAddr, kNoPanId, kNoSec, kModeId1, 11, 2},
261         {kVer2015, kNoneAddr, kNoPanId, kShrtAddr, kNoPanId, kMic32, kModeId1, 11, 6},
262         {kVer2015, kNoneAddr, kNoPanId, kExtdAddr, kNoPanId, kMic32, kModeId1, 17, 6},
263         {kVer2015, kShrtAddr, kNoPanId, kNoneAddr, kNoPanId, kNoSec, kModeId1, 5, 2},
264         {kVer2015, kShrtAddr, kNoPanId, kNoneAddr, kNoPanId, kMic32, kModeId1, 11, 6},
265         {kVer2015, kExtdAddr, kNoPanId, kNoneAddr, kNoPanId, kNoSec, kModeId1, 11, 2},
266         {kVer2015, kExtdAddr, kNoPanId, kNoneAddr, kNoPanId, kMic32, kModeId1, 17, 6},
267         {kVer2015, kExtdAddr, kNoPanId, kExtdAddr, kNoPanId, kNoSec, kModeId1, 19, 2},
268         {kVer2015, kExtdAddr, kNoPanId, kExtdAddr, kNoPanId, kMic32, kModeId1, 25, 6},
269         {kVer2015, kExtdAddr, kNoPanId, kExtdAddr, kNoPanId, kMic32, kModeId1, 24, 6, true},
270     };
271 
272     const uint16_t kPanId1     = 0xbaba;
273     const uint16_t kPanId2     = 0xdede;
274     const uint16_t kShortAddr1 = 0x1234;
275     const uint16_t kShortAddr2 = 0x5678;
276     const uint8_t  kExtAddr1[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
277     const uint8_t  kExtAddr2[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
278 
279     char            string[100];
280     Mac::ExtAddress extAddr1;
281     Mac::ExtAddress extAddr2;
282 
283     extAddr1.Set(kExtAddr1);
284     extAddr2.Set(kExtAddr2);
285 
286     printf("TestMacHeader\n");
287 
288     for (const TestCase &testCase : kTestCases)
289     {
290         uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
291         uint8_t offset;
292 
293         Mac::TxFrame       frame;
294         Mac::TxFrame::Info frameInfo;
295         Mac::Address       address;
296         Mac::PanId         panId;
297 
298         frame.mPsdu      = psdu;
299         frame.mLength    = 0;
300         frame.mRadioType = 0;
301 
302         VerifyOrQuit(frameInfo.mAddrs.mSource.IsNone());
303         VerifyOrQuit(frameInfo.mAddrs.mDestination.IsNone());
304         VerifyOrQuit(!frameInfo.mPanIds.IsSourcePresent());
305         VerifyOrQuit(!frameInfo.mPanIds.IsDestinationPresent());
306 
307         switch (testCase.mSrcAddrType)
308         {
309         case kNoneAddr:
310             frameInfo.mAddrs.mSource.SetNone();
311             break;
312         case kShrtAddr:
313             frameInfo.mAddrs.mSource.SetShort(kShortAddr1);
314             break;
315         case kExtdAddr:
316             frameInfo.mAddrs.mSource.SetExtended(extAddr1);
317             break;
318         }
319 
320         switch (testCase.mDstAddrType)
321         {
322         case kNoneAddr:
323             frameInfo.mAddrs.mDestination.SetNone();
324             break;
325         case kShrtAddr:
326             frameInfo.mAddrs.mDestination.SetShort(kShortAddr2);
327             break;
328         case kExtdAddr:
329             frameInfo.mAddrs.mDestination.SetExtended(extAddr2);
330             break;
331         }
332 
333         switch (testCase.mSrcPanIdMode)
334         {
335         case kNoPanId:
336             break;
337         case kUsePanId1:
338             frameInfo.mPanIds.SetSource(kPanId1);
339             break;
340         case kUsePanId2:
341             frameInfo.mPanIds.SetSource(kPanId2);
342             break;
343         }
344 
345         switch (testCase.mDstPanIdMode)
346         {
347         case kNoPanId:
348             break;
349         case kUsePanId1:
350             frameInfo.mPanIds.SetDestination(kPanId1);
351             break;
352         case kUsePanId2:
353             frameInfo.mPanIds.SetDestination(kPanId2);
354             break;
355         }
356 
357         frameInfo.mType             = Mac::Frame::kTypeData;
358         frameInfo.mVersion          = testCase.mVersion;
359         frameInfo.mSecurityLevel    = testCase.mSecurity;
360         frameInfo.mKeyIdMode        = testCase.mKeyIdMode;
361         frameInfo.mSuppressSequence = testCase.mSuppressSequence;
362 
363         frameInfo.PrepareHeadersIn(frame);
364 
365         VerifyOrQuit(frame.GetHeaderLength() == testCase.mHeaderLength);
366         VerifyOrQuit(frame.GetFooterLength() == testCase.mFooterLength);
367         VerifyOrQuit(frame.GetLength() == testCase.mHeaderLength + testCase.mFooterLength);
368 
369         VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeData);
370         VerifyOrQuit(!frame.IsAck());
371         VerifyOrQuit(frame.GetVersion() == testCase.mVersion);
372         VerifyOrQuit(frame.GetSecurityEnabled() == (testCase.mSecurity != kNoSec));
373         VerifyOrQuit(!frame.GetFramePending());
374         VerifyOrQuit(!frame.IsIePresent());
375         VerifyOrQuit(frame.GetAckRequest() == (testCase.mDstAddrType != kNoneAddr));
376 
377         VerifyOrQuit(frame.IsSrcAddrPresent() == (testCase.mSrcAddrType != kNoneAddr));
378         SuccessOrQuit(frame.GetSrcAddr(address));
379         VerifyOrQuit(CompareAddresses(address, frameInfo.mAddrs.mSource));
380         VerifyOrQuit(frame.IsDstAddrPresent() == (testCase.mDstAddrType != kNoneAddr));
381         SuccessOrQuit(frame.GetDstAddr(address));
382         VerifyOrQuit(CompareAddresses(address, frameInfo.mAddrs.mDestination));
383 
384         VerifyOrQuit(frame.IsDstPanIdPresent() == (testCase.mDstPanIdMode != kNoPanId));
385 
386         if (frame.IsDstPanIdPresent())
387         {
388             SuccessOrQuit(frame.GetDstPanId(panId));
389             VerifyOrQuit(panId == frameInfo.mPanIds.GetDestination());
390             VerifyOrQuit(frameInfo.mPanIds.IsDestinationPresent());
391         }
392 
393         if (frame.IsSrcPanIdPresent())
394         {
395             SuccessOrQuit(frame.GetSrcPanId(panId));
396             VerifyOrQuit(panId == frameInfo.mPanIds.GetSource());
397             VerifyOrQuit(frameInfo.mPanIds.IsSourcePresent());
398         }
399 
400         if (frame.GetSecurityEnabled())
401         {
402             uint8_t security;
403             uint8_t keyIdMode;
404 
405             SuccessOrQuit(frame.GetSecurityLevel(security));
406             VerifyOrQuit(security == testCase.mSecurity);
407 
408             SuccessOrQuit(frame.GetKeyIdMode(keyIdMode));
409             VerifyOrQuit(keyIdMode == testCase.mKeyIdMode);
410         }
411 
412         offset = snprintf(string, sizeof(string), "\nver:%s, src[addr:%s, pan:%s], dst[addr:%s, pan:%s], sec:%s",
413                           (testCase.mVersion == kVer2006) ? "2006" : "2015", kAddrTypeStrings[testCase.mSrcAddrType],
414                           kPanIdModeStrings[testCase.mSrcPanIdMode], kAddrTypeStrings[testCase.mDstAddrType],
415                           kPanIdModeStrings[testCase.mDstPanIdMode], testCase.mSecurity == kNoSec ? "no" : "mic32");
416 
417         if (!testCase.mSuppressSequence)
418         {
419             VerifyOrQuit(frame.IsSequencePresent());
420             offset += snprintf(string + offset, sizeof(string) - offset, ", seq:%u", frame.GetSequence());
421         }
422         else
423         {
424             VerifyOrQuit(!frame.IsSequencePresent());
425         }
426         DumpBuffer(string, frame.GetPsdu(), frame.GetLength());
427     }
428 }
429 
VerifyChannelMaskContent(const Mac::ChannelMask & aMask,uint8_t * aChannels,uint8_t aLength)430 void VerifyChannelMaskContent(const Mac::ChannelMask &aMask, uint8_t *aChannels, uint8_t aLength)
431 {
432     uint8_t index = 0;
433     uint8_t channel;
434 
435     for (channel = Radio::kChannelMin; channel <= Radio::kChannelMax; channel++)
436     {
437         if (index < aLength)
438         {
439             if (channel == aChannels[index])
440             {
441                 index++;
442                 VerifyOrQuit(aMask.ContainsChannel(channel));
443             }
444             else
445             {
446                 VerifyOrQuit(!aMask.ContainsChannel(channel));
447             }
448         }
449     }
450 
451     index   = 0;
452     channel = Mac::ChannelMask::kChannelIteratorFirst;
453 
454     while (aMask.GetNextChannel(channel) == kErrorNone)
455     {
456         VerifyOrQuit(channel == aChannels[index++], "ChannelMask.GetNextChannel() failed");
457     }
458 
459     VerifyOrQuit(index == aLength, "ChannelMask.GetNextChannel() failed");
460 
461     if (aLength == 1)
462     {
463         VerifyOrQuit(aMask.IsSingleChannel());
464     }
465     else
466     {
467         VerifyOrQuit(!aMask.IsSingleChannel());
468     }
469 
470     VerifyOrQuit(aLength == aMask.GetNumberOfChannels());
471 }
472 
TestMacChannelMask(void)473 void TestMacChannelMask(void)
474 {
475     uint8_t allChannels[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};
476     uint8_t channels1[]   = {11, 14, 15, 16, 17, 20, 21, 22, 24, 25};
477     uint8_t channels2[]   = {14, 21, 26};
478     uint8_t channels3[]   = {14, 21};
479     uint8_t channles4[]   = {20};
480 
481     static const char kEmptyMaskString[]   = "{ }";
482     static const char kAllChannelsString[] = "{ 11-26 }";
483     static const char kChannels1String[]   = "{ 11, 14-17, 20-22, 24, 25 }";
484     static const char kChannels2String[]   = "{ 14, 21, 26 }";
485     static const char kChannels3String[]   = "{ 14, 21 }";
486     static const char kChannels4String[]   = "{ 20 }";
487 
488     Mac::ChannelMask mask1;
489     Mac::ChannelMask mask2(Radio::kSupportedChannels);
490 
491     printf("Testing Mac::ChannelMask\n");
492 
493     VerifyOrQuit(mask1.IsEmpty());
494     printf("empty = %s\n", mask1.ToString().AsCString());
495     VerifyOrQuit(strcmp(mask1.ToString().AsCString(), kEmptyMaskString) == 0);
496 
497     VerifyOrQuit(!mask2.IsEmpty());
498     VerifyOrQuit(mask2.GetMask() == Radio::kSupportedChannels);
499     printf("allChannels = %s\n", mask2.ToString().AsCString());
500     VerifyOrQuit(strcmp(mask2.ToString().AsCString(), kAllChannelsString) == 0);
501 
502     mask1.SetMask(Radio::kSupportedChannels);
503     VerifyOrQuit(!mask1.IsEmpty());
504     VerifyOrQuit(mask1.GetMask() == Radio::kSupportedChannels);
505 
506     VerifyChannelMaskContent(mask1, allChannels, sizeof(allChannels));
507 
508     // Test ChannelMask::RemoveChannel()
509     for (size_t index = 0; index < sizeof(allChannels) - 1; index++)
510     {
511         mask1.RemoveChannel(allChannels[index]);
512         VerifyChannelMaskContent(mask1, &allChannels[index + 1], sizeof(allChannels) - 1 - index);
513     }
514 
515     mask1.Clear();
516     VerifyOrQuit(mask1.IsEmpty());
517     VerifyChannelMaskContent(mask1, nullptr, 0);
518 
519     for (uint8_t channel : channels1)
520     {
521         mask1.AddChannel(channel);
522     }
523 
524     printf("channels1 = %s\n", mask1.ToString().AsCString());
525     VerifyOrQuit(strcmp(mask1.ToString().AsCString(), kChannels1String) == 0);
526 
527     VerifyOrQuit(!mask1.IsEmpty());
528     VerifyChannelMaskContent(mask1, channels1, sizeof(channels1));
529 
530     mask2.Clear();
531 
532     for (uint8_t channel : channels2)
533     {
534         mask2.AddChannel(channel);
535     }
536 
537     printf("channels2 = %s\n", mask2.ToString().AsCString());
538     VerifyOrQuit(strcmp(mask2.ToString().AsCString(), kChannels2String) == 0);
539 
540     VerifyOrQuit(!mask2.IsEmpty());
541     VerifyChannelMaskContent(mask2, channels2, sizeof(channels2));
542 
543     mask1.Intersect(mask2);
544     VerifyChannelMaskContent(mask1, channels3, sizeof(channels3));
545     printf("channels3 = %s\n", mask1.ToString().AsCString());
546     VerifyOrQuit(strcmp(mask1.ToString().AsCString(), kChannels3String) == 0);
547 
548     mask2.Clear();
549     mask2.AddChannel(channles4[0]);
550     VerifyChannelMaskContent(mask2, channles4, sizeof(channles4));
551 
552     printf("channels4 = %s\n", mask2.ToString().AsCString());
553     VerifyOrQuit(strcmp(mask2.ToString().AsCString(), kChannels4String) == 0);
554 
555     mask1.Clear();
556     mask2.Clear();
557     VerifyOrQuit(mask1 == mask2);
558 
559     mask1.SetMask(Radio::kSupportedChannels);
560     mask2.SetMask(Radio::kSupportedChannels);
561     VerifyOrQuit(mask1 == mask2);
562 
563     mask1.Clear();
564     VerifyOrQuit(mask1 != mask2);
565 }
566 
TestMacFrameApi(void)567 void TestMacFrameApi(void)
568 {
569     uint8_t ack_psdu1[]     = {0x02, 0x10, 0x5e, 0xd2, 0x9b};
570     uint8_t mac_cmd_psdu1[] = {0x6b, 0xdc, 0x85, 0xce, 0xfa, 0x47, 0x36, 0x07, 0xd9, 0x74, 0x45, 0x8d,
571                                0xb2, 0x6e, 0x81, 0x25, 0xc9, 0xdb, 0xac, 0x2b, 0x0a, 0x0d, 0x00, 0x00,
572                                0x00, 0x00, 0x01, 0x04, 0xaf, 0x14, 0xce, 0xaa, 0x5a, 0xe5};
573 
574     Mac::Frame frame;
575 
576 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
577     uint8_t data_psdu1[]    = {0x29, 0xee, 0x53, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x05,
578                                0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x01};
579     uint8_t mac_cmd_psdu2[] = {0x6b, 0xaa, 0x8d, 0xce, 0xfa, 0x00, 0x68, 0x01, 0x68, 0x0d,
580                                0x08, 0x00, 0x00, 0x00, 0x01, 0x04, 0x0d, 0xed, 0x0b, 0x35,
581                                0x0c, 0x80, 0x3f, 0x04, 0x4b, 0x88, 0x89, 0xd6, 0x59, 0xe1};
582     uint8_t scf; // SecurityControlField
583 #endif
584 
585     // Imm-Ack, Sequence Number: 94
586     //   Frame Control Field: 0x1002
587     //     .... .... .... .010 = Frame Type: Ack (0x2)
588     //     .... .... .... 0... = Security Enabled: False
589     //     .... .... ...0 .... = Frame Pending: False
590     //     .... .... ..0. .... = Acknowledge Request: False
591     //     .... .... .0.. .... = PAN ID Compression: False
592     //     .... ...0 .... .... = Sequence Number Suppression: False
593     //     .... ..0. .... .... = Information Elements Present: False
594     //     .... 00.. .... .... = Destination Addressing Mode: None (0x0)
595     //     ..01 .... .... .... = Frame Version: IEEE Std 802.15.4-2006 (1)
596     //     00.. .... .... .... = Source Addressing Mode: None (0x0)
597     //   Sequence Number: 94
598     //   FCS: 0x9bd2 (Correct)
599     frame.mPsdu   = ack_psdu1;
600     frame.mLength = sizeof(ack_psdu1);
601     VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeAck);
602     VerifyOrQuit(!frame.GetSecurityEnabled());
603     VerifyOrQuit(!frame.GetFramePending());
604     VerifyOrQuit(!frame.GetAckRequest());
605     VerifyOrQuit(!frame.IsIePresent());
606     VerifyOrQuit(!frame.IsDstPanIdPresent());
607     VerifyOrQuit(!frame.IsDstAddrPresent());
608     VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
609     VerifyOrQuit(!frame.IsSrcAddrPresent());
610     VerifyOrQuit(frame.IsSequencePresent());
611     VerifyOrQuit(frame.GetSequence() == 94);
612 
613 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
614     // IEEE 802.15.4-2015 Data
615     //   Sequence Number: 83
616     //   Destination PAN: 0xface
617     //   Destination: 16:6e:0a:00:00:00:00:01
618     //   Extended Source: 16:6e:0a:00:00:00:00:05
619     //   Auxiliary Security Header
620     //     Security Control Field: 0x0d
621     frame.mPsdu   = data_psdu1;
622     frame.mLength = sizeof(data_psdu1);
623     VerifyOrQuit(frame.IsVersion2015());
624     VerifyOrQuit(frame.IsDstPanIdPresent());
625     VerifyOrQuit(frame.IsDstAddrPresent());
626     VerifyOrQuit(frame.IsSrcAddrPresent());
627     SuccessOrQuit(frame.GetSecurityControlField(scf));
628     VerifyOrQuit(scf == 0x0d);
629 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
630 
631     // IEEE 802.15.4-2006 Mac Command
632     //   Sequence Number: 133
633     //   Command Identifier: Data Request (0x04)
634     uint8_t commandId;
635     frame.mPsdu   = mac_cmd_psdu1;
636     frame.mLength = sizeof(mac_cmd_psdu1);
637     VerifyOrQuit(frame.IsSequencePresent());
638     VerifyOrQuit(frame.GetSequence() == 133);
639     VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
640     VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeMacCmd);
641     SuccessOrQuit(frame.GetCommandId(commandId));
642     VerifyOrQuit(commandId == Mac::Frame::kMacCmdDataRequest);
643 
644 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
645     // IEEE 802.15.4-2015 Mac Command
646     //   Sequence Number: 141
647     //   Header IEs
648     //     CSL IE
649     //     Header Termination 2 IE (Payload follows)
650     //   Command Identifier: Data Request (0x04)
651     frame.mPsdu   = mac_cmd_psdu2;
652     frame.mLength = sizeof(mac_cmd_psdu2);
653     VerifyOrQuit(frame.IsSequencePresent());
654     VerifyOrQuit(frame.GetSequence() == 141);
655     VerifyOrQuit(frame.IsVersion2015());
656     VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeMacCmd);
657     SuccessOrQuit(frame.GetCommandId(commandId));
658     VerifyOrQuit(commandId == Mac::Frame::kMacCmdDataRequest);
659     printf("commandId:%d\n", commandId);
660 
661 #endif
662 }
663 
TestMacFrameAckGeneration(void)664 void TestMacFrameAckGeneration(void)
665 {
666     constexpr uint8_t kImmAckLength = 5;
667 
668     Mac::RxFrame receivedFrame;
669     Mac::TxFrame ackFrame;
670     uint8_t      ackFrameBuffer[100];
671 
672     ackFrame.mPsdu   = ackFrameBuffer;
673     ackFrame.mLength = sizeof(ackFrameBuffer);
674 
675     // Received Frame 1
676     // IEEE 802.15.4 Data
677     //   Frame Control Field: 0xdc61
678     //     .... .... .... .001 = Frame Type: Data (0x1)
679     //     .... .... .... 0... = Security Enabled: False
680     //     .... .... ...0 .... = Frame Pending: False
681     //     .... .... ..1. .... = Acknowledge Request: True
682     //     .... .... .1.. .... = PAN ID Compression: True
683     //     .... ...0 .... .... = Sequence Number Suppression: False
684     //     .... ..0. .... .... = Information Elements Present: False
685     //     .... 11.. .... .... = Destination Addressing Mode: Long/64-bit (0x3)
686     //     ..01 .... .... .... = Frame Version: IEEE Std 802.15.4-2006 (1)
687     //     11.. .... .... .... = Source Addressing Mode: Long/64-bit (0x3)
688     //  Sequence Number: 189
689     //  Destination PAN: 0xface
690     //  Destination: 16:6e:0a:00:00:00:00:01 (16:6e:0a:00:00:00:00:01)
691     //  Extended Source: 16:6e:0a:00:00:00:00:02 (16:6e:0a:00:00:00:00:02)
692     uint8_t data_psdu1[]  = {0x61, 0xdc, 0xbd, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x02,
693                              0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x7f, 0x33, 0xf0, 0x4d, 0x4c, 0x4d, 0x4c,
694                              0x8b, 0xf0, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2,
695                              0x57, 0x9c, 0x31, 0xb3, 0x2a, 0xa1, 0x86, 0xba, 0x9a, 0xed, 0x5a, 0xb9, 0xa3, 0x59,
696                              0x88, 0xeb, 0xbb, 0x0d, 0xc3, 0xed, 0xeb, 0x8a, 0x53, 0xa6, 0xed, 0xf7, 0xdd, 0x45,
697                              0x6e, 0xf7, 0x9a, 0x17, 0xb4, 0xab, 0xc6, 0x75, 0x71, 0x46, 0x37, 0x93, 0x4a, 0x32,
698                              0xb1, 0x21, 0x9f, 0x9d, 0xb3, 0x65, 0x27, 0xd5, 0xfc, 0x50, 0x16, 0x90, 0xd2, 0xd4};
699     receivedFrame.mPsdu   = data_psdu1;
700     receivedFrame.mLength = sizeof(data_psdu1);
701 
702     ackFrame.GenerateImmAck(receivedFrame, false);
703     VerifyOrQuit(ackFrame.mLength == kImmAckLength);
704     VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
705     VerifyOrQuit(!ackFrame.GetSecurityEnabled());
706     VerifyOrQuit(!ackFrame.GetFramePending());
707 
708     VerifyOrQuit(!ackFrame.GetAckRequest());
709     VerifyOrQuit(!ackFrame.IsIePresent());
710     VerifyOrQuit(!ackFrame.IsDstPanIdPresent());
711     VerifyOrQuit(!ackFrame.IsDstAddrPresent());
712     VerifyOrQuit(!ackFrame.IsSrcAddrPresent());
713     VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2006);
714     VerifyOrQuit(ackFrame.IsSequencePresent());
715     VerifyOrQuit(ackFrame.GetSequence() == 189);
716 
717 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
718     // Received Frame 2
719     // IEEE 802.15.4 Data
720     //   Frame Control Field: 0xa869, Frame Type: Data, Security Enabled, Acknowledge Request, PAN ID Compression,
721     //   Destination Addressing Mode: Short/16-bit, Frame Version: IEEE Std 802.15.4-2015, Source Addressing Mode:
722     //   Short/16-bit
723     //     .... .... .... .001 = Frame Type: Data (0x1)
724     //     .... .... .... 1... = Security Enabled: True
725     //     .... .... ...0 .... = Frame Pending: False
726     //     .... .... ..1. .... = Acknowledge Request: True
727     //     .... .... .1.. .... = PAN ID Compression: True
728     //     .... ...0 .... .... = Sequence Number Suppression: False
729     //     .... ..0. .... .... = Information Elements Present: False
730     //     .... 10.. .... .... = Destination Addressing Mode: Short/16-bit (0x2)
731     //     ..10 .... .... .... = Frame Version: IEEE Std 802.15.4-2015 (2)
732     //     10.. .... .... .... = Source Addressing Mode: Short/16-bit (0x2)
733     //   Sequence Number: 142
734     //   Destination PAN: 0xface
735     //   Destination: 0x2402
736     //   Source: 0x2400
737     //   [Extended Source: 16:6e:0a:00:00:00:00:01 (16:6e:0a:00:00:00:00:01)]
738     //   [Origin: 2]
739     //   Auxiliary Security Header
740     //     Security Control Field: 0x0d, Security Level: Encryption with 32-bit Message Integrity Code, Key Identifier
741     //     Mode: Indexed Key using the Default Key Source
742     //       .... .101 = Security Level: Encryption with 32-bit Message Integrity Code (0x5)
743     //       ...0 1... = Key Identifier Mode: Indexed Key using the Default Key Source (0x1)
744     //       ..0. .... = Frame Counter Suppression: False
745     //       .0.. .... = ASN in Nonce: False
746     //       0... .... = Reserved: 0x0
747     //     Frame Counter: 2
748     //     Key Identifier Field
749     //       Key Index: 0x01
750     //   MIC: f94e5870
751     //   [Key Number: 0]
752     //   FCS: 0x8c40 (Correct)
753     uint8_t data_psdu2[]  = {0x69, 0xa8, 0x8e, 0xce, 0xfa, 0x02, 0x24, 0x00, 0x24, 0x0d, 0x02,
754                              0x00, 0x00, 0x00, 0x01, 0x6b, 0x64, 0x60, 0x08, 0x55, 0xb8, 0x10,
755                              0x18, 0xc7, 0x40, 0x2e, 0xfb, 0xf3, 0xda, 0xf9, 0x4e, 0x58, 0x70};
756     receivedFrame.mPsdu   = data_psdu2;
757     receivedFrame.mLength = sizeof(data_psdu2);
758 
759     uint8_t     ie_data[6] = {0x04, 0x0d, 0x21, 0x0c, 0x35, 0x0c};
760     Mac::CslIe *csl;
761 
762     SuccessOrQuit(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)));
763 
764     csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
765     VerifyOrQuit(ackFrame.mLength == 25);
766     VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
767     VerifyOrQuit(ackFrame.GetSecurityEnabled());
768     VerifyOrQuit(ackFrame.IsIePresent());
769     VerifyOrQuit(ackFrame.IsDstPanIdPresent());
770     VerifyOrQuit(ackFrame.IsDstAddrPresent());
771     VerifyOrQuit(!ackFrame.IsSrcAddrPresent());
772     VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2015);
773     VerifyOrQuit(ackFrame.IsSequencePresent());
774     VerifyOrQuit(ackFrame.GetSequence() == 142);
775     VerifyOrQuit(csl->GetPeriod() == 3125 && csl->GetPhase() == 3105);
776 
777 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
778     ackFrame.SetCslIe(123, 456);
779     csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
780     VerifyOrQuit(csl->GetPeriod() == 123 && csl->GetPhase() == 456);
781 #endif
782 #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
783 }
784 
785 #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
786 constexpr uint16_t kMpFcfLongFrame           = 1 << 3;
787 constexpr uint16_t kMpFcfDstAddrShift        = 4;
788 constexpr uint16_t kMpFcfDstAddrExt          = 3 << kMpFcfDstAddrShift;
789 constexpr uint16_t kMpFcfSrcAddrShift        = 6;
790 constexpr uint16_t kMpFcfSrcAddrShort        = 2 << kMpFcfSrcAddrShift;
791 constexpr uint16_t kMpFcfSrcAddrExt          = 3 << kMpFcfSrcAddrShift;
792 constexpr uint16_t kMpFcfPanidPresent        = 1 << 8;
793 constexpr uint16_t kMpFcfSecurityEnabled     = 1 << 9;
794 constexpr uint16_t kMpFcfSequenceSuppression = 1 << 10;
795 constexpr uint16_t kMpFcfAckRequest          = 1 << 14;
796 constexpr uint16_t kMpFcfIePresent           = 1 << 15;
797 
TestMacWakeupFrameGeneration(void)798 void TestMacWakeupFrameGeneration(void)
799 {
800     constexpr static uint8_t kSrcExtaddr[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
801     constexpr static uint8_t kDstExtaddr[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87};
802     constexpr static uint8_t kKeySource[]  = {0, 0, 0, 0x1c};
803 
804     constexpr static uint8_t kWakeupPsdu[] = {
805         // Frame Control
806         Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
807         (kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
808         // PAN ID
809         0xce, 0xfa,
810         // Destination Address
811         0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0,
812         // Source Address
813         0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
814         // Security Header
815         Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xfc, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x1c, 0x1d,
816         // Rendezvous Time IE
817         0x82, 0x0e, 0xcd, 0xab,
818         // Connection IE
819         0x05, 0x00, 0x9b, 0xb8, 0xea, 0x01, 0x1c};
820 
821     uint8_t            psdu[OT_RADIO_FRAME_MAX_SIZE];
822     Mac::Address       src;
823     Mac::Address       dst;
824     Mac::Address       addr;
825     Mac::TxFrame       txFrame;
826     Mac::Frame         rxFrame;
827     Mac::ConnectionIe *connectionIe;
828 
829     printf("TestMacWakeupFrameGeneration\n");
830 
831     src.SetExtended(kSrcExtaddr);
832     dst.SetExtended(kDstExtaddr);
833     txFrame.mPsdu      = psdu;
834     txFrame.mLength    = 0;
835     txFrame.mRadioType = 0;
836 
837     SuccessOrQuit(txFrame.GenerateWakeupFrame(0xface, dst, src));
838 
839     // Validate that the frame satisfies the wake-up frame definition
840     VerifyOrQuit(txFrame.GetType() == Mac::Frame::kTypeMultipurpose);
841     VerifyOrQuit(!txFrame.GetAckRequest());
842     VerifyOrQuit(txFrame.GetRendezvousTimeIe() != nullptr);
843     VerifyOrQuit(txFrame.GetConnectionIe() != nullptr);
844     VerifyOrQuit(txFrame.GetPayloadLength() == 0);
845     SuccessOrQuit(txFrame.GetSrcAddr(addr));
846     VerifyOrQuit(CompareAddresses(src, addr));
847     SuccessOrQuit(txFrame.GetDstAddr(addr));
848     VerifyOrQuit(CompareAddresses(dst, addr));
849 
850     // Initialize remaining fields and check if the frame has the expected contents
851     txFrame.SetFrameCounter(0xfcfcfcfc);
852     txFrame.SetKeySource(kKeySource);
853     txFrame.SetKeyId(0x1d);
854     txFrame.GetRendezvousTimeIe()->SetRendezvousTime(0xabcd);
855     connectionIe = txFrame.GetConnectionIe();
856     connectionIe->SetRetryInterval(1);
857     connectionIe->SetRetryCount(12);
858 
859     VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xabcd);
860     VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
861     VerifyOrQuit(connectionIe->GetRetryCount() == 12);
862     VerifyOrQuit(txFrame.GetLength() == sizeof(kWakeupPsdu) + txFrame.GetFooterLength());
863     VerifyOrQuit(memcmp(psdu, kWakeupPsdu, sizeof(kWakeupPsdu)) == 0);
864 
865     // Initialize RX Frame with the same PSDU and check if it's recognized as wake-up frame
866     rxFrame.mPsdu      = psdu;
867     rxFrame.mLength    = txFrame.GetLength();
868     rxFrame.mRadioType = 0;
869 
870     SuccessOrQuit(rxFrame.ValidatePsdu());
871     VerifyOrQuit(rxFrame.IsWakeupFrame());
872 }
873 
TestMacWakeupFrameDetectionNegative(void)874 void TestMacWakeupFrameDetectionNegative(void)
875 {
876     struct TestCase
877     {
878         uint8_t *mPsdu;
879         uint8_t  mLength;
880     };
881 
882     uint8_t ackRequestedPsdu[] = {
883         // Frame Control
884         Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
885         (kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfAckRequest | kMpFcfIePresent) >>
886             8,
887         // PAN ID
888         0xCE, 0xFA,
889         // Destination Address
890         0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
891         // Source Address
892         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
893         // Security Header
894         Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
895         // Rendezvous Time IE
896         0x82, 0x0E, 0xCD, 0xAB,
897         // Connection IE
898         0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
899         // Footer
900         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
901 
902     uint8_t shortAddressPsdu[] = {
903         // Frame Control
904         Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrShort,
905         (kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
906         // PAN ID
907         0xCE, 0xFA,
908         // Destination Address
909         0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
910         // Source Address
911         0x55, 0x55,
912         // Security Header
913         Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
914         // Rendezvous Time IE
915         0x82, 0x0E, 0xCD, 0xAB,
916         // Connection IE
917         0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
918         // Footer
919         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
920 
921     uint8_t noRendezvousIePsdu[] = {
922         // Frame Control
923         Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
924         (kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
925         // PAN ID
926         0xCE, 0xFA,
927         // Destination Address
928         0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
929         // Source Address
930         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
931         // Security Header
932         Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
933         // Connection IE
934         0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
935         // Footer
936         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
937 
938     uint8_t noConnectionIePsdu[] = {
939         // Frame Control
940         Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
941         (kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
942         // PAN ID
943         0xCE, 0xFA,
944         // Destination Address
945         0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
946         // Source Address
947         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
948         // Security Header
949         Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
950         // Rendezvous Time IE
951         0x82, 0x0E, 0xCD, 0xAB,
952         // Connection IE
953         0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x02, 0x1C,
954         // Footer
955         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
956 
957     uint8_t keyIdMode1Psdu[] = {
958         // Frame Control
959         Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
960         (kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
961         // PAN ID
962         0xCE, 0xFA,
963         // Destination Address
964         0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
965         // Source Address
966         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
967         // Security Header
968         Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x1D,
969         // Rendezvous Time IE
970         0x82, 0x0E, 0xCD, 0xAB,
971         // Connection IE
972         0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
973         // Footer
974         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
975 
976     const TestCase testCases[] = {
977         {ackRequestedPsdu, sizeof(ackRequestedPsdu)},     {shortAddressPsdu, sizeof(shortAddressPsdu)},
978         {noRendezvousIePsdu, sizeof(noRendezvousIePsdu)}, {noConnectionIePsdu, sizeof(noConnectionIePsdu)},
979         {keyIdMode1Psdu, sizeof(keyIdMode1Psdu)},
980     };
981 
982     Mac::Frame rxFrame;
983 
984     printf("TestMacWakeupFrameDetectionNegative\n");
985 
986     for (const TestCase &testCase : testCases)
987     {
988         rxFrame.mPsdu      = testCase.mPsdu;
989         rxFrame.mLength    = testCase.mLength;
990         rxFrame.mRadioType = 0;
991 
992         SuccessOrQuit(rxFrame.ValidatePsdu());
993         VerifyOrQuit(!rxFrame.IsWakeupFrame());
994     }
995 }
996 #endif
997 } // namespace ot
998 
main(void)999 int main(void)
1000 {
1001     ot::TestMacAddress();
1002     ot::TestMacHeader();
1003     ot::TestMacChannelMask();
1004     ot::TestMacFrameApi();
1005     ot::TestMacFrameAckGeneration();
1006 #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
1007     ot::TestMacWakeupFrameGeneration();
1008     ot::TestMacWakeupFrameDetectionNegative();
1009 #endif
1010     printf("All tests passed\n");
1011     return 0;
1012 }
1013