xref: /aosp_15_r20/external/openthread/src/posix/platform/system.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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  *
377  */
trySelect(otSysMainloopContext & aContext)378 static int trySelect(otSysMainloopContext &aContext)
379 {
380     struct timeval timeout          = {0, 0};
381     fd_set         originReadFdSet  = aContext.mReadFdSet;
382     fd_set         originWriteFdSet = aContext.mWriteFdSet;
383     fd_set         originErrorFdSet = aContext.mErrorFdSet;
384     int            rval;
385 
386     rval = select(aContext.mMaxFd + 1, &aContext.mReadFdSet, &aContext.mWriteFdSet, &aContext.mErrorFdSet, &timeout);
387 
388     if (rval == 0)
389     {
390         aContext.mReadFdSet  = originReadFdSet;
391         aContext.mWriteFdSet = originWriteFdSet;
392         aContext.mErrorFdSet = originErrorFdSet;
393     }
394 
395     return rval;
396 }
397 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
398 
otSysMainloopUpdate(otInstance * aInstance,otSysMainloopContext * aMainloop)399 void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop)
400 {
401     ot::Posix::Mainloop::Manager::Get().Update(*aMainloop);
402 
403     platformAlarmUpdateTimeout(&aMainloop->mTimeout);
404 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
405     platformNetifUpdateFdSet(aMainloop);
406 #endif
407 #if OPENTHREAD_POSIX_VIRTUAL_TIME
408     virtualTimeUpdateFdSet(aMainloop);
409 #else
410     platformSpinelManagerUpdateFdSet(aMainloop);
411     platformRadioUpdateFdSet(aMainloop);
412 #endif
413 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
414     platformTrelUpdateFdSet(aMainloop);
415 #endif
416 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
417     platformResolverUpdateFdSet(aMainloop);
418 #endif
419 
420     if (otTaskletsArePending(aInstance))
421     {
422         aMainloop->mTimeout.tv_sec  = 0;
423         aMainloop->mTimeout.tv_usec = 0;
424     }
425 }
426 
otSysMainloopPoll(otSysMainloopContext * aMainloop)427 int otSysMainloopPoll(otSysMainloopContext *aMainloop)
428 {
429     int rval;
430 
431 #if OPENTHREAD_POSIX_VIRTUAL_TIME
432     if (timerisset(&aMainloop->mTimeout))
433     {
434         // Make sure there are no data ready in UART
435         rval = trySelect(*aMainloop);
436 
437         if (rval == 0)
438         {
439             bool noWrite = true;
440 
441             // If there are write requests, the device is supposed to wake soon
442             for (int i = 0; i < aMainloop->mMaxFd + 1; ++i)
443             {
444                 if (FD_ISSET(i, &aMainloop->mWriteFdSet))
445                 {
446                     noWrite = false;
447                     break;
448                 }
449             }
450 
451             if (noWrite)
452             {
453                 virtualTimeSendSleepEvent(&aMainloop->mTimeout);
454             }
455 
456             rval = select(aMainloop->mMaxFd + 1, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet,
457                           &aMainloop->mErrorFdSet, nullptr);
458         }
459     }
460     else
461 #endif
462     {
463         rval = select(aMainloop->mMaxFd + 1, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet,
464                       &aMainloop->mTimeout);
465     }
466 
467     return rval;
468 }
469 
otSysMainloopProcess(otInstance * aInstance,const otSysMainloopContext * aMainloop)470 void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMainloop)
471 {
472     ot::Posix::Mainloop::Manager::Get().Process(*aMainloop);
473 
474 #if OPENTHREAD_POSIX_VIRTUAL_TIME
475     virtualTimeProcess(aInstance, aMainloop);
476 #else
477     platformSpinelManagerProcess(aInstance, aMainloop);
478     platformRadioProcess(aInstance, aMainloop);
479 #endif
480 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
481     platformTrelProcess(aInstance, aMainloop);
482 #endif
483     platformAlarmProcess(aInstance);
484 #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
485     platformNetifProcess(aMainloop);
486 #endif
487 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
488     platformResolverProcess(aMainloop);
489 #endif
490 }
491 
IsSystemDryRun(void)492 bool IsSystemDryRun(void) { return gDryRun; }
493 
494 #if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE && OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE
otSysCliInitUsingDaemon(otInstance * aInstance)495 void otSysCliInitUsingDaemon(otInstance *aInstance)
496 {
497     otCliInit(
498         aInstance,
499         [](void *aContext, const char *aFormat, va_list aArguments) -> int {
500             return static_cast<ot::Posix::Daemon *>(aContext)->OutputFormatV(aFormat, aArguments);
501         },
502         &ot::Posix::Daemon::Get());
503 }
504 #endif
505