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