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