• 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/trel.h>
47 #include <openthread/platform/alarm-milli.h>
48 #include <openthread/platform/infra_if.h>
49 #include <openthread/platform/logging.h>
50 #include <openthread/platform/otns.h>
51 #include <openthread/platform/radio.h>
52 
53 #include "common/code_utils.hpp"
54 #include "common/debug.hpp"
55 #include "posix/platform/daemon.hpp"
56 #include "posix/platform/firewall.hpp"
57 #include "posix/platform/infra_if.hpp"
58 #include "posix/platform/mainloop.hpp"
59 #include "posix/platform/mdns_socket.hpp"
60 #include "posix/platform/radio_url.hpp"
61 #include "posix/platform/spinel_driver_getter.hpp"
62 #include "posix/platform/udp.hpp"
63 
64 otInstance *gInstance = nullptr;
65 bool        gDryRun   = false;
66 
67 CoprocessorType sCoprocessorType = OT_COPROCESSOR_UNKNOWN;
68 
processStateChange(otChangedFlags aFlags,void * aContext)69 static void processStateChange(otChangedFlags aFlags, void *aContext)
70 {
71     otInstance *instance = static_cast<otInstance *>(aContext);
72 
73     OT_UNUSED_VARIABLE(instance);
74     OT_UNUSED_VARIABLE(aFlags);
75 
76 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
77     platformNetifStateChange(instance, aFlags);
78 #endif
79 
80 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
81     ot::Posix::InfraNetif::Get().HandleBackboneStateChange(instance, aFlags);
82 #endif
83 
84     platformRadioHandleStateChange(instance, aFlags);
85 }
86 
get802154RadioUrl(const otPlatformCoprocessorUrls & aUrls)87 static const char *get802154RadioUrl(const otPlatformCoprocessorUrls &aUrls)
88 {
89     const char *radioUrl = nullptr;
90 
91     for (uint8_t i = 0; i < aUrls.mNum; i++)
92     {
93         ot::Posix::RadioUrl url(aUrls.mUrls[i]);
94 
95         if (strcmp(url.GetProtocol(), "trel") == 0)
96         {
97             continue;
98         }
99 
100         radioUrl = aUrls.mUrls[i];
101         break;
102     }
103 
104     VerifyOrDie(radioUrl != nullptr, OT_EXIT_INVALID_ARGUMENTS);
105     return radioUrl;
106 }
107 
108 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
getTrelRadioUrl(otPlatformConfig * aPlatformConfig)109 static const char *getTrelRadioUrl(otPlatformConfig *aPlatformConfig)
110 {
111     const char *radioUrl = nullptr;
112 
113     for (uint8_t i = 0; i < aPlatformConfig->mCoprocessorUrls.mNum; i++)
114     {
115         ot::Posix::RadioUrl url(aPlatformConfig->mCoprocessorUrls.mUrls[i]);
116 
117         if (strcmp(url.GetProtocol(), "trel") == 0)
118         {
119             radioUrl = aPlatformConfig->mCoprocessorUrls.mUrls[i];
120             break;
121         }
122     }
123 
124     return radioUrl;
125 }
126 #endif
127 
128 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
otSysSetInfraNetif(const char * aInfraNetifName,int aIcmp6Socket)129 void otSysSetInfraNetif(const char *aInfraNetifName, int aIcmp6Socket)
130 {
131     ot::Posix::InfraNetif::Get().SetInfraNetif(aInfraNetifName, aIcmp6Socket);
132 }
133 #endif
134 
platformInitRcpMode(otPlatformConfig * aPlatformConfig)135 void platformInitRcpMode(otPlatformConfig *aPlatformConfig)
136 {
137     platformRadioInit(get802154RadioUrl(aPlatformConfig->mCoprocessorUrls));
138 
139     // For Dry-Run option, only init the co-processor.
140     VerifyOrExit(!aPlatformConfig->mDryRun);
141 
142 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE && !OPENTHREAD_POSIX_CONFIG_TREL_SELECT_INFRA_IF
143     platformTrelInit(getTrelRadioUrl(aPlatformConfig));
144 #endif
145     platformRandomInit();
146 
147 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
148     ot::Posix::InfraNetif::Get().Init();
149 #endif
150 
151 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
152     ot::Posix::MdnsSocket::Get().Init();
153 #endif
154 
155     gNetifName[0] = '\0';
156 
157 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
158     platformNetifInit(aPlatformConfig);
159 #endif
160 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
161     platformResolverInit();
162 #endif
163 
164 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
165 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
166     ot::Posix::Udp::Get().Init(otSysGetThreadNetifName());
167 #else
168     ot::Posix::Udp::Get().Init(aPlatformConfig->mInterfaceName);
169 #endif
170 #endif
171 exit:
172     return;
173 }
174 
platformInitNcpMode(otPlatformConfig * aPlatformConfig)175 void platformInitNcpMode(otPlatformConfig *aPlatformConfig)
176 {
177     // Do nothing now.
178     OT_UNUSED_VARIABLE(aPlatformConfig);
179 }
180 
platformInit(otPlatformConfig * aPlatformConfig)181 void platformInit(otPlatformConfig *aPlatformConfig)
182 {
183 #if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE
184     platformBacktraceInit();
185 #endif
186 
187     platformAlarmInit(aPlatformConfig->mSpeedUpFactor, aPlatformConfig->mRealTimeSignal);
188 
189     if (sCoprocessorType == OT_COPROCESSOR_UNKNOWN)
190     {
191         sCoprocessorType = platformSpinelManagerInit(get802154RadioUrl(aPlatformConfig->mCoprocessorUrls));
192     }
193 
194     switch (sCoprocessorType)
195     {
196     case OT_COPROCESSOR_RCP:
197         platformInitRcpMode(aPlatformConfig);
198         break;
199 
200     case OT_COPROCESSOR_NCP:
201         platformInitNcpMode(aPlatformConfig);
202         break;
203 
204     default:
205         otPlatLog(OT_LOG_LEVEL_CRIT, OT_LOG_REGION_PLATFORM, "Unknown type of the co-processor!\n");
206         exit(OT_EXIT_FAILURE);
207         break;
208     }
209 
210     aPlatformConfig->mCoprocessorType = sCoprocessorType;
211 }
212 
platformSetUp(otPlatformConfig * aPlatformConfig)213 void platformSetUp(otPlatformConfig *aPlatformConfig)
214 {
215     OT_UNUSED_VARIABLE(aPlatformConfig);
216 
217     VerifyOrExit(!gDryRun);
218 
219 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
220     if (aPlatformConfig->mBackboneInterfaceName != nullptr && strlen(aPlatformConfig->mBackboneInterfaceName) > 0)
221     {
222         int icmp6Sock = -1;
223 
224 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
225         icmp6Sock = ot::Posix::InfraNetif::CreateIcmp6Socket(aPlatformConfig->mBackboneInterfaceName);
226 #endif
227 
228         otSysSetInfraNetif(aPlatformConfig->mBackboneInterfaceName, icmp6Sock);
229     }
230 #endif
231 
232 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
233     ot::Posix::InfraNetif::Get().SetUp();
234 #endif
235 
236 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
237     platformNetifSetUp();
238 #endif
239 
240 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
241     ot::Posix::Udp::Get().SetUp();
242 #endif
243 
244 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
245     ot::Posix::MdnsSocket::Get().SetUp();
246 #endif
247 
248 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
249     ot::Posix::Daemon::Get().SetUp();
250 #endif
251 
252     SuccessOrDie(otSetStateChangedCallback(gInstance, processStateChange, gInstance));
253 
254 exit:
255     return;
256 }
257 
otSysInitCoprocessor(otPlatformCoprocessorUrls * aUrls)258 CoprocessorType otSysInitCoprocessor(otPlatformCoprocessorUrls *aUrls)
259 {
260     sCoprocessorType = platformSpinelManagerInit(get802154RadioUrl(*aUrls));
261     return sCoprocessorType;
262 }
263 
otSysGetSpinelDriver(void)264 otSpinelDriver *otSysGetSpinelDriver(void) { return &ot::Posix::GetSpinelDriver(); }
265 
otSysInit(otPlatformConfig * aPlatformConfig)266 otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
267 {
268     OT_ASSERT(gInstance == nullptr);
269 
270     platformInit(aPlatformConfig);
271 
272     gDryRun = aPlatformConfig->mDryRun;
273     if (sCoprocessorType == OT_COPROCESSOR_RCP)
274     {
275         gInstance = otInstanceInitSingle();
276         OT_ASSERT(gInstance != nullptr);
277 
278         platformSetUp(aPlatformConfig);
279     }
280 
281     return gInstance;
282 }
283 
platformTearDown(void)284 void platformTearDown(void)
285 {
286     VerifyOrExit(!gDryRun);
287 
288 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
289     ot::Posix::Daemon::Get().TearDown();
290 #endif
291 
292 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
293     ot::Posix::Udp::Get().TearDown();
294 #endif
295 
296 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
297     platformNetifTearDown();
298 #endif
299 
300 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
301     ot::Posix::InfraNetif::Get().TearDown();
302 #endif
303 
304 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
305     ot::Posix::MdnsSocket::Get().TearDown();
306 #endif
307 
308 exit:
309     return;
310 }
311 
platformDeinitRcpMode(void)312 void platformDeinitRcpMode(void)
313 {
314 #if OPENTHREAD_POSIX_VIRTUAL_TIME
315     virtualTimeDeinit();
316 #endif
317     platformRadioDeinit();
318     platformSpinelManagerDeinit();
319     sCoprocessorType = OT_COPROCESSOR_UNKNOWN;
320 
321     // For Dry-Run option, only the radio is initialized.
322     VerifyOrExit(!gDryRun);
323 
324 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
325     ot::Posix::Udp::Get().Deinit();
326 #endif
327 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
328     platformNetifDeinit();
329 #endif
330 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE && !OPENTHREAD_POSIX_CONFIG_TREL_SELECT_INFRA_IF
331     otPlatTrelDisable(/* aInstance */ nullptr);
332     platformTrelDeinit();
333 #endif
334 
335 #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
336     ot::Posix::InfraNetif::Get().Deinit();
337 #endif
338 
339 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
340     ot::Posix::MdnsSocket::Get().Deinit();
341 #endif
342 
343 exit:
344     return;
345 }
346 
platformDeinitNcpMode(void)347 void platformDeinitNcpMode(void)
348 {
349     platformSpinelManagerDeinit();
350     sCoprocessorType = OT_COPROCESSOR_UNKNOWN;
351 }
352 
otSysDeinit(void)353 void otSysDeinit(void)
354 {
355     if (sCoprocessorType == OT_COPROCESSOR_RCP)
356     {
357         OT_ASSERT(gInstance != nullptr);
358         platformTearDown();
359         otInstanceFinalize(gInstance);
360         gInstance = nullptr;
361         platformDeinitRcpMode();
362     }
363     else if (sCoprocessorType == OT_COPROCESSOR_NCP)
364     {
365         platformDeinitNcpMode();
366     }
367 }
368 
369 #if OPENTHREAD_POSIX_VIRTUAL_TIME
370 /**
371  * Try selecting the given file descriptors in nonblocking mode.
372  *
373  * @param[in,out]  aContext  A reference to the mainloop context.
374  *
375  * @returns The value returned from select().
376  */
trySelect(otSysMainloopContext & aContext)377 static int trySelect(otSysMainloopContext &aContext)
378 {
379     struct timeval timeout          = {0, 0};
380     fd_set         originReadFdSet  = aContext.mReadFdSet;
381     fd_set         originWriteFdSet = aContext.mWriteFdSet;
382     fd_set         originErrorFdSet = aContext.mErrorFdSet;
383     int            rval;
384 
385     rval = select(aContext.mMaxFd + 1, &aContext.mReadFdSet, &aContext.mWriteFdSet, &aContext.mErrorFdSet, &timeout);
386 
387     if (rval == 0)
388     {
389         aContext.mReadFdSet  = originReadFdSet;
390         aContext.mWriteFdSet = originWriteFdSet;
391         aContext.mErrorFdSet = originErrorFdSet;
392     }
393 
394     return rval;
395 }
396 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
397 
otSysMainloopUpdate(otInstance * aInstance,otSysMainloopContext * aMainloop)398 void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop)
399 {
400     ot::Posix::Mainloop::Manager::Get().Update(*aMainloop);
401 
402     platformAlarmUpdateTimeout(&aMainloop->mTimeout);
403 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
404     platformNetifUpdateFdSet(aMainloop);
405 #endif
406 #if OPENTHREAD_POSIX_VIRTUAL_TIME
407     virtualTimeUpdateFdSet(aMainloop);
408 #else
409     platformSpinelManagerUpdateFdSet(aMainloop);
410     platformRadioUpdateFdSet(aMainloop);
411 #endif
412 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
413     platformTrelUpdateFdSet(aMainloop);
414 #endif
415 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
416     platformResolverUpdateFdSet(aMainloop);
417 #endif
418 
419     if (otTaskletsArePending(aInstance))
420     {
421         aMainloop->mTimeout.tv_sec  = 0;
422         aMainloop->mTimeout.tv_usec = 0;
423     }
424 }
425 
otSysMainloopPoll(otSysMainloopContext * aMainloop)426 int otSysMainloopPoll(otSysMainloopContext *aMainloop)
427 {
428     int rval;
429 
430 #if OPENTHREAD_POSIX_VIRTUAL_TIME
431     if (timerisset(&aMainloop->mTimeout))
432     {
433         // Make sure there are no data ready in UART
434         rval = trySelect(*aMainloop);
435 
436         if (rval == 0)
437         {
438             bool noWrite = true;
439 
440             // If there are write requests, the device is supposed to wake soon
441             for (int i = 0; i < aMainloop->mMaxFd + 1; ++i)
442             {
443                 if (FD_ISSET(i, &aMainloop->mWriteFdSet))
444                 {
445                     noWrite = false;
446                     break;
447                 }
448             }
449 
450             if (noWrite)
451             {
452                 virtualTimeSendSleepEvent(&aMainloop->mTimeout);
453             }
454 
455             rval = select(aMainloop->mMaxFd + 1, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet,
456                           &aMainloop->mErrorFdSet, nullptr);
457         }
458     }
459     else
460 #endif
461     {
462         rval = select(aMainloop->mMaxFd + 1, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet,
463                       &aMainloop->mTimeout);
464     }
465 
466     return rval;
467 }
468 
otSysMainloopProcess(otInstance * aInstance,const otSysMainloopContext * aMainloop)469 void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMainloop)
470 {
471     ot::Posix::Mainloop::Manager::Get().Process(*aMainloop);
472 
473 #if OPENTHREAD_POSIX_VIRTUAL_TIME
474     virtualTimeProcess(aInstance, aMainloop);
475 #else
476     platformSpinelManagerProcess(aInstance, aMainloop);
477     platformRadioProcess(aInstance, aMainloop);
478 #endif
479 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
480     platformTrelProcess(aInstance, aMainloop);
481 #endif
482     platformAlarmProcess(aInstance);
483 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
484     platformNetifProcess(aMainloop);
485 #endif
486 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
487     platformResolverProcess(aMainloop);
488 #endif
489 }
490 
IsSystemDryRun(void)491 bool IsSystemDryRun(void) { return gDryRun; }
492 
493 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE && OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE
otSysCliInitUsingDaemon(otInstance * aInstance)494 void otSysCliInitUsingDaemon(otInstance *aInstance)
495 {
496     otCliInit(
497         aInstance,
498         [](void *aContext, const char *aFormat, va_list aArguments) -> int {
499             return static_cast<ot::Posix::Daemon *>(aContext)->OutputFormatV(aFormat, aArguments);
500         },
501         &ot::Posix::Daemon::Get());
502 }
503 #endif
504