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