• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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