xref: /aosp_15_r20/external/ot-br-posix/src/agent/main.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *    Copyright (c) 2017, 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 #define OTBR_LOG_TAG "AGENT"
30 
31 #include <openthread-br/config.h>
32 
33 #include <algorithm>
34 #include <vector>
35 
36 #include <assert.h>
37 #include <getopt.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include <openthread/logging.h>
44 #include <openthread/platform/radio.h>
45 
46 #if OTBR_ENABLE_PLATFORM_ANDROID
47 #include <cutils/properties.h>
48 #endif
49 
50 #include "agent/application.hpp"
51 #include "common/code_utils.hpp"
52 #include "common/logging.hpp"
53 #include "common/mainloop.hpp"
54 #include "common/types.hpp"
55 #include "ncp/thread_host.hpp"
56 
57 #ifdef OTBR_ENABLE_PLATFORM_ANDROID
58 #include <log/log.h>
59 #ifndef __ANDROID__
60 #error "OTBR_ENABLE_PLATFORM_ANDROID can be enabled for only Android devices"
61 #endif
62 #endif
63 
64 static const char kDefaultInterfaceName[] = "wpan0";
65 
66 // Port number used by Rest server.
67 static const uint32_t kPortNumber = 8081;
68 
69 enum
70 {
71     OTBR_OPT_BACKBONE_INTERFACE_NAME = 'B',
72     OTBR_OPT_DEBUG_LEVEL             = 'd',
73     OTBR_OPT_HELP                    = 'h',
74     OTBR_OPT_INTERFACE_NAME          = 'I',
75     OTBR_OPT_VERBOSE                 = 'v',
76     OTBR_OPT_SYSLOG_DISABLE          = 's',
77     OTBR_OPT_VERSION                 = 'V',
78     OTBR_OPT_SHORTMAX                = 128,
79     OTBR_OPT_RADIO_VERSION,
80     OTBR_OPT_AUTO_ATTACH,
81     OTBR_OPT_REST_LISTEN_ADDR,
82     OTBR_OPT_REST_LISTEN_PORT,
83 };
84 
85 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
86 static jmp_buf sResetJump;
87 #endif
88 static otbr::Application *gApp = nullptr;
89 
90 void                       __gcov_flush();
91 static const struct option kOptions[] = {
92     {"backbone-ifname", required_argument, nullptr, OTBR_OPT_BACKBONE_INTERFACE_NAME},
93     {"debug-level", required_argument, nullptr, OTBR_OPT_DEBUG_LEVEL},
94     {"help", no_argument, nullptr, OTBR_OPT_HELP},
95     {"thread-ifname", required_argument, nullptr, OTBR_OPT_INTERFACE_NAME},
96     {"verbose", no_argument, nullptr, OTBR_OPT_VERBOSE},
97     {"syslog-disable", no_argument, nullptr, OTBR_OPT_SYSLOG_DISABLE},
98     {"version", no_argument, nullptr, OTBR_OPT_VERSION},
99     {"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION},
100     {"auto-attach", optional_argument, nullptr, OTBR_OPT_AUTO_ATTACH},
101     {"rest-listen-address", required_argument, nullptr, OTBR_OPT_REST_LISTEN_ADDR},
102     {"rest-listen-port", required_argument, nullptr, OTBR_OPT_REST_LISTEN_PORT},
103     {0, 0, 0, 0}};
104 
ParseInteger(const char * aStr,long & aOutResult)105 static bool ParseInteger(const char *aStr, long &aOutResult)
106 {
107     bool  successful = true;
108     char *strEnd;
109     long  result;
110 
111     VerifyOrExit(aStr != nullptr, successful = false);
112     errno  = 0;
113     result = strtol(aStr, &strEnd, 0);
114     VerifyOrExit(errno != ERANGE, successful = false);
115     VerifyOrExit(aStr != strEnd, successful = false);
116 
117     aOutResult = result;
118 
119 exit:
120     return successful;
121 }
122 
123 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
124 static constexpr char kAutoAttachDisableArg[] = "--auto-attach=0";
125 static char           sAutoAttachDisableArgStorage[sizeof(kAutoAttachDisableArg)];
126 
AppendAutoAttachDisableArg(int argc,char * argv[])127 static std::vector<char *> AppendAutoAttachDisableArg(int argc, char *argv[])
128 {
129     std::vector<char *> args(argv, argv + argc);
130 
131     args.erase(std::remove_if(
132                    args.begin(), args.end(),
133                    [](const char *arg) { return arg != nullptr && std::string(arg).rfind("--auto-attach", 0) == 0; }),
134                args.end());
135     strcpy(sAutoAttachDisableArgStorage, kAutoAttachDisableArg);
136     args.push_back(sAutoAttachDisableArgStorage);
137     args.push_back(nullptr);
138 
139     return args;
140 }
141 #endif
142 
PrintHelp(const char * aProgramName)143 static void PrintHelp(const char *aProgramName)
144 {
145     fprintf(stderr,
146             "Usage: %s [-I interfaceName] [-B backboneIfName] [-d DEBUG_LEVEL] [-v] [-s] [--auto-attach[=0/1]] "
147             "RADIO_URL [RADIO_URL]\n"
148             "    --auto-attach defaults to 1\n"
149             "    -s disables syslog and prints to standard out\n",
150             aProgramName);
151     fprintf(stderr, "%s", otSysGetRadioUrlHelpString());
152 }
153 
PrintVersion(void)154 static void PrintVersion(void)
155 {
156     printf("%s\n", OTBR_PACKAGE_VERSION);
157 }
158 
OnAllocateFailed(void)159 static void OnAllocateFailed(void)
160 {
161     otbrLogCrit("Allocate failure, exiting...");
162     exit(1);
163 }
164 
GetDefaultLogLevel(void)165 static otbrLogLevel GetDefaultLogLevel(void)
166 {
167 #if OTBR_ENABLE_PLATFORM_ANDROID
168     // The log level is set to DEBUG by default, the final output log will be filtered by Android log system.
169     otbrLogLevel level = OTBR_LOG_DEBUG;
170     char         value[PROPERTY_VALUE_MAX];
171 
172     // Set the Android log level to INFO by default.
173     __android_log_set_minimum_priority(ANDROID_LOG_INFO);
174 
175     property_get("ro.build.type", value, "user");
176     if (!strcmp(value, "user"))
177     {
178         level = OTBR_LOG_WARNING;
179     }
180 #else
181     otbrLogLevel level = OTBR_LOG_INFO;
182 #endif
183 
184     return level;
185 }
186 
PrintRadioVersionAndExit(const std::vector<const char * > & aRadioUrls)187 static void PrintRadioVersionAndExit(const std::vector<const char *> &aRadioUrls)
188 {
189     auto host = std::unique_ptr<otbr::Ncp::ThreadHost>(
190         otbr::Ncp::ThreadHost::Create(/* aInterfaceName */ "", aRadioUrls,
191                                       /* aBackboneInterfaceName */ "",
192                                       /* aDryRun */ true, /* aEnableAutoAttach */ false));
193     const char *coprocessorVersion;
194 
195     host->Init();
196 
197     coprocessorVersion = host->GetCoprocessorVersion();
198     printf("%s\n", coprocessorVersion);
199 
200     host->Deinit();
201 
202     exit(EXIT_SUCCESS);
203 }
204 
realmain(int argc,char * argv[])205 static int realmain(int argc, char *argv[])
206 {
207     otbrLogLevel              logLevel = GetDefaultLogLevel();
208     int                       opt;
209     int                       ret               = EXIT_SUCCESS;
210     const char               *interfaceName     = kDefaultInterfaceName;
211     bool                      verbose           = false;
212     bool                      syslogDisable     = false;
213     bool                      printRadioVersion = false;
214     bool                      enableAutoAttach  = true;
215     const char               *restListenAddress = "";
216     int                       restListenPort    = kPortNumber;
217     std::vector<const char *> radioUrls;
218     std::vector<const char *> backboneInterfaceNames;
219     long                      parseResult;
220 
221     std::set_new_handler(OnAllocateFailed);
222 
223     while ((opt = getopt_long(argc, argv, "B:d:hI:Vvs", kOptions, nullptr)) != -1)
224     {
225         switch (opt)
226         {
227         case OTBR_OPT_BACKBONE_INTERFACE_NAME:
228             backboneInterfaceNames.push_back(optarg);
229             otbrLogNotice("Backbone interface: %s", optarg);
230             break;
231 
232         case OTBR_OPT_DEBUG_LEVEL:
233             VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
234             VerifyOrExit(OTBR_LOG_EMERG <= parseResult && parseResult <= OTBR_LOG_DEBUG, ret = EXIT_FAILURE);
235             logLevel = static_cast<otbrLogLevel>(parseResult);
236             break;
237 
238         case OTBR_OPT_INTERFACE_NAME:
239             interfaceName = optarg;
240             break;
241 
242         case OTBR_OPT_VERBOSE:
243             verbose = true;
244             break;
245 
246         case OTBR_OPT_SYSLOG_DISABLE:
247             syslogDisable = true;
248             break;
249 
250         case OTBR_OPT_VERSION:
251             PrintVersion();
252             ExitNow();
253             break;
254 
255         case OTBR_OPT_HELP:
256             PrintHelp(argv[0]);
257             ExitNow(ret = EXIT_SUCCESS);
258             break;
259 
260         case OTBR_OPT_RADIO_VERSION:
261             printRadioVersion = true;
262             break;
263 
264         case OTBR_OPT_AUTO_ATTACH:
265             if (optarg == nullptr)
266             {
267                 enableAutoAttach = true;
268             }
269             else
270             {
271                 VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
272                 enableAutoAttach = parseResult;
273             }
274             break;
275         case OTBR_OPT_REST_LISTEN_ADDR:
276             restListenAddress = optarg;
277             break;
278 
279         case OTBR_OPT_REST_LISTEN_PORT:
280             VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
281             restListenPort = parseResult;
282             break;
283 
284         default:
285             PrintHelp(argv[0]);
286             ExitNow(ret = EXIT_FAILURE);
287             break;
288         }
289     }
290 
291     otbrLogInit(argv[0], logLevel, verbose, syslogDisable);
292     otbrLogNotice("Running %s", OTBR_PACKAGE_VERSION);
293     otbrLogNotice("Thread version: %s", otbr::Ncp::RcpHost::GetThreadVersion());
294     otbrLogNotice("Thread interface: %s", interfaceName);
295 
296     if (backboneInterfaceNames.empty())
297     {
298         otbrLogNotice("Backbone interface is not specified");
299     }
300 
301     for (int i = optind; i < argc; i++)
302     {
303         otbrLogNotice("Radio URL: %s", argv[i]);
304         radioUrls.push_back(argv[i]);
305     }
306 
307     if (printRadioVersion)
308     {
309         PrintRadioVersionAndExit(radioUrls);
310         assert(false);
311     }
312 
313     {
314         otbr::Application app(interfaceName, backboneInterfaceNames, radioUrls, enableAutoAttach, restListenAddress,
315                               restListenPort);
316 
317         gApp = &app;
318         app.Init();
319 
320         ret = app.Run();
321 
322         app.Deinit();
323     }
324 
325     otbrLogDeinit();
326 
327 exit:
328     return ret;
329 }
330 
otPlatReset(otInstance * aInstance)331 void otPlatReset(otInstance *aInstance)
332 {
333     OT_UNUSED_VARIABLE(aInstance);
334 
335     gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
336 
337     VerifyOrDie(gApp != nullptr, "gApp is null");
338     gApp->Deinit();
339     gApp = nullptr;
340 
341 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
342     longjmp(sResetJump, 1);
343     assert(false);
344 #else
345     // Exits immediately on Android. The Android system_server will receive the
346     // signal and decide whether (and how) to restart the ot-daemon
347     exit(0);
348 #endif
349 }
350 
main(int argc,char * argv[])351 int main(int argc, char *argv[])
352 {
353 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
354     if (setjmp(sResetJump))
355     {
356         std::vector<char *> args = AppendAutoAttachDisableArg(argc, argv);
357 
358         alarm(0);
359 #if OPENTHREAD_ENABLE_COVERAGE
360         __gcov_flush();
361 #endif
362 
363         execvp(args[0], args.data());
364     }
365 #endif
366     return realmain(argc, argv);
367 }
368