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