• 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 <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