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 "host/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 #define DEFAULT_INTERFACE_NAME "wpan0"
65 static const char kDefaultInterfaceName[] = DEFAULT_INTERFACE_NAME;
66
67 // Port number used by Rest server.
68 static const uint32_t kPortNumber = 8081;
69 #define HELP_DEFAULT_REST_PORT_NUMBER "8081"
70
71 enum
72 {
73 OTBR_OPT_BACKBONE_INTERFACE_NAME = 'B',
74 OTBR_OPT_DEBUG_LEVEL = 'd',
75 OTBR_OPT_HELP = 'h',
76 OTBR_OPT_INTERFACE_NAME = 'I',
77 OTBR_OPT_VERBOSE = 'v',
78 OTBR_OPT_SYSLOG_DISABLE = 's',
79 OTBR_OPT_VERSION = 'V',
80 OTBR_OPT_SHORTMAX = 128,
81 OTBR_OPT_RADIO_VERSION,
82 OTBR_OPT_AUTO_ATTACH,
83 OTBR_OPT_REST_LISTEN_ADDR,
84 OTBR_OPT_REST_LISTEN_PORT,
85 };
86
87 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
88 static jmp_buf sResetJump;
89 #endif
90 static otbr::Application *gApp = nullptr;
91
92 void __gcov_flush();
93 static const struct option kOptions[] = {
94 {"backbone-ifname", required_argument, nullptr, OTBR_OPT_BACKBONE_INTERFACE_NAME},
95 {"debug-level", required_argument, nullptr, OTBR_OPT_DEBUG_LEVEL},
96 {"help", no_argument, nullptr, OTBR_OPT_HELP},
97 {"thread-ifname", required_argument, nullptr, OTBR_OPT_INTERFACE_NAME},
98 {"verbose", no_argument, nullptr, OTBR_OPT_VERBOSE},
99 {"syslog-disable", no_argument, nullptr, OTBR_OPT_SYSLOG_DISABLE},
100 {"version", no_argument, nullptr, OTBR_OPT_VERSION},
101 {"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION},
102 {"auto-attach", optional_argument, nullptr, OTBR_OPT_AUTO_ATTACH},
103 {"rest-listen-address", required_argument, nullptr, OTBR_OPT_REST_LISTEN_ADDR},
104 {"rest-listen-port", required_argument, nullptr, OTBR_OPT_REST_LISTEN_PORT},
105 {0, 0, 0, 0}};
106
ParseInteger(const char * aStr,long & aOutResult)107 static bool ParseInteger(const char *aStr, long &aOutResult)
108 {
109 bool successful = true;
110 char *strEnd;
111 long result;
112
113 VerifyOrExit(aStr != nullptr, successful = false);
114 errno = 0;
115 result = strtol(aStr, &strEnd, 0);
116 VerifyOrExit(errno != ERANGE, successful = false);
117 VerifyOrExit(aStr != strEnd, successful = false);
118
119 aOutResult = result;
120
121 exit:
122 return successful;
123 }
124
125 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
126 static constexpr char kAutoAttachDisableArg[] = "--auto-attach=0";
127 static char sAutoAttachDisableArgStorage[sizeof(kAutoAttachDisableArg)];
128
AppendAutoAttachDisableArg(int argc,char * argv[])129 static std::vector<char *> AppendAutoAttachDisableArg(int argc, char *argv[])
130 {
131 std::vector<char *> args(argv, argv + argc);
132
133 args.erase(std::remove_if(
134 args.begin(), args.end(),
135 [](const char *arg) { return arg != nullptr && std::string(arg).rfind("--auto-attach", 0) == 0; }),
136 args.end());
137 strcpy(sAutoAttachDisableArgStorage, kAutoAttachDisableArg);
138 args.push_back(sAutoAttachDisableArgStorage);
139 args.push_back(nullptr);
140
141 return args;
142 }
143 #endif
144
PrintHelp(const char * aProgramName)145 static void PrintHelp(const char *aProgramName)
146 {
147 fprintf(stderr,
148 "Usage: %s [-I interfaceName] [-B backboneIfName] [-d DEBUG_LEVEL] [-v] [-s] [--auto-attach[=0/1]] "
149 "RADIO_URL [RADIO_URL]\n"
150 " -I, --thread-ifname Name of the Thread network interface (default: " DEFAULT_INTERFACE_NAME ").\n"
151 " -B, --backbone-ifname Name of the backbone network interfaces (can be specified multiple times).\n"
152 " -d, --debug-level The log level (EMERG=0, ALERT=1, CRIT=2, ERR=3, WARNING=4, NOTICE=5, INFO=6, "
153 "DEBUG=7).\n"
154 " -v, --verbose Enable verbose logging.\n"
155 " -s, --syslog-disable Disable syslog and print to standard out.\n"
156 " -h, --help Show this help text.\n"
157 " -V, --version Print the application's version and exit.\n"
158 " --radio-version Print the radio coprocessor version and exit.\n"
159 " --auto-attach Whether or not to automatically attach to the saved network (default: 1).\n"
160 " --rest-listen-address Network address to listen on for the REST API (default: [::]).\n"
161 " --rest-listen-port Network port to listen on for the REST API "
162 "(default: " HELP_DEFAULT_REST_PORT_NUMBER ").\n"
163 "\n",
164 aProgramName);
165 fprintf(stderr, "%s", otSysGetRadioUrlHelpString());
166 }
167
PrintVersion(void)168 static void PrintVersion(void)
169 {
170 printf("%s\n", OTBR_PACKAGE_VERSION);
171 }
172
OnAllocateFailed(void)173 static void OnAllocateFailed(void)
174 {
175 otbrLogCrit("Allocate failure, exiting...");
176 exit(1);
177 }
178
GetDefaultLogLevel(void)179 static otbrLogLevel GetDefaultLogLevel(void)
180 {
181 #if OTBR_ENABLE_PLATFORM_ANDROID
182 // The log level is set to DEBUG by default, the final output log will be filtered by Android log system.
183 otbrLogLevel level = OTBR_LOG_DEBUG;
184 char value[PROPERTY_VALUE_MAX];
185
186 // Set the Android log level to INFO by default.
187 __android_log_set_minimum_priority(ANDROID_LOG_INFO);
188
189 property_get("ro.build.type", value, "user");
190 if (!strcmp(value, "user"))
191 {
192 level = OTBR_LOG_WARNING;
193 }
194 #else
195 otbrLogLevel level = OTBR_LOG_INFO;
196 #endif
197
198 return level;
199 }
200
PrintRadioVersionAndExit(const std::vector<const char * > & aRadioUrls)201 static void PrintRadioVersionAndExit(const std::vector<const char *> &aRadioUrls)
202 {
203 auto host = std::unique_ptr<otbr::Host::ThreadHost>(
204 otbr::Host::ThreadHost::Create(/* aInterfaceName */ "", aRadioUrls,
205 /* aBackboneInterfaceName */ "",
206 /* aDryRun */ true, /* aEnableAutoAttach */ false));
207 const char *coprocessorVersion;
208
209 host->Init();
210
211 coprocessorVersion = host->GetCoprocessorVersion();
212 printf("%s\n", coprocessorVersion);
213
214 host->Deinit();
215
216 exit(EXIT_SUCCESS);
217 }
218
realmain(int argc,char * argv[])219 static int realmain(int argc, char *argv[])
220 {
221 otbrLogLevel logLevel = GetDefaultLogLevel();
222 int opt;
223 int ret = EXIT_SUCCESS;
224 const char *interfaceName = kDefaultInterfaceName;
225 bool verbose = false;
226 bool syslogDisable = false;
227 bool printRadioVersion = false;
228 bool enableAutoAttach = true;
229 const char *restListenAddress = "";
230 int restListenPort = kPortNumber;
231 std::vector<const char *> radioUrls;
232 std::vector<const char *> backboneInterfaceNames;
233 long parseResult;
234
235 std::set_new_handler(OnAllocateFailed);
236
237 while ((opt = getopt_long(argc, argv, "B:d:hI:Vvs", kOptions, nullptr)) != -1)
238 {
239 switch (opt)
240 {
241 case OTBR_OPT_BACKBONE_INTERFACE_NAME:
242 backboneInterfaceNames.push_back(optarg);
243 otbrLogNotice("Backbone interface: %s", optarg);
244 break;
245
246 case OTBR_OPT_DEBUG_LEVEL:
247 VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
248 VerifyOrExit(OTBR_LOG_EMERG <= parseResult && parseResult <= OTBR_LOG_DEBUG, ret = EXIT_FAILURE);
249 logLevel = static_cast<otbrLogLevel>(parseResult);
250 break;
251
252 case OTBR_OPT_INTERFACE_NAME:
253 interfaceName = optarg;
254 break;
255
256 case OTBR_OPT_VERBOSE:
257 verbose = true;
258 break;
259
260 case OTBR_OPT_SYSLOG_DISABLE:
261 syslogDisable = true;
262 break;
263
264 case OTBR_OPT_VERSION:
265 PrintVersion();
266 ExitNow();
267 break;
268
269 case OTBR_OPT_HELP:
270 PrintHelp(argv[0]);
271 ExitNow(ret = EXIT_SUCCESS);
272 break;
273
274 case OTBR_OPT_RADIO_VERSION:
275 printRadioVersion = true;
276 break;
277
278 case OTBR_OPT_AUTO_ATTACH:
279 if (optarg == nullptr)
280 {
281 enableAutoAttach = true;
282 }
283 else
284 {
285 VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
286 enableAutoAttach = parseResult;
287 }
288 break;
289 case OTBR_OPT_REST_LISTEN_ADDR:
290 restListenAddress = optarg;
291 break;
292
293 case OTBR_OPT_REST_LISTEN_PORT:
294 VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
295 restListenPort = parseResult;
296 break;
297
298 default:
299 PrintHelp(argv[0]);
300 ExitNow(ret = EXIT_FAILURE);
301 break;
302 }
303 }
304
305 otbrLogInit(argv[0], logLevel, verbose, syslogDisable);
306 otbrLogNotice("Running %s", OTBR_PACKAGE_VERSION);
307 otbrLogNotice("Thread version: %s", otbr::Host::RcpHost::GetThreadVersion());
308 otbrLogNotice("Thread interface: %s", interfaceName);
309
310 if (backboneInterfaceNames.empty())
311 {
312 otbrLogNotice("Backbone interface is not specified");
313 }
314
315 for (int i = optind; i < argc; i++)
316 {
317 otbrLogNotice("Radio URL: %s", argv[i]);
318 radioUrls.push_back(argv[i]);
319 }
320
321 if (printRadioVersion)
322 {
323 PrintRadioVersionAndExit(radioUrls);
324 assert(false);
325 }
326
327 {
328 #if __linux__
329 otbr::Utils::InfraLinkSelector infraLinkSelector(backboneInterfaceNames);
330 const std::string backboneInterfaceName = infraLinkSelector.Select();
331 otbr::Application::ErrorCondition errorCondition = [&backboneInterfaceName, &infraLinkSelector](void) {
332 return std::string(infraLinkSelector.Select()) == backboneInterfaceName ? OTBR_ERROR_NONE
333 : OTBR_ERROR_INFRA_LINK_CHANGED;
334 };
335 #else
336 const std::string backboneInterfaceName = backboneInterfaceNames.empty() ? "" : backboneInterfaceNames.front();
337 #endif
338 std::unique_ptr<otbr::Host::ThreadHost> host = otbr::Host::ThreadHost::Create(
339 interfaceName, radioUrls, backboneInterfaceName.c_str(), /* aDryRun */ false, enableAutoAttach);
340
341 otbr::Application app(*host, interfaceName, backboneInterfaceName, restListenAddress, restListenPort);
342
343 gApp = &app;
344 app.Init();
345 #if __linux__
346 app.SetErrorCondition(errorCondition);
347 #endif
348
349 ret = app.Run();
350
351 app.Deinit();
352 }
353
354 otbrLogDeinit();
355
356 exit:
357 return ret;
358 }
359
otPlatReset(otInstance * aInstance)360 void otPlatReset(otInstance *aInstance)
361 {
362 OT_UNUSED_VARIABLE(aInstance);
363
364 gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
365
366 VerifyOrDie(gApp != nullptr, "gApp is null");
367 gApp->Deinit();
368 gApp = nullptr;
369
370 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
371 longjmp(sResetJump, 1);
372 assert(false);
373 #else
374 // Exits immediately on Android. The Android system_server will receive the
375 // signal and decide whether (and how) to restart the ot-daemon
376 exit(0);
377 #endif
378 }
379
main(int argc,char * argv[])380 int main(int argc, char *argv[])
381 {
382 #ifndef OTBR_ENABLE_PLATFORM_ANDROID
383 if (setjmp(sResetJump))
384 {
385 std::vector<char *> args = AppendAutoAttachDisableArg(argc, argv);
386
387 alarm(0);
388 #if OPENTHREAD_ENABLE_COVERAGE
389 __gcov_flush();
390 #endif
391
392 execvp(args[0], args.data());
393 }
394 #endif
395 return realmain(argc, argv);
396 }
397