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