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