• 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 
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