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