1 /*
2  *  Copyright (c) 2016-2019, 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 "platform-simulation.h"
30 
31 #include <errno.h>
32 #include <sys/time.h>
33 
34 #include <openthread/cli.h>
35 #include <openthread/dataset.h>
36 #include <openthread/link.h>
37 #include <openthread/random_noncrypto.h>
38 #include <openthread/platform/alarm-micro.h>
39 #include <openthread/platform/alarm-milli.h>
40 #include <openthread/platform/diag.h>
41 #include <openthread/platform/radio.h>
42 #include <openthread/platform/time.h>
43 
44 #include "simul_utils.h"
45 #include "utils/code_utils.h"
46 #include "utils/link_metrics.h"
47 #include "utils/mac_frame.h"
48 #include "utils/soft_source_match_table.h"
49 
50 enum
51 {
52     IEEE802154_ACK_LENGTH = 5,
53 
54     IEEE802154_FRAME_TYPE_ACK = 2 << 0,
55 
56     IEEE802154_FRAME_PENDING = 1 << 4,
57 };
58 
59 enum
60 {
61     SIM_RECEIVE_SENSITIVITY = -100, // dBm
62 
63     SIM_HIGH_RSSI_SAMPLE               = -30, // dBm
64     SIM_LOW_RSSI_SAMPLE                = -98, // dBm
65     SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL = 5,
66 };
67 
68 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
69 extern int      sSockFd;
70 extern uint16_t sPortBase;
71 extern uint16_t sPortOffset;
72 #else
73 static utilsSocket sSocket;
74 static uint16_t    sPortBase   = 9000;
75 static uint16_t    sPortOffset = 0;
76 #endif
77 
78 static int8_t   sEnergyScanResult  = OT_RADIO_RSSI_INVALID;
79 static bool     sEnergyScanning    = false;
80 static uint32_t sEnergyScanEndTime = 0;
81 
82 enum
83 {
84     SIM_RADIO_CHANNEL_MIN = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN,
85     SIM_RADIO_CHANNEL_MAX = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX,
86 };
87 
88 OT_TOOL_PACKED_BEGIN
89 struct RadioMessage
90 {
91     uint8_t mChannel;
92     uint8_t mPsdu[OT_RADIO_FRAME_MAX_SIZE];
93 } OT_TOOL_PACKED_END;
94 
95 static void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame);
96 static void radioSendMessage(otInstance *aInstance);
97 static void radioSendAck(void);
98 static void radioProcessFrame(otInstance *aInstance);
99 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
100 static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen);
101 #endif
102 
103 static otRadioState        sState = OT_RADIO_STATE_DISABLED;
104 static struct RadioMessage sReceiveMessage;
105 static struct RadioMessage sTransmitMessage;
106 static struct RadioMessage sAckMessage;
107 static otRadioFrame        sReceiveFrame;
108 static otRadioFrame        sTransmitFrame;
109 static otRadioFrame        sAckFrame;
110 
111 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
112 static otRadioIeInfo sTransmitIeInfo;
113 #endif
114 
115 static otExtAddress   sExtAddress;
116 static otShortAddress sShortAddress;
117 static otPanId        sPanid;
118 static bool           sPromiscuous = false;
119 static bool           sTxWait      = false;
120 static int8_t         sTxPower     = 0;
121 static int8_t         sCcaEdThresh = -74;
122 static int8_t         sLnaGain     = 0;
123 static uint16_t       sRegionCode  = 0;
124 
125 enum
126 {
127     kMinChannel = 11,
128     kMaxChannel = 26,
129 };
130 static int8_t  sChannelMaxTransmitPower[kMaxChannel - kMinChannel + 1];
131 static uint8_t sCurrentChannel = kMinChannel;
132 
133 static bool sSrcMatchEnabled = false;
134 
135 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
136 static uint8_t sAckIeData[OT_ACK_IE_MAX_SIZE];
137 static uint8_t sAckIeDataLength = 0;
138 #endif
139 
140 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
141 static uint32_t sCslSampleTime;
142 static uint32_t sCslPeriod;
143 #endif
144 
145 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
146 static bool sRadioCoexEnabled = true;
147 #endif
148 
149 otRadioCaps gRadioCaps =
150 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
151     OT_RADIO_CAPS_TRANSMIT_SEC;
152 #else
153     OT_RADIO_CAPS_NONE;
154 #endif
155 
156 static uint32_t         sMacFrameCounter;
157 static uint8_t          sKeyId;
158 static otMacKeyMaterial sPrevKey;
159 static otMacKeyMaterial sCurrKey;
160 static otMacKeyMaterial sNextKey;
161 static otRadioKeyType   sKeyType;
162 
163 static int8_t GetRssi(uint16_t aChannel);
164 
165 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
166 
167 static enum {
168     kFilterOff,
169     kFilterDenyList,
170     kFilterAllowList,
171 } sFilterMode = kFilterOff;
172 
173 static uint8_t sFilterNodeIdsBitVector[(MAX_NETWORK_SIZE + 7) / 8];
174 
FilterContainsId(uint16_t aNodeId)175 static bool FilterContainsId(uint16_t aNodeId)
176 {
177     uint16_t index = aNodeId - 1;
178 
179     return (sFilterNodeIdsBitVector[index / 8] & (0x80 >> (index % 8))) != 0;
180 }
181 
NodeIdFilterIsConnectable(uint16_t aNodeId)182 static bool NodeIdFilterIsConnectable(uint16_t aNodeId)
183 {
184     bool isConnectable = true;
185 
186     otEXPECT_ACTION(aNodeId != gNodeId, isConnectable = false);
187 
188     switch (sFilterMode)
189     {
190     case kFilterOff:
191         break;
192     case kFilterDenyList:
193         isConnectable = !FilterContainsId(aNodeId);
194         break;
195     case kFilterAllowList:
196         isConnectable = FilterContainsId(aNodeId);
197         break;
198     }
199 
200 exit:
201     return isConnectable;
202 }
203 
AddNodeIdToFilter(uint16_t aNodeId)204 static void AddNodeIdToFilter(uint16_t aNodeId)
205 {
206     uint16_t index = aNodeId - 1;
207 
208     sFilterNodeIdsBitVector[index / 8] |= 0x80 >> (index % 8);
209 }
210 
otCliOutputFormat(const char * aFmt,...)211 OT_TOOL_WEAK void otCliOutputFormat(const char *aFmt, ...) { OT_UNUSED_VARIABLE(aFmt); }
212 
ProcessNodeIdFilter(void * aContext,uint8_t aArgsLength,char * aArgs[])213 otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[])
214 {
215     OT_UNUSED_VARIABLE(aContext);
216 
217     otError error = OT_ERROR_NONE;
218     bool    deny  = false;
219 
220     if (aArgsLength == 0)
221     {
222         switch (sFilterMode)
223         {
224         case kFilterOff:
225             otCliOutputFormat("off");
226             break;
227         case kFilterDenyList:
228             otCliOutputFormat("deny-list");
229             break;
230         case kFilterAllowList:
231             otCliOutputFormat("allow-list");
232             break;
233         }
234 
235         for (uint16_t nodeId = 0; nodeId <= (uint16_t)MAX_NETWORK_SIZE; nodeId++)
236         {
237             if (FilterContainsId(nodeId))
238             {
239                 otCliOutputFormat(" %d", nodeId);
240             }
241         }
242 
243         otCliOutputFormat("\r\n");
244     }
245     else if (!strcmp(aArgs[0], "clear"))
246     {
247         otEXPECT_ACTION(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
248 
249         memset(sFilterNodeIdsBitVector, 0, sizeof(sFilterNodeIdsBitVector));
250         sFilterMode = kFilterOff;
251     }
252     else if ((deny = !strcmp(aArgs[0], "deny")) || !strcmp(aArgs[0], "allow"))
253     {
254         uint16_t nodeId;
255         char    *endptr;
256 
257         otEXPECT_ACTION(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
258 
259         nodeId = (uint16_t)strtol(aArgs[1], &endptr, 0);
260 
261         otEXPECT_ACTION(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
262         otEXPECT_ACTION(1 <= nodeId && nodeId <= MAX_NETWORK_SIZE, error = OT_ERROR_INVALID_ARGS);
263 
264         otEXPECT_ACTION(sFilterMode != (deny ? kFilterAllowList : kFilterDenyList), error = OT_ERROR_INVALID_STATE);
265 
266         AddNodeIdToFilter(nodeId);
267         sFilterMode = deny ? kFilterDenyList : kFilterAllowList;
268     }
269     else
270     {
271         error = OT_ERROR_INVALID_COMMAND;
272     }
273 
274 exit:
275     return error;
276 }
277 #else
ProcessNodeIdFilter(void * aContext,uint8_t aArgsLength,char * aArgs[])278 otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[])
279 {
280     OT_UNUSED_VARIABLE(aContext);
281     OT_UNUSED_VARIABLE(aArgsLength);
282     OT_UNUSED_VARIABLE(aArgs);
283 
284     return OT_ERROR_NOT_IMPLEMENTED;
285 }
286 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
287 
IsTimeAfterOrEqual(uint32_t aTimeA,uint32_t aTimeB)288 static bool IsTimeAfterOrEqual(uint32_t aTimeA, uint32_t aTimeB) { return (aTimeA - aTimeB) < (1U << 31); }
289 
ReverseExtAddress(otExtAddress * aReversed,const otExtAddress * aOrigin)290 static void ReverseExtAddress(otExtAddress *aReversed, const otExtAddress *aOrigin)
291 {
292     for (size_t i = 0; i < sizeof(*aReversed); i++)
293     {
294         aReversed->m8[i] = aOrigin->m8[sizeof(*aOrigin) - 1 - i];
295     }
296 }
297 
hasFramePending(const otRadioFrame * aFrame)298 static bool hasFramePending(const otRadioFrame *aFrame)
299 {
300     bool         rval = false;
301     otMacAddress src;
302 
303     otEXPECT_ACTION(sSrcMatchEnabled, rval = true);
304     otEXPECT(otMacFrameGetSrcAddr(aFrame, &src) == OT_ERROR_NONE);
305 
306     switch (src.mType)
307     {
308     case OT_MAC_ADDRESS_TYPE_SHORT:
309         rval = utilsSoftSrcMatchShortFindEntry(src.mAddress.mShortAddress) >= 0;
310         break;
311     case OT_MAC_ADDRESS_TYPE_EXTENDED:
312     {
313         otExtAddress extAddr;
314 
315         ReverseExtAddress(&extAddr, &src.mAddress.mExtAddress);
316         rval = utilsSoftSrcMatchExtFindEntry(&extAddr) >= 0;
317         break;
318     }
319     default:
320         break;
321     }
322 
323 exit:
324     return rval;
325 }
326 
crc16_citt(uint16_t aFcs,uint8_t aByte)327 static uint16_t crc16_citt(uint16_t aFcs, uint8_t aByte)
328 {
329     // CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
330     // width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 name="KERMIT"
331     // http://reveng.sourceforge.net/crc-catalogue/16.htm#crc.cat.kermit
332     static const uint16_t sFcsTable[256] = {
333         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5,
334         0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52,
335         0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3,
336         0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
337         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9,
338         0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e,
339         0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f,
340         0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
341         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862,
342         0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb,
343         0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948,
344         0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
345         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226,
346         0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497,
347         0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704,
348         0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
349         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb,
350         0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c,
351         0x3de3, 0x2c6a, 0x1ef1, 0x0f78};
352     return (aFcs >> 8) ^ sFcsTable[(aFcs ^ aByte) & 0xff];
353 }
354 
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)355 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
356 {
357     OT_UNUSED_VARIABLE(aInstance);
358 
359     aIeeeEui64[0] = 0x18;
360     aIeeeEui64[1] = 0xb4;
361     aIeeeEui64[2] = 0x30;
362     aIeeeEui64[3] = 0x00;
363     aIeeeEui64[4] = (gNodeId >> 24) & 0xff;
364     aIeeeEui64[5] = (gNodeId >> 16) & 0xff;
365     aIeeeEui64[6] = (gNodeId >> 8) & 0xff;
366     aIeeeEui64[7] = gNodeId & 0xff;
367 }
368 
otPlatRadioSetPanId(otInstance * aInstance,otPanId aPanid)369 void otPlatRadioSetPanId(otInstance *aInstance, otPanId aPanid)
370 {
371     OT_UNUSED_VARIABLE(aInstance);
372 
373     assert(aInstance != NULL);
374 
375     sPanid = aPanid;
376     utilsSoftSrcMatchSetPanId(aPanid);
377 }
378 
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aExtAddress)379 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
380 {
381     OT_UNUSED_VARIABLE(aInstance);
382 
383     assert(aInstance != NULL);
384 
385     ReverseExtAddress(&sExtAddress, aExtAddress);
386 }
387 
otPlatRadioSetShortAddress(otInstance * aInstance,otShortAddress aShortAddress)388 void otPlatRadioSetShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
389 {
390     OT_UNUSED_VARIABLE(aInstance);
391 
392     assert(aInstance != NULL);
393 
394     sShortAddress = aShortAddress;
395 }
396 
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)397 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
398 {
399     OT_UNUSED_VARIABLE(aInstance);
400 
401     assert(aInstance != NULL);
402 
403     sPromiscuous = aEnable;
404 }
405 
platformRadioInit(void)406 void platformRadioInit(void)
407 {
408 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
409     parseFromEnvAsUint16("PORT_BASE", &sPortBase);
410     parseFromEnvAsUint16("PORT_OFFSET", &sPortOffset);
411     sPortOffset *= (MAX_NETWORK_SIZE + 1);
412 
413     utilsInitSocket(&sSocket, sPortBase + sPortOffset);
414 #endif
415 
416     sReceiveFrame.mPsdu  = sReceiveMessage.mPsdu;
417     sTransmitFrame.mPsdu = sTransmitMessage.mPsdu;
418     sAckFrame.mPsdu      = sAckMessage.mPsdu;
419 
420 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
421     sTransmitFrame.mInfo.mTxInfo.mIeInfo = &sTransmitIeInfo;
422 #else
423     sTransmitFrame.mInfo.mTxInfo.mIeInfo = NULL;
424 #endif
425 
426     for (size_t i = 0; i <= kMaxChannel - kMinChannel; i++)
427     {
428         sChannelMaxTransmitPower[i] = OT_RADIO_POWER_INVALID;
429     }
430 
431 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
432     otLinkMetricsInit(SIM_RECEIVE_SENSITIVITY);
433 #endif
434 }
435 
436 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
getCslPhase(void)437 static uint16_t getCslPhase(void)
438 {
439     uint32_t curTime       = otPlatAlarmMicroGetNow();
440     uint32_t cslPeriodInUs = sCslPeriod * OT_US_PER_TEN_SYMBOLS;
441     uint32_t diff = ((sCslSampleTime % cslPeriodInUs) - (curTime % cslPeriodInUs) + cslPeriodInUs) % cslPeriodInUs;
442 
443     return (uint16_t)(diff / OT_US_PER_TEN_SYMBOLS);
444 }
445 #endif
446 
otPlatRadioIsEnabled(otInstance * aInstance)447 bool otPlatRadioIsEnabled(otInstance *aInstance)
448 {
449     OT_UNUSED_VARIABLE(aInstance);
450 
451     return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
452 }
453 
otPlatRadioEnable(otInstance * aInstance)454 otError otPlatRadioEnable(otInstance *aInstance)
455 {
456     if (!otPlatRadioIsEnabled(aInstance))
457     {
458         sState = OT_RADIO_STATE_SLEEP;
459     }
460 
461     return OT_ERROR_NONE;
462 }
463 
otPlatRadioDisable(otInstance * aInstance)464 otError otPlatRadioDisable(otInstance *aInstance)
465 {
466     otError error = OT_ERROR_NONE;
467 
468     otEXPECT(otPlatRadioIsEnabled(aInstance));
469     otEXPECT_ACTION(sState == OT_RADIO_STATE_SLEEP, error = OT_ERROR_INVALID_STATE);
470 
471     sState = OT_RADIO_STATE_DISABLED;
472 
473 exit:
474     return error;
475 }
476 
otPlatRadioSleep(otInstance * aInstance)477 otError otPlatRadioSleep(otInstance *aInstance)
478 {
479     OT_UNUSED_VARIABLE(aInstance);
480 
481     assert(aInstance != NULL);
482 
483     otError error = OT_ERROR_INVALID_STATE;
484 
485     if (sState == OT_RADIO_STATE_SLEEP || sState == OT_RADIO_STATE_RECEIVE)
486     {
487         error  = OT_ERROR_NONE;
488         sState = OT_RADIO_STATE_SLEEP;
489     }
490 
491     return error;
492 }
493 
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)494 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
495 {
496     OT_UNUSED_VARIABLE(aInstance);
497 
498     assert(aInstance != NULL);
499 
500     otError error = OT_ERROR_INVALID_STATE;
501 
502     if (sState != OT_RADIO_STATE_DISABLED)
503     {
504         error                  = OT_ERROR_NONE;
505         sState                 = OT_RADIO_STATE_RECEIVE;
506         sTxWait                = false;
507         sReceiveFrame.mChannel = aChannel;
508         sCurrentChannel        = aChannel;
509     }
510 
511     return error;
512 }
513 
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)514 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
515 {
516     OT_UNUSED_VARIABLE(aInstance);
517     OT_UNUSED_VARIABLE(aFrame);
518 
519     assert(aInstance != NULL);
520     assert(aFrame != NULL);
521 
522     otError error = OT_ERROR_INVALID_STATE;
523 
524     if (sState == OT_RADIO_STATE_RECEIVE)
525     {
526         error           = OT_ERROR_NONE;
527         sState          = OT_RADIO_STATE_TRANSMIT;
528         sCurrentChannel = aFrame->mChannel;
529     }
530 
531     return error;
532 }
533 
otPlatRadioGetTransmitBuffer(otInstance * aInstance)534 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
535 {
536     OT_UNUSED_VARIABLE(aInstance);
537 
538     assert(aInstance != NULL);
539 
540     return &sTransmitFrame;
541 }
542 
otPlatRadioGetRssi(otInstance * aInstance)543 int8_t otPlatRadioGetRssi(otInstance *aInstance)
544 {
545     OT_UNUSED_VARIABLE(aInstance);
546     assert(aInstance != NULL);
547 
548     return GetRssi(sReceiveFrame.mChannel);
549 }
550 
GetRssi(uint16_t aChannel)551 static int8_t GetRssi(uint16_t aChannel)
552 {
553     int8_t   rssi = SIM_LOW_RSSI_SAMPLE;
554     uint32_t probabilityThreshold;
555 
556     otEXPECT((SIM_RADIO_CHANNEL_MIN <= aChannel) && aChannel <= (SIM_RADIO_CHANNEL_MAX));
557 
558     // To emulate a simple interference model, we return either a high or
559     // a low  RSSI value with a fixed probability per each channel. The
560     // probability is increased per channel by a constant.
561 
562     probabilityThreshold = (aChannel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
563 
564     if (otRandomNonCryptoGetUint16() < (probabilityThreshold * 0xffff / 100))
565     {
566         rssi = SIM_HIGH_RSSI_SAMPLE;
567     }
568 
569 exit:
570     return rssi;
571 }
572 
otPlatRadioGetCaps(otInstance * aInstance)573 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
574 {
575     OT_UNUSED_VARIABLE(aInstance);
576 
577     assert(aInstance != NULL);
578 
579     return gRadioCaps;
580 }
581 
otPlatRadioGetPromiscuous(otInstance * aInstance)582 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
583 {
584     OT_UNUSED_VARIABLE(aInstance);
585 
586     assert(aInstance != NULL);
587 
588     return sPromiscuous;
589 }
590 
radioReceive(otInstance * aInstance)591 static void radioReceive(otInstance *aInstance)
592 {
593     bool isTxDone = false;
594     bool isAck    = otMacFrameIsAck(&sReceiveFrame);
595 
596     otEXPECT(sReceiveFrame.mChannel == sReceiveMessage.mChannel);
597     otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT);
598 
599     // Unable to simulate SFD, so use the rx done timestamp instead.
600     sReceiveFrame.mInfo.mRxInfo.mTimestamp = otPlatTimeGet();
601 
602     if (sTxWait)
603     {
604         if (otMacFrameIsAckRequested(&sTransmitFrame))
605         {
606             uint8_t rxSeq;
607             uint8_t txSeq;
608 
609             isTxDone = isAck && otMacFrameGetSequence(&sReceiveFrame, &rxSeq) == OT_ERROR_NONE &&
610                        otMacFrameGetSequence(&sTransmitFrame, &txSeq) == OT_ERROR_NONE && rxSeq == txSeq;
611         }
612 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
613         // Simulate tx done when receiving the echo frame.
614         else
615         {
616             isTxDone = !isAck && sTransmitFrame.mLength == sReceiveFrame.mLength &&
617                        memcmp(sTransmitFrame.mPsdu, sReceiveFrame.mPsdu, sTransmitFrame.mLength) == 0;
618         }
619 #endif
620     }
621 
622     if (isTxDone)
623     {
624         sState  = OT_RADIO_STATE_RECEIVE;
625         sTxWait = false;
626 
627 #if OPENTHREAD_CONFIG_DIAG_ENABLE
628 
629         if (otPlatDiagModeGet())
630         {
631             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, OT_ERROR_NONE);
632         }
633         else
634 #endif
635         {
636             otPlatRadioTxDone(aInstance, &sTransmitFrame, (isAck ? &sReceiveFrame : NULL), OT_ERROR_NONE);
637         }
638     }
639     else if (!isAck || sPromiscuous)
640     {
641         radioProcessFrame(aInstance);
642     }
643 
644 exit:
645     return;
646 }
647 
radioComputeCrc(struct RadioMessage * aMessage,uint16_t aLength)648 static void radioComputeCrc(struct RadioMessage *aMessage, uint16_t aLength)
649 {
650     uint16_t crc        = 0;
651     uint16_t crc_offset = aLength - sizeof(uint16_t);
652 
653     for (uint16_t i = 0; i < crc_offset; i++)
654     {
655         crc = crc16_citt(crc, aMessage->mPsdu[i]);
656     }
657 
658     aMessage->mPsdu[crc_offset]     = crc & 0xff;
659     aMessage->mPsdu[crc_offset + 1] = crc >> 8;
660 }
661 
radioProcessTransmitSecurity(otRadioFrame * aFrame)662 static otError radioProcessTransmitSecurity(otRadioFrame *aFrame)
663 {
664     otError error = OT_ERROR_NONE;
665 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
666     otMacKeyMaterial *key = NULL;
667     uint8_t           keyId;
668 
669     otEXPECT(otMacFrameIsSecurityEnabled(aFrame) && otMacFrameIsKeyIdMode1(aFrame) &&
670              !aFrame->mInfo.mTxInfo.mIsSecurityProcessed);
671 
672     if (otMacFrameIsAck(aFrame))
673     {
674         keyId = otMacFrameGetKeyId(aFrame);
675 
676         otEXPECT_ACTION(keyId != 0, error = OT_ERROR_FAILED);
677 
678         if (keyId == sKeyId)
679         {
680             key = &sCurrKey;
681         }
682         else if (keyId == sKeyId - 1)
683         {
684             key = &sPrevKey;
685         }
686         else if (keyId == sKeyId + 1)
687         {
688             key = &sNextKey;
689         }
690         else
691         {
692             error = OT_ERROR_SECURITY;
693             otEXPECT(false);
694         }
695     }
696     else
697     {
698         key   = &sCurrKey;
699         keyId = sKeyId;
700     }
701 
702     aFrame->mInfo.mTxInfo.mAesKey = key;
703 
704     if (!aFrame->mInfo.mTxInfo.mIsHeaderUpdated)
705     {
706         otMacFrameSetKeyId(aFrame, keyId);
707         otMacFrameSetFrameCounter(aFrame, sMacFrameCounter++);
708     }
709 #else
710     otEXPECT(!aFrame->mInfo.mTxInfo.mIsSecurityProcessed);
711 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
712 
713     otMacFrameProcessTransmitAesCcm(aFrame, &sExtAddress);
714 
715 exit:
716     return error;
717 }
718 
radioSendMessage(otInstance * aInstance)719 void radioSendMessage(otInstance *aInstance)
720 {
721 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
722     if (sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0)
723     {
724         uint8_t *timeIe = sTransmitFrame.mPsdu + sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset;
725         uint64_t time = (uint64_t)((int64_t)otPlatTimeGet() + sTransmitFrame.mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
726 
727         *timeIe = sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeSyncSeq;
728 
729         *(++timeIe) = (uint8_t)(time & 0xff);
730         for (uint8_t i = 1; i < sizeof(uint64_t); i++)
731         {
732             time        = time >> 8;
733             *(++timeIe) = (uint8_t)(time & 0xff);
734         }
735     }
736 #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
737 
738 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
739     if (sCslPeriod > 0 && !sTransmitFrame.mInfo.mTxInfo.mIsHeaderUpdated)
740     {
741         otMacFrameSetCslIe(&sTransmitFrame, (uint16_t)sCslPeriod, getCslPhase());
742     }
743 #endif
744 
745     sTransmitMessage.mChannel = sTransmitFrame.mChannel;
746 
747     otEXPECT(radioProcessTransmitSecurity(&sTransmitFrame) == OT_ERROR_NONE);
748     otPlatRadioTxStarted(aInstance, &sTransmitFrame);
749     radioComputeCrc(&sTransmitMessage, sTransmitFrame.mLength);
750     radioTransmit(&sTransmitMessage, &sTransmitFrame);
751 
752 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
753     sTxWait = otMacFrameIsAckRequested(&sTransmitFrame);
754 
755     if (!sTxWait)
756     {
757         sState = OT_RADIO_STATE_RECEIVE;
758 
759 #if OPENTHREAD_CONFIG_DIAG_ENABLE
760 
761         if (otPlatDiagModeGet())
762         {
763             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, OT_ERROR_NONE);
764         }
765         else
766 #endif
767         {
768             otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_NONE);
769         }
770     }
771 #else
772     // Wait for echo radio in virtual time mode.
773     sTxWait = true;
774 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
775 exit:
776     return;
777 }
778 
platformRadioIsTransmitPending(void)779 bool platformRadioIsTransmitPending(void) { return sState == OT_RADIO_STATE_TRANSMIT && !sTxWait; }
780 
781 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
platformRadioReceive(otInstance * aInstance,uint8_t * aBuf,uint16_t aBufLength)782 void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLength)
783 {
784     assert(sizeof(sReceiveMessage) >= aBufLength);
785 
786     memcpy(&sReceiveMessage, aBuf, aBufLength);
787 
788     sReceiveFrame.mLength = (uint8_t)(aBufLength - 1);
789 
790     radioReceive(aInstance);
791 }
792 #else
platformRadioUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,struct timeval * aTimeout,int * aMaxFd)793 void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
794 {
795     if (sState != OT_RADIO_STATE_TRANSMIT || sTxWait)
796     {
797         utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
798     }
799 
800     if (platformRadioIsTransmitPending())
801     {
802         utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
803     }
804 
805     if (sEnergyScanning)
806     {
807         struct timeval tv  = {0, 0};
808         uint32_t       now = otPlatAlarmMilliGetNow();
809 
810         if (IsTimeAfterOrEqual(sEnergyScanEndTime, now))
811         {
812             uint32_t remaining = sEnergyScanEndTime - now;
813 
814             tv.tv_sec  = remaining / OT_MS_PER_S;
815             tv.tv_usec = (remaining % OT_MS_PER_S) * OT_US_PER_MS;
816         }
817 
818         if (timercmp(&tv, aTimeout, <))
819         {
820             *aTimeout = tv;
821         }
822     }
823 }
824 
825 // no need to close in virtual time mode.
platformRadioDeinit(void)826 void platformRadioDeinit(void) { utilsDeinitSocket(&sSocket); }
827 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
828 
platformRadioProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)829 void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
830 {
831     OT_UNUSED_VARIABLE(aReadFdSet);
832     OT_UNUSED_VARIABLE(aWriteFdSet);
833 
834 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
835     if (utilsCanSocketReceive(&sSocket, aReadFdSet))
836     {
837         uint16_t senderNodeId;
838         uint16_t len;
839 
840         len = utilsReceiveFromSocket(&sSocket, &sReceiveMessage, sizeof(sReceiveMessage), &senderNodeId);
841 
842         if (NodeIdFilterIsConnectable(senderNodeId))
843         {
844             sReceiveFrame.mLength = len - 1;
845             radioReceive(aInstance);
846         }
847     }
848 #endif
849 
850     if (platformRadioIsTransmitPending())
851     {
852         radioSendMessage(aInstance);
853     }
854 
855     if (sEnergyScanning && IsTimeAfterOrEqual(otPlatAlarmMilliGetNow(), sEnergyScanEndTime))
856     {
857         sEnergyScanning = false;
858         otPlatRadioEnergyScanDone(aInstance, sEnergyScanResult);
859     }
860 }
861 
radioTransmit(struct RadioMessage * aMessage,const struct otRadioFrame * aFrame)862 void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame)
863 {
864 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
865     utilsSendOverSocket(&sSocket, aMessage, aFrame->mLength + 1); // + 1 is for `mChannel`
866 #else
867     struct Event event;
868 
869     event.mDelay      = 1; // 1us for now
870     event.mEvent      = OT_SIM_EVENT_RADIO_RECEIVED;
871     event.mDataLength = 1 + aFrame->mLength; // include channel in first byte
872     memcpy(event.mData, aMessage, event.mDataLength);
873     otSimSendEvent(&event);
874 #endif
875 }
876 
radioSendAck(void)877 void radioSendAck(void)
878 {
879     if (
880 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
881         // Determine if frame pending should be set
882         ((otMacFrameIsVersion2015(&sReceiveFrame) && otMacFrameIsCommand(&sReceiveFrame)) ||
883          otMacFrameIsData(&sReceiveFrame) || otMacFrameIsDataRequest(&sReceiveFrame))
884 #else
885         otMacFrameIsDataRequest(&sReceiveFrame)
886 #endif
887         && hasFramePending(&sReceiveFrame))
888     {
889         sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
890     }
891 
892 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
893     // Use enh-ack for 802.15.4-2015 frames
894     if (otMacFrameIsVersion2015(&sReceiveFrame))
895     {
896         uint8_t  linkMetricsDataLen = 0;
897         uint8_t *dataPtr            = NULL;
898 
899 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
900         uint8_t      linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
901         otMacAddress macAddress;
902 
903         otEXPECT(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE);
904 
905         linkMetricsDataLen = otLinkMetricsEnhAckGenData(&macAddress, sReceiveFrame.mInfo.mRxInfo.mLqi,
906                                                         sReceiveFrame.mInfo.mRxInfo.mRssi, linkMetricsData);
907 
908         if (linkMetricsDataLen > 0)
909         {
910             dataPtr = linkMetricsData;
911         }
912 #endif
913 
914         sAckIeDataLength = generateAckIeData(dataPtr, linkMetricsDataLen);
915 
916         otEXPECT(otMacFrameGenerateEnhAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending,
917                                           sAckIeData, sAckIeDataLength, &sAckFrame) == OT_ERROR_NONE);
918 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
919         if (sCslPeriod > 0)
920         {
921             otMacFrameSetCslIe(&sAckFrame, (uint16_t)sCslPeriod, getCslPhase());
922         }
923 #endif
924         if (otMacFrameIsSecurityEnabled(&sAckFrame))
925         {
926             otEXPECT(radioProcessTransmitSecurity(&sAckFrame) == OT_ERROR_NONE);
927         }
928     }
929     else
930 #endif
931     {
932         otMacFrameGenerateImmAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending, &sAckFrame);
933     }
934 
935     sAckMessage.mChannel = sReceiveFrame.mChannel;
936 
937     radioComputeCrc(&sAckMessage, sAckFrame.mLength);
938     radioTransmit(&sAckMessage, &sAckFrame);
939 
940 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
941 exit:
942 #endif
943     return;
944 }
945 
radioProcessFrame(otInstance * aInstance)946 void radioProcessFrame(otInstance *aInstance)
947 {
948     otError      error = OT_ERROR_NONE;
949     otMacAddress macAddress;
950     OT_UNUSED_VARIABLE(macAddress);
951 
952     sReceiveFrame.mInfo.mRxInfo.mRssi = -20;
953     sReceiveFrame.mInfo.mRxInfo.mLqi  = OT_RADIO_LQI_NONE;
954 
955     sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = false;
956     sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck    = false;
957 
958     otEXPECT(sPromiscuous == false);
959 
960     otEXPECT_ACTION(otMacFrameDoesAddrMatch(&sReceiveFrame, sPanid, sShortAddress, &sExtAddress),
961                     error = OT_ERROR_ABORT);
962 
963 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
964     otEXPECT_ACTION(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE, error = OT_ERROR_PARSE);
965 #endif
966 
967     // generate acknowledgment
968     if (otMacFrameIsAckRequested(&sReceiveFrame))
969     {
970         radioSendAck();
971 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
972         if (otMacFrameIsSecurityEnabled(&sAckFrame))
973         {
974             sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = true;
975             sReceiveFrame.mInfo.mRxInfo.mAckFrameCounter    = otMacFrameGetFrameCounter(&sAckFrame);
976         }
977 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
978     }
979 
980 exit:
981 
982     if (error != OT_ERROR_ABORT)
983     {
984 #if OPENTHREAD_CONFIG_DIAG_ENABLE
985         if (otPlatDiagModeGet())
986         {
987             otPlatDiagRadioReceiveDone(aInstance, error == OT_ERROR_NONE ? &sReceiveFrame : NULL, error);
988         }
989         else
990 #endif
991         {
992             otPlatRadioReceiveDone(aInstance, error == OT_ERROR_NONE ? &sReceiveFrame : NULL, error);
993         }
994     }
995 }
996 
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)997 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
998 {
999     OT_UNUSED_VARIABLE(aInstance);
1000 
1001     assert(aInstance != NULL);
1002 
1003     sSrcMatchEnabled = aEnable;
1004 }
1005 
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)1006 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
1007 {
1008     OT_UNUSED_VARIABLE(aInstance);
1009     OT_UNUSED_VARIABLE(aScanChannel);
1010 
1011     otError error = OT_ERROR_NONE;
1012 
1013     assert(aInstance != NULL);
1014     assert(aScanChannel >= SIM_RADIO_CHANNEL_MIN && aScanChannel <= SIM_RADIO_CHANNEL_MAX);
1015     assert(aScanDuration > 0);
1016 
1017     otEXPECT_ACTION((gRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN), error = OT_ERROR_NOT_IMPLEMENTED);
1018     otEXPECT_ACTION(!sEnergyScanning, error = OT_ERROR_BUSY);
1019 
1020     sEnergyScanResult  = GetRssi(aScanChannel);
1021     sEnergyScanning    = true;
1022     sEnergyScanEndTime = otPlatAlarmMilliGetNow() + aScanDuration;
1023 
1024 exit:
1025     return error;
1026 }
1027 
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)1028 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
1029 {
1030     OT_UNUSED_VARIABLE(aInstance);
1031 
1032     int8_t maxPower = sChannelMaxTransmitPower[sCurrentChannel - kMinChannel];
1033 
1034     assert(aInstance != NULL);
1035 
1036     *aPower = sTxPower < maxPower ? sTxPower : maxPower;
1037 
1038     return OT_ERROR_NONE;
1039 }
1040 
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)1041 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
1042 {
1043     OT_UNUSED_VARIABLE(aInstance);
1044 
1045     assert(aInstance != NULL);
1046 
1047     sTxPower = aPower;
1048 
1049     return OT_ERROR_NONE;
1050 }
1051 
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)1052 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
1053 {
1054     OT_UNUSED_VARIABLE(aInstance);
1055 
1056     assert(aInstance != NULL);
1057 
1058     *aThreshold = sCcaEdThresh;
1059 
1060     return OT_ERROR_NONE;
1061 }
1062 
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)1063 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
1064 {
1065     OT_UNUSED_VARIABLE(aInstance);
1066 
1067     assert(aInstance != NULL);
1068 
1069     sCcaEdThresh = aThreshold;
1070 
1071     return OT_ERROR_NONE;
1072 }
1073 
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)1074 otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
1075 {
1076     OT_UNUSED_VARIABLE(aInstance);
1077 
1078     assert(aInstance != NULL && aGain != NULL);
1079 
1080     *aGain = sLnaGain;
1081 
1082     return OT_ERROR_NONE;
1083 }
1084 
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)1085 otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
1086 {
1087     OT_UNUSED_VARIABLE(aInstance);
1088 
1089     assert(aInstance != NULL);
1090 
1091     sLnaGain = aGain;
1092 
1093     return OT_ERROR_NONE;
1094 }
1095 
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)1096 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
1097 {
1098     OT_UNUSED_VARIABLE(aInstance);
1099 
1100     assert(aInstance != NULL);
1101 
1102     return SIM_RECEIVE_SENSITIVITY;
1103 }
1104 
otPlatRadioGetState(otInstance * aInstance)1105 otRadioState otPlatRadioGetState(otInstance *aInstance)
1106 {
1107     OT_UNUSED_VARIABLE(aInstance);
1108 
1109     return sState;
1110 }
1111 
1112 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)1113 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
1114 {
1115     OT_UNUSED_VARIABLE(aInstance);
1116 
1117     assert(aInstance != NULL);
1118 
1119     sRadioCoexEnabled = aEnabled;
1120     return OT_ERROR_NONE;
1121 }
1122 
otPlatRadioIsCoexEnabled(otInstance * aInstance)1123 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
1124 {
1125     OT_UNUSED_VARIABLE(aInstance);
1126 
1127     assert(aInstance != NULL);
1128 
1129     return sRadioCoexEnabled;
1130 }
1131 
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)1132 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
1133 {
1134     OT_UNUSED_VARIABLE(aInstance);
1135 
1136     otError error = OT_ERROR_NONE;
1137 
1138     assert(aInstance != NULL);
1139     otEXPECT_ACTION(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS);
1140 
1141     memset(aCoexMetrics, 0, sizeof(otRadioCoexMetrics));
1142 
1143     aCoexMetrics->mStopped                            = false;
1144     aCoexMetrics->mNumGrantGlitch                     = 1;
1145     aCoexMetrics->mNumTxRequest                       = 2;
1146     aCoexMetrics->mNumTxGrantImmediate                = 3;
1147     aCoexMetrics->mNumTxGrantWait                     = 4;
1148     aCoexMetrics->mNumTxGrantWaitActivated            = 5;
1149     aCoexMetrics->mNumTxGrantWaitTimeout              = 6;
1150     aCoexMetrics->mNumTxGrantDeactivatedDuringRequest = 7;
1151     aCoexMetrics->mNumTxDelayedGrant                  = 8;
1152     aCoexMetrics->mAvgTxRequestToGrantTime            = 9;
1153     aCoexMetrics->mNumRxRequest                       = 10;
1154     aCoexMetrics->mNumRxGrantImmediate                = 11;
1155     aCoexMetrics->mNumRxGrantWait                     = 12;
1156     aCoexMetrics->mNumRxGrantWaitActivated            = 13;
1157     aCoexMetrics->mNumRxGrantWaitTimeout              = 14;
1158     aCoexMetrics->mNumRxGrantDeactivatedDuringRequest = 15;
1159     aCoexMetrics->mNumRxDelayedGrant                  = 16;
1160     aCoexMetrics->mAvgRxRequestToGrantTime            = 17;
1161     aCoexMetrics->mNumRxGrantNone                     = 18;
1162 
1163 exit:
1164     return error;
1165 }
1166 #endif
1167 
otPlatRadioGetNow(otInstance * aInstance)1168 uint64_t otPlatRadioGetNow(otInstance *aInstance)
1169 {
1170     OT_UNUSED_VARIABLE(aInstance);
1171 
1172     return otPlatTimeGet();
1173 }
1174 
1175 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
generateAckIeData(uint8_t * aLinkMetricsIeData,uint8_t aLinkMetricsIeDataLen)1176 static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen)
1177 {
1178     OT_UNUSED_VARIABLE(aLinkMetricsIeData);
1179     OT_UNUSED_VARIABLE(aLinkMetricsIeDataLen);
1180 
1181     uint8_t offset = 0;
1182 
1183 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1184     if (sCslPeriod > 0)
1185     {
1186         offset += otMacFrameGenerateCslIeTemplate(sAckIeData);
1187     }
1188 #endif
1189 
1190 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1191     if (aLinkMetricsIeData != NULL && aLinkMetricsIeDataLen > 0)
1192     {
1193         offset += otMacFrameGenerateEnhAckProbingIe(sAckIeData, aLinkMetricsIeData, aLinkMetricsIeDataLen);
1194     }
1195 #endif
1196 
1197     return offset;
1198 }
1199 #endif
1200 
1201 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otPlatRadioEnableCsl(otInstance * aInstance,uint32_t aCslPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)1202 otError otPlatRadioEnableCsl(otInstance         *aInstance,
1203                              uint32_t            aCslPeriod,
1204                              otShortAddress      aShortAddr,
1205                              const otExtAddress *aExtAddr)
1206 {
1207     OT_UNUSED_VARIABLE(aInstance);
1208     OT_UNUSED_VARIABLE(aShortAddr);
1209     OT_UNUSED_VARIABLE(aExtAddr);
1210 
1211     sCslPeriod = aCslPeriod;
1212 
1213     return OT_ERROR_NONE;
1214 }
1215 
otPlatRadioResetCsl(otInstance * aInstance)1216 otError otPlatRadioResetCsl(otInstance *aInstance)
1217 {
1218     OT_UNUSED_VARIABLE(aInstance);
1219 
1220     sCslPeriod = 0;
1221 
1222     return OT_ERROR_NONE;
1223 }
1224 
otPlatRadioUpdateCslSampleTime(otInstance * aInstance,uint32_t aCslSampleTime)1225 void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
1226 {
1227     OT_UNUSED_VARIABLE(aInstance);
1228 
1229     sCslSampleTime = aCslSampleTime;
1230 }
1231 
otPlatRadioGetCslAccuracy(otInstance * aInstance)1232 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
1233 {
1234     OT_UNUSED_VARIABLE(aInstance);
1235 
1236     return 0;
1237 }
1238 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1239 
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)1240 void otPlatRadioSetMacKey(otInstance             *aInstance,
1241                           uint8_t                 aKeyIdMode,
1242                           uint8_t                 aKeyId,
1243                           const otMacKeyMaterial *aPrevKey,
1244                           const otMacKeyMaterial *aCurrKey,
1245                           const otMacKeyMaterial *aNextKey,
1246                           otRadioKeyType          aKeyType)
1247 {
1248     OT_UNUSED_VARIABLE(aInstance);
1249     OT_UNUSED_VARIABLE(aKeyIdMode);
1250 
1251     otEXPECT(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL);
1252 
1253     sKeyId   = aKeyId;
1254     sKeyType = aKeyType;
1255     memcpy(&sPrevKey, aPrevKey, sizeof(otMacKeyMaterial));
1256     memcpy(&sCurrKey, aCurrKey, sizeof(otMacKeyMaterial));
1257     memcpy(&sNextKey, aNextKey, sizeof(otMacKeyMaterial));
1258 
1259 exit:
1260     return;
1261 }
1262 
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)1263 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
1264 {
1265     OT_UNUSED_VARIABLE(aInstance);
1266 
1267     sMacFrameCounter = aMacFrameCounter;
1268 }
1269 
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)1270 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
1271 {
1272     OT_UNUSED_VARIABLE(aInstance);
1273 
1274     otError error = OT_ERROR_NONE;
1275 
1276     otEXPECT_ACTION(aChannel >= kMinChannel && aChannel <= kMaxChannel, error = OT_ERROR_INVALID_ARGS);
1277     sChannelMaxTransmitPower[aChannel - kMinChannel] = aMaxPower;
1278 
1279 exit:
1280     return error;
1281 }
1282 
1283 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)1284 otError otPlatRadioConfigureEnhAckProbing(otInstance          *aInstance,
1285                                           otLinkMetrics        aLinkMetrics,
1286                                           const otShortAddress aShortAddress,
1287                                           const otExtAddress  *aExtAddress)
1288 {
1289     OT_UNUSED_VARIABLE(aInstance);
1290 
1291     return otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics);
1292 }
1293 #endif
1294 
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)1295 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
1296 {
1297     OT_UNUSED_VARIABLE(aInstance);
1298 
1299     sRegionCode = aRegionCode;
1300     return OT_ERROR_NONE;
1301 }
1302 
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)1303 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
1304 {
1305     OT_UNUSED_VARIABLE(aInstance);
1306     otError error = OT_ERROR_NONE;
1307 
1308     otEXPECT_ACTION(aRegionCode != NULL, error = OT_ERROR_INVALID_ARGS);
1309 
1310     *aRegionCode = sRegionCode;
1311 exit:
1312     return error;
1313 }
1314 
parseFromEnvAsUint16(const char * aEnvName,uint16_t * aValue)1315 void parseFromEnvAsUint16(const char *aEnvName, uint16_t *aValue)
1316 {
1317     char *env = getenv(aEnvName);
1318 
1319     if (env)
1320     {
1321         char *endptr;
1322 
1323         *aValue = (uint16_t)strtol(env, &endptr, 0);
1324 
1325         if (*endptr != '\0')
1326         {
1327             fprintf(stderr, "Invalid %s: %s\n", aEnvName, env);
1328             exit(EXIT_FAILURE);
1329         }
1330     }
1331 }
1332