• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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