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::Addresses addresses;
295         Mac::Address   address;
296         Mac::PanIds    panIds;
297         Mac::PanId     panId;
298 
299         frame.mPsdu      = psdu;
300         frame.mLength    = 0;
301         frame.mRadioType = 0;
302 
303         VerifyOrQuit(addresses.mSource.IsNone());
304         VerifyOrQuit(addresses.mDestination.IsNone());
305         VerifyOrQuit(!panIds.IsSourcePresent());
306         VerifyOrQuit(!panIds.IsDestinationPresent());
307 
308         switch (testCase.mSrcAddrType)
309         {
310         case kNoneAddr:
311             addresses.mSource.SetNone();
312             break;
313         case kShrtAddr:
314             addresses.mSource.SetShort(kShortAddr1);
315             break;
316         case kExtdAddr:
317             addresses.mSource.SetExtended(extAddr1);
318             break;
319         }
320 
321         switch (testCase.mDstAddrType)
322         {
323         case kNoneAddr:
324             addresses.mDestination.SetNone();
325             break;
326         case kShrtAddr:
327             addresses.mDestination.SetShort(kShortAddr2);
328             break;
329         case kExtdAddr:
330             addresses.mDestination.SetExtended(extAddr2);
331             break;
332         }
333 
334         switch (testCase.mSrcPanIdMode)
335         {
336         case kNoPanId:
337             break;
338         case kUsePanId1:
339             panIds.SetSource(kPanId1);
340             break;
341         case kUsePanId2:
342             panIds.SetSource(kPanId2);
343             break;
344         }
345 
346         switch (testCase.mDstPanIdMode)
347         {
348         case kNoPanId:
349             break;
350         case kUsePanId1:
351             panIds.SetDestination(kPanId1);
352             break;
353         case kUsePanId2:
354             panIds.SetDestination(kPanId2);
355             break;
356         }
357 
358         frame.InitMacHeader(Mac::Frame::kTypeData, testCase.mVersion, addresses, panIds, testCase.mSecurity,
359                             testCase.mKeyIdMode, testCase.mSuppressSequence);
360 
361         VerifyOrQuit(frame.GetHeaderLength() == testCase.mHeaderLength);
362         VerifyOrQuit(frame.GetFooterLength() == testCase.mFooterLength);
363         VerifyOrQuit(frame.GetLength() == testCase.mHeaderLength + testCase.mFooterLength);
364 
365         VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeData);
366         VerifyOrQuit(!frame.IsAck());
367         VerifyOrQuit(frame.GetVersion() == testCase.mVersion);
368         VerifyOrQuit(frame.GetSecurityEnabled() == (testCase.mSecurity != kNoSec));
369         VerifyOrQuit(!frame.GetFramePending());
370         VerifyOrQuit(!frame.IsIePresent());
371         VerifyOrQuit(frame.GetAckRequest() == (testCase.mDstAddrType != kNoneAddr));
372 
373         VerifyOrQuit(frame.IsSrcAddrPresent() == (testCase.mSrcAddrType != kNoneAddr));
374         SuccessOrQuit(frame.GetSrcAddr(address));
375         VerifyOrQuit(CompareAddresses(address, addresses.mSource));
376         VerifyOrQuit(frame.IsDstAddrPresent() == (testCase.mDstAddrType != kNoneAddr));
377         SuccessOrQuit(frame.GetDstAddr(address));
378         VerifyOrQuit(CompareAddresses(address, addresses.mDestination));
379 
380         VerifyOrQuit(frame.IsDstPanIdPresent() == (testCase.mDstPanIdMode != kNoPanId));
381 
382         if (frame.IsDstPanIdPresent())
383         {
384             SuccessOrQuit(frame.GetDstPanId(panId));
385             VerifyOrQuit(panId == panIds.GetDestination());
386             VerifyOrQuit(panIds.IsDestinationPresent());
387         }
388 
389         if (frame.IsSrcPanIdPresent())
390         {
391             SuccessOrQuit(frame.GetSrcPanId(panId));
392             VerifyOrQuit(panId == panIds.GetSource());
393             VerifyOrQuit(panIds.IsSourcePresent());
394         }
395 
396         if (frame.GetSecurityEnabled())
397         {
398             uint8_t security;
399             uint8_t keyIdMode;
400 
401             SuccessOrQuit(frame.GetSecurityLevel(security));
402             VerifyOrQuit(security == testCase.mSecurity);
403 
404             SuccessOrQuit(frame.GetKeyIdMode(keyIdMode));
405             VerifyOrQuit(keyIdMode == testCase.mKeyIdMode);
406         }
407 
408         offset = snprintf(string, sizeof(string), "\nver:%s, src[addr:%s, pan:%s], dst[addr:%s, pan:%s], sec:%s",
409                           (testCase.mVersion == kVer2006) ? "2006" : "2015", kAddrTypeStrings[testCase.mSrcAddrType],
410                           kPanIdModeStrings[testCase.mSrcPanIdMode], kAddrTypeStrings[testCase.mDstAddrType],
411                           kPanIdModeStrings[testCase.mDstPanIdMode], testCase.mSecurity == kNoSec ? "no" : "mic32");
412 
413         if (!testCase.mSuppressSequence)
414         {
415             VerifyOrQuit(frame.IsSequencePresent());
416             offset += snprintf(string + offset, sizeof(string) - offset, ", seq:%u", frame.GetSequence());
417         }
418         else
419         {
420             VerifyOrQuit(!frame.IsSequencePresent());
421         }
422         DumpBuffer(string, frame.GetPsdu(), frame.GetLength());
423     }
424 }
425 
VerifyChannelMaskContent(const Mac::ChannelMask & aMask,uint8_t * aChannels,uint8_t aLength)426 void VerifyChannelMaskContent(const Mac::ChannelMask &aMask, uint8_t *aChannels, uint8_t aLength)
427 {
428     uint8_t index = 0;
429     uint8_t channel;
430 
431     for (channel = Radio::kChannelMin; channel <= Radio::kChannelMax; channel++)
432     {
433         if (index < aLength)
434         {
435             if (channel == aChannels[index])
436             {
437                 index++;
438                 VerifyOrQuit(aMask.ContainsChannel(channel));
439             }
440             else
441             {
442                 VerifyOrQuit(!aMask.ContainsChannel(channel));
443             }
444         }
445     }
446 
447     index   = 0;
448     channel = Mac::ChannelMask::kChannelIteratorFirst;
449 
450     while (aMask.GetNextChannel(channel) == kErrorNone)
451     {
452         VerifyOrQuit(channel == aChannels[index++], "ChannelMask.GetNextChannel() failed");
453     }
454 
455     VerifyOrQuit(index == aLength, "ChannelMask.GetNextChannel() failed");
456 
457     if (aLength == 1)
458     {
459         VerifyOrQuit(aMask.IsSingleChannel());
460     }
461     else
462     {
463         VerifyOrQuit(!aMask.IsSingleChannel());
464     }
465 
466     VerifyOrQuit(aLength == aMask.GetNumberOfChannels());
467 }
468 
TestMacChannelMask(void)469 void TestMacChannelMask(void)
470 {
471     uint8_t allChannels[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};
472     uint8_t channels1[]   = {11, 14, 15, 16, 17, 20, 21, 22, 24, 25};
473     uint8_t channels2[]   = {14, 21, 26};
474     uint8_t channels3[]   = {14, 21};
475     uint8_t channles4[]   = {20};
476 
477     static const char kEmptyMaskString[]   = "{ }";
478     static const char kAllChannelsString[] = "{ 11-26 }";
479     static const char kChannels1String[]   = "{ 11, 14-17, 20-22, 24, 25 }";
480     static const char kChannels2String[]   = "{ 14, 21, 26 }";
481     static const char kChannels3String[]   = "{ 14, 21 }";
482     static const char kChannels4String[]   = "{ 20 }";
483 
484     Mac::ChannelMask mask1;
485     Mac::ChannelMask mask2(Radio::kSupportedChannels);
486 
487     printf("Testing Mac::ChannelMask\n");
488 
489     VerifyOrQuit(mask1.IsEmpty());
490     printf("empty = %s\n", mask1.ToString().AsCString());
491     VerifyOrQuit(strcmp(mask1.ToString().AsCString(), kEmptyMaskString) == 0);
492 
493     VerifyOrQuit(!mask2.IsEmpty());
494     VerifyOrQuit(mask2.GetMask() == Radio::kSupportedChannels);
495     printf("allChannels = %s\n", mask2.ToString().AsCString());
496     VerifyOrQuit(strcmp(mask2.ToString().AsCString(), kAllChannelsString) == 0);
497 
498     mask1.SetMask(Radio::kSupportedChannels);
499     VerifyOrQuit(!mask1.IsEmpty());
500     VerifyOrQuit(mask1.GetMask() == Radio::kSupportedChannels);
501 
502     VerifyChannelMaskContent(mask1, allChannels, sizeof(allChannels));
503 
504     // Test ChannelMask::RemoveChannel()
505     for (size_t index = 0; index < sizeof(allChannels) - 1; index++)
506     {
507         mask1.RemoveChannel(allChannels[index]);
508         VerifyChannelMaskContent(mask1, &allChannels[index + 1], sizeof(allChannels) - 1 - index);
509     }
510 
511     mask1.Clear();
512     VerifyOrQuit(mask1.IsEmpty());
513     VerifyChannelMaskContent(mask1, nullptr, 0);
514 
515     for (uint8_t channel : channels1)
516     {
517         mask1.AddChannel(channel);
518     }
519 
520     printf("channels1 = %s\n", mask1.ToString().AsCString());
521     VerifyOrQuit(strcmp(mask1.ToString().AsCString(), kChannels1String) == 0);
522 
523     VerifyOrQuit(!mask1.IsEmpty());
524     VerifyChannelMaskContent(mask1, channels1, sizeof(channels1));
525 
526     mask2.Clear();
527 
528     for (uint8_t channel : channels2)
529     {
530         mask2.AddChannel(channel);
531     }
532 
533     printf("channels2 = %s\n", mask2.ToString().AsCString());
534     VerifyOrQuit(strcmp(mask2.ToString().AsCString(), kChannels2String) == 0);
535 
536     VerifyOrQuit(!mask2.IsEmpty());
537     VerifyChannelMaskContent(mask2, channels2, sizeof(channels2));
538 
539     mask1.Intersect(mask2);
540     VerifyChannelMaskContent(mask1, channels3, sizeof(channels3));
541     printf("channels3 = %s\n", mask1.ToString().AsCString());
542     VerifyOrQuit(strcmp(mask1.ToString().AsCString(), kChannels3String) == 0);
543 
544     mask2.Clear();
545     mask2.AddChannel(channles4[0]);
546     VerifyChannelMaskContent(mask2, channles4, sizeof(channles4));
547 
548     printf("channels4 = %s\n", mask2.ToString().AsCString());
549     VerifyOrQuit(strcmp(mask2.ToString().AsCString(), kChannels4String) == 0);
550 
551     mask1.Clear();
552     mask2.Clear();
553     VerifyOrQuit(mask1 == mask2);
554 
555     mask1.SetMask(Radio::kSupportedChannels);
556     mask2.SetMask(Radio::kSupportedChannels);
557     VerifyOrQuit(mask1 == mask2);
558 
559     mask1.Clear();
560     VerifyOrQuit(mask1 != mask2);
561 }
562 
TestMacFrameApi(void)563 void TestMacFrameApi(void)
564 {
565     uint8_t ack_psdu1[]     = {0x02, 0x10, 0x5e, 0xd2, 0x9b};
566     uint8_t mac_cmd_psdu1[] = {0x6b, 0xdc, 0x85, 0xce, 0xfa, 0x47, 0x36, 0x07, 0xd9, 0x74, 0x45, 0x8d,
567                                0xb2, 0x6e, 0x81, 0x25, 0xc9, 0xdb, 0xac, 0x2b, 0x0a, 0x0d, 0x00, 0x00,
568                                0x00, 0x00, 0x01, 0x04, 0xaf, 0x14, 0xce, 0xaa, 0x5a, 0xe5};
569 
570     Mac::Frame frame;
571 
572 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
573     uint8_t data_psdu1[]    = {0x29, 0xee, 0x53, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x05,
574                                0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x01};
575     uint8_t mac_cmd_psdu2[] = {0x6b, 0xaa, 0x8d, 0xce, 0xfa, 0x00, 0x68, 0x01, 0x68, 0x0d,
576                                0x08, 0x00, 0x00, 0x00, 0x01, 0x04, 0x0d, 0xed, 0x0b, 0x35,
577                                0x0c, 0x80, 0x3f, 0x04, 0x4b, 0x88, 0x89, 0xd6, 0x59, 0xe1};
578     uint8_t scf; // SecurityControlField
579 #endif
580 
581     // Imm-Ack, Sequence Number: 94
582     //   Frame Control Field: 0x1002
583     //     .... .... .... .010 = Frame Type: Ack (0x2)
584     //     .... .... .... 0... = Security Enabled: False
585     //     .... .... ...0 .... = Frame Pending: False
586     //     .... .... ..0. .... = Acknowledge Request: False
587     //     .... .... .0.. .... = PAN ID Compression: False
588     //     .... ...0 .... .... = Sequence Number Suppression: False
589     //     .... ..0. .... .... = Information Elements Present: False
590     //     .... 00.. .... .... = Destination Addressing Mode: None (0x0)
591     //     ..01 .... .... .... = Frame Version: IEEE Std 802.15.4-2006 (1)
592     //     00.. .... .... .... = Source Addressing Mode: None (0x0)
593     //   Sequence Number: 94
594     //   FCS: 0x9bd2 (Correct)
595     frame.mPsdu   = ack_psdu1;
596     frame.mLength = sizeof(ack_psdu1);
597     VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeAck);
598     VerifyOrQuit(!frame.GetSecurityEnabled());
599     VerifyOrQuit(!frame.GetFramePending());
600     VerifyOrQuit(!frame.GetAckRequest());
601     VerifyOrQuit(!frame.IsIePresent());
602     VerifyOrQuit(!frame.IsDstPanIdPresent());
603     VerifyOrQuit(!frame.IsDstAddrPresent());
604     VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
605     VerifyOrQuit(!frame.IsSrcAddrPresent());
606     VerifyOrQuit(frame.IsSequencePresent());
607     VerifyOrQuit(frame.GetSequence() == 94);
608 
609 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
610     // IEEE 802.15.4-2015 Data
611     //   Sequence Number: 83
612     //   Destination PAN: 0xface
613     //   Destination: 16:6e:0a:00:00:00:00:01
614     //   Extended Source: 16:6e:0a:00:00:00:00:05
615     //   Auxiliary Security Header
616     //     Security Control Field: 0x0d
617     frame.mPsdu   = data_psdu1;
618     frame.mLength = sizeof(data_psdu1);
619     VerifyOrQuit(frame.IsVersion2015());
620     VerifyOrQuit(frame.IsDstPanIdPresent());
621     VerifyOrQuit(frame.IsDstAddrPresent());
622     VerifyOrQuit(frame.IsSrcAddrPresent());
623     SuccessOrQuit(frame.GetSecurityControlField(scf));
624     VerifyOrQuit(scf == 0x0d);
625     frame.SetSecurityControlField(0xff);
626     SuccessOrQuit(frame.GetSecurityControlField(scf));
627     VerifyOrQuit(scf == 0xff);
628 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
629 
630     // IEEE 802.15.4-2006 Mac Command
631     //   Sequence Number: 133
632     //   Command Identifier: Data Request (0x04)
633     uint8_t commandId;
634     frame.mPsdu   = mac_cmd_psdu1;
635     frame.mLength = sizeof(mac_cmd_psdu1);
636     VerifyOrQuit(frame.IsSequencePresent());
637     VerifyOrQuit(frame.GetSequence() == 133);
638     VerifyOrQuit(frame.GetVersion() == Mac::Frame::kVersion2006);
639     VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeMacCmd);
640     SuccessOrQuit(frame.GetCommandId(commandId));
641     VerifyOrQuit(commandId == Mac::Frame::kMacCmdDataRequest);
642     SuccessOrQuit(frame.SetCommandId(Mac::Frame::kMacCmdBeaconRequest));
643     SuccessOrQuit(frame.GetCommandId(commandId));
644     VerifyOrQuit(commandId == Mac::Frame::kMacCmdBeaconRequest);
645 
646 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
647     // IEEE 802.15.4-2015 Mac Command
648     //   Sequence Number: 141
649     //   Header IEs
650     //     CSL IE
651     //     Header Termination 2 IE (Payload follows)
652     //   Command Identifier: Data Request (0x04)
653     frame.mPsdu   = mac_cmd_psdu2;
654     frame.mLength = sizeof(mac_cmd_psdu2);
655     VerifyOrQuit(frame.IsSequencePresent());
656     VerifyOrQuit(frame.GetSequence() == 141);
657     VerifyOrQuit(frame.IsVersion2015());
658     VerifyOrQuit(frame.GetType() == Mac::Frame::kTypeMacCmd);
659     SuccessOrQuit(frame.GetCommandId(commandId));
660     VerifyOrQuit(commandId == Mac::Frame::kMacCmdDataRequest);
661     printf("commandId:%d\n", commandId);
662     SuccessOrQuit(frame.SetCommandId(Mac::Frame::kMacCmdOrphanNotification));
663     SuccessOrQuit(frame.GetCommandId(commandId));
664     VerifyOrQuit(commandId == Mac::Frame::kMacCmdOrphanNotification);
665 
666 #endif
667 }
668 
TestMacFrameAckGeneration(void)669 void TestMacFrameAckGeneration(void)
670 {
671     constexpr uint8_t kImmAckLength = 5;
672 
673     Mac::RxFrame receivedFrame;
674     Mac::TxFrame ackFrame;
675     uint8_t      ackFrameBuffer[100];
676 
677     ackFrame.mPsdu   = ackFrameBuffer;
678     ackFrame.mLength = sizeof(ackFrameBuffer);
679 
680     // Received Frame 1
681     // IEEE 802.15.4 Data
682     //   Frame Control Field: 0xdc61
683     //     .... .... .... .001 = Frame Type: Data (0x1)
684     //     .... .... .... 0... = Security Enabled: False
685     //     .... .... ...0 .... = Frame Pending: False
686     //     .... .... ..1. .... = Acknowledge Request: True
687     //     .... .... .1.. .... = PAN ID Compression: True
688     //     .... ...0 .... .... = Sequence Number Suppression: False
689     //     .... ..0. .... .... = Information Elements Present: False
690     //     .... 11.. .... .... = Destination Addressing Mode: Long/64-bit (0x3)
691     //     ..01 .... .... .... = Frame Version: IEEE Std 802.15.4-2006 (1)
692     //     11.. .... .... .... = Source Addressing Mode: Long/64-bit (0x3)
693     //  Sequence Number: 189
694     //  Destination PAN: 0xface
695     //  Destination: 16:6e:0a:00:00:00:00:01 (16:6e:0a:00:00:00:00:01)
696     //  Extended Source: 16:6e:0a:00:00:00:00:02 (16:6e:0a:00:00:00:00:02)
697     uint8_t data_psdu1[]  = {0x61, 0xdc, 0xbd, 0xce, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x02,
698                              0x00, 0x00, 0x00, 0x00, 0x0a, 0x6e, 0x16, 0x7f, 0x33, 0xf0, 0x4d, 0x4c, 0x4d, 0x4c,
699                              0x8b, 0xf0, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2,
700                              0x57, 0x9c, 0x31, 0xb3, 0x2a, 0xa1, 0x86, 0xba, 0x9a, 0xed, 0x5a, 0xb9, 0xa3, 0x59,
701                              0x88, 0xeb, 0xbb, 0x0d, 0xc3, 0xed, 0xeb, 0x8a, 0x53, 0xa6, 0xed, 0xf7, 0xdd, 0x45,
702                              0x6e, 0xf7, 0x9a, 0x17, 0xb4, 0xab, 0xc6, 0x75, 0x71, 0x46, 0x37, 0x93, 0x4a, 0x32,
703                              0xb1, 0x21, 0x9f, 0x9d, 0xb3, 0x65, 0x27, 0xd5, 0xfc, 0x50, 0x16, 0x90, 0xd2, 0xd4};
704     receivedFrame.mPsdu   = data_psdu1;
705     receivedFrame.mLength = sizeof(data_psdu1);
706 
707     ackFrame.GenerateImmAck(receivedFrame, false);
708     VerifyOrQuit(ackFrame.mLength == kImmAckLength);
709     VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
710     VerifyOrQuit(!ackFrame.GetSecurityEnabled());
711     VerifyOrQuit(!ackFrame.GetFramePending());
712 
713     VerifyOrQuit(!ackFrame.GetAckRequest());
714     VerifyOrQuit(!ackFrame.IsIePresent());
715     VerifyOrQuit(!ackFrame.IsDstPanIdPresent());
716     VerifyOrQuit(!ackFrame.IsDstAddrPresent());
717     VerifyOrQuit(!ackFrame.IsSrcAddrPresent());
718     VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2006);
719     VerifyOrQuit(ackFrame.IsSequencePresent());
720     VerifyOrQuit(ackFrame.GetSequence() == 189);
721 
722 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
723     // Received Frame 2
724     // IEEE 802.15.4 Data
725     //   Frame Control Field: 0xa869, Frame Type: Data, Security Enabled, Acknowledge Request, PAN ID Compression,
726     //   Destination Addressing Mode: Short/16-bit, Frame Version: IEEE Std 802.15.4-2015, Source Addressing Mode:
727     //   Short/16-bit
728     //     .... .... .... .001 = Frame Type: Data (0x1)
729     //     .... .... .... 1... = Security Enabled: True
730     //     .... .... ...0 .... = Frame Pending: False
731     //     .... .... ..1. .... = Acknowledge Request: True
732     //     .... .... .1.. .... = PAN ID Compression: True
733     //     .... ...0 .... .... = Sequence Number Suppression: False
734     //     .... ..0. .... .... = Information Elements Present: False
735     //     .... 10.. .... .... = Destination Addressing Mode: Short/16-bit (0x2)
736     //     ..10 .... .... .... = Frame Version: IEEE Std 802.15.4-2015 (2)
737     //     10.. .... .... .... = Source Addressing Mode: Short/16-bit (0x2)
738     //   Sequence Number: 142
739     //   Destination PAN: 0xface
740     //   Destination: 0x2402
741     //   Source: 0x2400
742     //   [Extended Source: 16:6e:0a:00:00:00:00:01 (16:6e:0a:00:00:00:00:01)]
743     //   [Origin: 2]
744     //   Auxiliary Security Header
745     //     Security Control Field: 0x0d, Security Level: Encryption with 32-bit Message Integrity Code, Key Identifier
746     //     Mode: Indexed Key using the Default Key Source
747     //       .... .101 = Security Level: Encryption with 32-bit Message Integrity Code (0x5)
748     //       ...0 1... = Key Identifier Mode: Indexed Key using the Default Key Source (0x1)
749     //       ..0. .... = Frame Counter Suppression: False
750     //       .0.. .... = ASN in Nonce: False
751     //       0... .... = Reserved: 0x0
752     //     Frame Counter: 2
753     //     Key Identifier Field
754     //       Key Index: 0x01
755     //   MIC: f94e5870
756     //   [Key Number: 0]
757     //   FCS: 0x8c40 (Correct)
758     uint8_t data_psdu2[]  = {0x69, 0xa8, 0x8e, 0xce, 0xfa, 0x02, 0x24, 0x00, 0x24, 0x0d, 0x02,
759                              0x00, 0x00, 0x00, 0x01, 0x6b, 0x64, 0x60, 0x08, 0x55, 0xb8, 0x10,
760                              0x18, 0xc7, 0x40, 0x2e, 0xfb, 0xf3, 0xda, 0xf9, 0x4e, 0x58, 0x70};
761     receivedFrame.mPsdu   = data_psdu2;
762     receivedFrame.mLength = sizeof(data_psdu2);
763 
764     uint8_t     ie_data[6] = {0x04, 0x0d, 0x21, 0x0c, 0x35, 0x0c};
765     Mac::CslIe *csl;
766 
767     SuccessOrQuit(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)));
768 
769     csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
770     VerifyOrQuit(ackFrame.mLength == 25);
771     VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
772     VerifyOrQuit(ackFrame.GetSecurityEnabled());
773     VerifyOrQuit(ackFrame.IsIePresent());
774     VerifyOrQuit(ackFrame.IsDstPanIdPresent());
775     VerifyOrQuit(ackFrame.IsDstAddrPresent());
776     VerifyOrQuit(!ackFrame.IsSrcAddrPresent());
777     VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2015);
778     VerifyOrQuit(ackFrame.IsSequencePresent());
779     VerifyOrQuit(ackFrame.GetSequence() == 142);
780     VerifyOrQuit(csl->GetPeriod() == 3125 && csl->GetPhase() == 3105);
781 
782 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
783     ackFrame.SetCslIe(123, 456);
784     csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
785     VerifyOrQuit(csl->GetPeriod() == 123 && csl->GetPhase() == 456);
786 #endif
787 #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
788 }
789 
790 } // namespace ot
791 
main(void)792 int main(void)
793 {
794     ot::TestMacAddress();
795     ot::TestMacHeader();
796     ot::TestMacChannelMask();
797     ot::TestMacFrameApi();
798     ot::TestMacFrameAckGeneration();
799     printf("All tests passed\n");
800     return 0;
801 }
802