1 /*
2 * Copyright (c) 2016, 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 /**
30 * @file
31 * @brief
32 * This file includes the platform-specific initializers.
33 */
34
35 #include "openthread-posix-config.h"
36 #include "platform-posix.h"
37
38 #include <assert.h>
39 #include <inttypes.h>
40
41 #include <openthread-core-config.h>
42 #include <openthread/border_router.h>
43 #include <openthread/cli.h>
44 #include <openthread/heap.h>
45 #include <openthread/tasklet.h>
46 #include <openthread/platform/alarm-milli.h>
47 #include <openthread/platform/infra_if.h>
48 #include <openthread/platform/otns.h>
49 #include <openthread/platform/radio.h>
50
51 #include "common/code_utils.hpp"
52 #include "common/debug.hpp"
53 #include "posix/platform/daemon.hpp"
54 #include "posix/platform/firewall.hpp"
55 #include "posix/platform/infra_if.hpp"
56 #include "posix/platform/mainloop.hpp"
57 #include "posix/platform/radio_url.hpp"
58 #include "posix/platform/udp.hpp"
59
60 otInstance *gInstance = nullptr;
61 bool gDryRun = false;
62
63 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
processStateChange(otChangedFlags aFlags,void * aContext)64 static void processStateChange(otChangedFlags aFlags, void *aContext)
65 {
66 otInstance *instance = static_cast<otInstance *>(aContext);
67
68 OT_UNUSED_VARIABLE(instance);
69 OT_UNUSED_VARIABLE(aFlags);
70
71 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
72 platformNetifStateChange(instance, aFlags);
73 #endif
74
75 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
76 ot::Posix::InfraNetif::Get().HandleBackboneStateChange(instance, aFlags);
77 #endif
78 }
79 #endif
80
get802154RadioUrl(otPlatformConfig * aPlatformConfig)81 static const char *get802154RadioUrl(otPlatformConfig *aPlatformConfig)
82 {
83 const char *radioUrl = nullptr;
84
85 for (uint8_t i = 0; i < aPlatformConfig->mRadioUrlNum; i++)
86 {
87 ot::Posix::RadioUrl url(aPlatformConfig->mRadioUrls[i]);
88
89 if (strcmp(url.GetProtocol(), "trel") == 0)
90 {
91 continue;
92 }
93
94 radioUrl = aPlatformConfig->mRadioUrls[i];
95 break;
96 }
97
98 VerifyOrDie(radioUrl != nullptr, OT_EXIT_INVALID_ARGUMENTS);
99 return radioUrl;
100 }
101
102 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
getTrelRadioUrl(otPlatformConfig * aPlatformConfig)103 static const char *getTrelRadioUrl(otPlatformConfig *aPlatformConfig)
104 {
105 const char *radioUrl = nullptr;
106
107 for (uint8_t i = 0; i < aPlatformConfig->mRadioUrlNum; i++)
108 {
109 ot::Posix::RadioUrl url(aPlatformConfig->mRadioUrls[i]);
110
111 if (strcmp(url.GetProtocol(), "trel") == 0)
112 {
113 radioUrl = aPlatformConfig->mRadioUrls[i];
114 break;
115 }
116 }
117
118 return radioUrl;
119 }
120 #endif
121
122 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
otSysSetInfraNetif(const char * aInfraNetifName,int aIcmp6Socket)123 void otSysSetInfraNetif(const char *aInfraNetifName, int aIcmp6Socket)
124 {
125 ot::Posix::InfraNetif::Get().SetInfraNetif(aInfraNetifName, aIcmp6Socket);
126 }
127 #endif
128
platformInit(otPlatformConfig * aPlatformConfig)129 void platformInit(otPlatformConfig *aPlatformConfig)
130 {
131 #if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE
132 platformBacktraceInit();
133 #endif
134
135 platformAlarmInit(aPlatformConfig->mSpeedUpFactor, aPlatformConfig->mRealTimeSignal);
136 platformRadioInit(get802154RadioUrl(aPlatformConfig));
137
138 // For Dry-Run option, only init the radio.
139 VerifyOrExit(!aPlatformConfig->mDryRun);
140
141 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
142 platformTrelInit(getTrelRadioUrl(aPlatformConfig));
143 #endif
144 platformRandomInit();
145
146 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
147 ot::Posix::InfraNetif::Get().Init();
148
149 #endif
150
151 gNetifName[0] = '\0';
152
153 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
154 platformNetifInit(aPlatformConfig);
155 #endif
156
157 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
158 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
159 ot::Posix::Udp::Get().Init(otSysGetThreadNetifName());
160 #else
161 ot::Posix::Udp::Get().Init(aPlatformConfig->mInterfaceName);
162 #endif
163 #endif
164
165 exit:
166 return;
167 }
168
platformSetUp(otPlatformConfig * aPlatformConfig)169 void platformSetUp(otPlatformConfig *aPlatformConfig)
170 {
171 OT_UNUSED_VARIABLE(aPlatformConfig);
172
173 VerifyOrExit(!gDryRun);
174
175 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
176 if (aPlatformConfig->mBackboneInterfaceName != nullptr && strlen(aPlatformConfig->mBackboneInterfaceName) > 0)
177 {
178 int icmp6Sock = -1;
179
180 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
181 icmp6Sock = ot::Posix::InfraNetif::CreateIcmp6Socket(aPlatformConfig->mBackboneInterfaceName);
182 #endif
183
184 otSysSetInfraNetif(aPlatformConfig->mBackboneInterfaceName, icmp6Sock);
185 }
186 #endif
187
188 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
189 if (aPlatformConfig->mBackboneInterfaceName != nullptr && strlen(aPlatformConfig->mBackboneInterfaceName) > 0)
190 {
191 otSysSetInfraNetif(aPlatformConfig->mBackboneInterfaceName,
192 ot::Posix::InfraNetif::CreateIcmp6Socket(aPlatformConfig->mBackboneInterfaceName));
193 }
194 ot::Posix::InfraNetif::Get().SetUp();
195 #endif
196
197 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
198 platformNetifSetUp();
199 #endif
200
201 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
202 ot::Posix::Udp::Get().SetUp();
203 #endif
204
205 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
206 ot::Posix::Daemon::Get().SetUp();
207 #endif
208
209 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
210 SuccessOrDie(otSetStateChangedCallback(gInstance, processStateChange, gInstance));
211 #endif
212
213 exit:
214 return;
215 }
216
otSysInit(otPlatformConfig * aPlatformConfig)217 otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
218 {
219 OT_ASSERT(gInstance == nullptr);
220
221 platformInit(aPlatformConfig);
222
223 gDryRun = aPlatformConfig->mDryRun;
224 gInstance = otInstanceInitSingle();
225 OT_ASSERT(gInstance != nullptr);
226
227 platformSetUp(aPlatformConfig);
228
229 return gInstance;
230 }
231
platformTearDown(void)232 void platformTearDown(void)
233 {
234 VerifyOrExit(!gDryRun);
235
236 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
237 ot::Posix::Daemon::Get().TearDown();
238 #endif
239
240 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
241 ot::Posix::Udp::Get().TearDown();
242 #endif
243
244 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
245 platformNetifTearDown();
246 #endif
247
248 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
249 ot::Posix::InfraNetif::Get().TearDown();
250 #endif
251
252 exit:
253 return;
254 }
255
platformDeinit(void)256 void platformDeinit(void)
257 {
258 #if OPENTHREAD_POSIX_VIRTUAL_TIME
259 virtualTimeDeinit();
260 #endif
261 platformRadioDeinit();
262
263 // For Dry-Run option, only the radio is initialized.
264 VerifyOrExit(!gDryRun);
265
266 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
267 ot::Posix::Udp::Get().Deinit();
268 #endif
269 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
270 platformNetifDeinit();
271 #endif
272 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
273 platformTrelDeinit();
274 #endif
275
276 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
277 ot::Posix::InfraNetif::Get().Deinit();
278 #endif
279
280 exit:
281 return;
282 }
283
otSysDeinit(void)284 void otSysDeinit(void)
285 {
286 OT_ASSERT(gInstance != nullptr);
287
288 platformTearDown();
289 otInstanceFinalize(gInstance);
290 gInstance = nullptr;
291 platformDeinit();
292 }
293
294 #if OPENTHREAD_POSIX_VIRTUAL_TIME
295 /**
296 * Try selecting the given file descriptors in nonblocking mode.
297 *
298 * @param[in,out] aContext A reference to the mainloop context.
299 *
300 * @returns The value returned from select().
301 *
302 */
trySelect(otSysMainloopContext & aContext)303 static int trySelect(otSysMainloopContext &aContext)
304 {
305 struct timeval timeout = {0, 0};
306 fd_set originReadFdSet = aContext.mReadFdSet;
307 fd_set originWriteFdSet = aContext.mWriteFdSet;
308 fd_set originErrorFdSet = aContext.mErrorFdSet;
309 int rval;
310
311 rval = select(aContext.mMaxFd + 1, &aContext.mReadFdSet, &aContext.mWriteFdSet, &aContext.mErrorFdSet, &timeout);
312
313 if (rval == 0)
314 {
315 aContext.mReadFdSet = originReadFdSet;
316 aContext.mWriteFdSet = originWriteFdSet;
317 aContext.mErrorFdSet = originErrorFdSet;
318 }
319
320 return rval;
321 }
322 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
323
otSysMainloopUpdate(otInstance * aInstance,otSysMainloopContext * aMainloop)324 void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop)
325 {
326 ot::Posix::Mainloop::Manager::Get().Update(*aMainloop);
327
328 platformAlarmUpdateTimeout(&aMainloop->mTimeout);
329 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
330 platformNetifUpdateFdSet(aMainloop);
331 #endif
332 #if OPENTHREAD_POSIX_VIRTUAL_TIME
333 virtualTimeUpdateFdSet(aMainloop);
334 #else
335 platformRadioUpdateFdSet(aMainloop);
336 #endif
337 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
338 platformTrelUpdateFdSet(aMainloop);
339 #endif
340
341 if (otTaskletsArePending(aInstance))
342 {
343 aMainloop->mTimeout.tv_sec = 0;
344 aMainloop->mTimeout.tv_usec = 0;
345 }
346 }
347
otSysMainloopPoll(otSysMainloopContext * aMainloop)348 int otSysMainloopPoll(otSysMainloopContext *aMainloop)
349 {
350 int rval;
351
352 #if OPENTHREAD_POSIX_VIRTUAL_TIME
353 if (timerisset(&aMainloop->mTimeout))
354 {
355 // Make sure there are no data ready in UART
356 rval = trySelect(*aMainloop);
357
358 if (rval == 0)
359 {
360 bool noWrite = true;
361
362 // If there are write requests, the device is supposed to wake soon
363 for (int i = 0; i < aMainloop->mMaxFd + 1; ++i)
364 {
365 if (FD_ISSET(i, &aMainloop->mWriteFdSet))
366 {
367 noWrite = false;
368 break;
369 }
370 }
371
372 if (noWrite)
373 {
374 virtualTimeSendSleepEvent(&aMainloop->mTimeout);
375 }
376
377 rval = select(aMainloop->mMaxFd + 1, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet,
378 &aMainloop->mErrorFdSet, nullptr);
379 }
380 }
381 else
382 #endif
383 {
384 rval = select(aMainloop->mMaxFd + 1, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet,
385 &aMainloop->mTimeout);
386 }
387
388 return rval;
389 }
390
otSysMainloopProcess(otInstance * aInstance,const otSysMainloopContext * aMainloop)391 void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMainloop)
392 {
393 ot::Posix::Mainloop::Manager::Get().Process(*aMainloop);
394
395 #if OPENTHREAD_POSIX_VIRTUAL_TIME
396 virtualTimeProcess(aInstance, aMainloop);
397 #else
398 platformRadioProcess(aInstance, aMainloop);
399 #endif
400 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
401 platformTrelProcess(aInstance, aMainloop);
402 #endif
403 platformAlarmProcess(aInstance);
404 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
405 platformNetifProcess(aMainloop);
406 #endif
407 }
408
IsSystemDryRun(void)409 bool IsSystemDryRun(void) { return gDryRun; }
410
411 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE && OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE
otSysCliInitUsingDaemon(otInstance * aInstance)412 void otSysCliInitUsingDaemon(otInstance *aInstance)
413 {
414 otCliInit(
415 aInstance,
416 [](void *aContext, const char *aFormat, va_list aArguments) -> int {
417 return static_cast<ot::Posix::Daemon *>(aContext)->OutputFormatV(aFormat, aArguments);
418 },
419 &ot::Posix::Daemon::Get());
420 }
421 #endif
422