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