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