• 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 kSyslogIdent[]          = "otbr-agent";
62 static const char kDefaultInterfaceName[] = "wpan0";
63 
64 enum
65 {
66     OTBR_OPT_BACKBONE_INTERFACE_NAME = 'B',
67     OTBR_OPT_DEBUG_LEVEL             = 'd',
68     OTBR_OPT_HELP                    = 'h',
69     OTBR_OPT_INTERFACE_NAME          = 'I',
70     OTBR_OPT_VERBOSE                 = 'v',
71     OTBR_OPT_VERSION                 = 'V',
72     OTBR_OPT_SHORTMAX                = 128,
73     OTBR_OPT_RADIO_VERSION,
74     OTBR_OPT_AUTO_ATTACH,
75 };
76 
77 static jmp_buf            sResetJump;
78 static otbr::Application *gApp = nullptr;
79 
80 void                       __gcov_flush();
81 static const struct option kOptions[] = {
82     {"backbone-ifname", required_argument, nullptr, OTBR_OPT_BACKBONE_INTERFACE_NAME},
83     {"debug-level", required_argument, nullptr, OTBR_OPT_DEBUG_LEVEL},
84     {"help", no_argument, nullptr, OTBR_OPT_HELP},
85     {"thread-ifname", required_argument, nullptr, OTBR_OPT_INTERFACE_NAME},
86     {"verbose", no_argument, nullptr, OTBR_OPT_VERBOSE},
87     {"version", no_argument, nullptr, OTBR_OPT_VERSION},
88     {"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION},
89     {"auto-attach", optional_argument, nullptr, OTBR_OPT_AUTO_ATTACH},
90     {0, 0, 0, 0}};
91 
ParseInteger(const char * aStr,long & aOutResult)92 static bool ParseInteger(const char *aStr, long &aOutResult)
93 {
94     bool  successful = true;
95     char *strEnd;
96     long  result;
97 
98     VerifyOrExit(aStr != nullptr, successful = false);
99     errno  = 0;
100     result = strtol(aStr, &strEnd, 0);
101     VerifyOrExit(errno != ERANGE, successful = false);
102     VerifyOrExit(aStr != strEnd, successful = false);
103 
104     aOutResult = result;
105 
106 exit:
107     return successful;
108 }
109 
110 static constexpr char kAutoAttachDisableArg[] = "--auto-attach=0";
111 static char           sAutoAttachDisableArgStorage[sizeof(kAutoAttachDisableArg)];
112 
AppendAutoAttachDisableArg(int argc,char * argv[])113 static std::vector<char *> AppendAutoAttachDisableArg(int argc, char *argv[])
114 {
115     std::vector<char *> args(argv, argv + argc);
116 
117     args.erase(std::remove_if(
118                    args.begin(), args.end(),
119                    [](const char *arg) { return arg != nullptr && std::string(arg).rfind("--auto-attach", 0) == 0; }),
120                args.end());
121     strcpy(sAutoAttachDisableArgStorage, kAutoAttachDisableArg);
122     args.push_back(sAutoAttachDisableArgStorage);
123     args.push_back(nullptr);
124 
125     return args;
126 }
127 
PrintHelp(const char * aProgramName)128 static void PrintHelp(const char *aProgramName)
129 {
130     fprintf(stderr,
131             "Usage: %s [-I interfaceName] [-B backboneIfName] [-d DEBUG_LEVEL] [-v] [--auto-attach[=0/1]] RADIO_URL "
132             "[RADIO_URL]\n"
133             "    --auto-attach defaults to 1\n",
134             aProgramName);
135     fprintf(stderr, "%s", otSysGetRadioUrlHelpString());
136 }
137 
PrintVersion(void)138 static void PrintVersion(void)
139 {
140     printf("%s\n", OTBR_PACKAGE_VERSION);
141 }
142 
OnAllocateFailed(void)143 static void OnAllocateFailed(void)
144 {
145     otbrLogCrit("Allocate failure, exiting...");
146     exit(1);
147 }
148 
GetDefaultLogLevel(void)149 static otbrLogLevel GetDefaultLogLevel(void)
150 {
151     otbrLogLevel level = OTBR_LOG_INFO;
152 
153 #if __ANDROID__ && OTBR_CONFIG_ANDROID_PROPERTY_ENABLE
154     char value[PROPERTY_VALUE_MAX];
155 
156     property_get("ro.build.type", value, "user");
157     if (!strcmp(value, "user"))
158     {
159         level = OTBR_LOG_WARNING;
160     }
161 #endif
162 
163     return level;
164 }
165 
PrintRadioVersionAndExit(const std::vector<const char * > & aRadioUrls)166 static void PrintRadioVersionAndExit(const std::vector<const char *> &aRadioUrls)
167 {
168     otbr::Ncp::ControllerOpenThread ncpOpenThread{/* aInterfaceName */ "", aRadioUrls, /* aBackboneInterfaceName */ "",
169                                                   /* aDryRun */ true, /* aEnableAutoAttach */ false};
170     const char *                    radioVersion;
171 
172     ncpOpenThread.Init();
173 
174     radioVersion = otPlatRadioGetVersionString(ncpOpenThread.GetInstance());
175     otbrLogNotice("Radio version: %s", radioVersion);
176     printf("%s\n", radioVersion);
177 
178     ncpOpenThread.Deinit();
179 
180     exit(EXIT_SUCCESS);
181 }
182 
realmain(int argc,char * argv[])183 static int realmain(int argc, char *argv[])
184 {
185     otbrLogLevel              logLevel = GetDefaultLogLevel();
186     int                       opt;
187     int                       ret               = EXIT_SUCCESS;
188     const char *              interfaceName     = kDefaultInterfaceName;
189     bool                      verbose           = false;
190     bool                      printRadioVersion = false;
191     bool                      enableAutoAttach  = true;
192     std::vector<const char *> radioUrls;
193     std::vector<const char *> backboneInterfaceNames;
194     long                      parseResult;
195 
196     std::set_new_handler(OnAllocateFailed);
197 
198     while ((opt = getopt_long(argc, argv, "B:d:hI:Vv", kOptions, nullptr)) != -1)
199     {
200         switch (opt)
201         {
202         case OTBR_OPT_BACKBONE_INTERFACE_NAME:
203             backboneInterfaceNames.push_back(optarg);
204             otbrLogNotice("Backbone interface: %s", optarg);
205             break;
206 
207         case OTBR_OPT_DEBUG_LEVEL:
208             VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
209             VerifyOrExit(OTBR_LOG_EMERG <= parseResult && parseResult <= OTBR_LOG_DEBUG, ret = EXIT_FAILURE);
210             logLevel = static_cast<otbrLogLevel>(parseResult);
211             break;
212 
213         case OTBR_OPT_INTERFACE_NAME:
214             interfaceName = optarg;
215             break;
216 
217         case OTBR_OPT_VERBOSE:
218             verbose = true;
219             break;
220 
221         case OTBR_OPT_VERSION:
222             PrintVersion();
223             ExitNow();
224             break;
225 
226         case OTBR_OPT_HELP:
227             PrintHelp(argv[0]);
228             ExitNow(ret = EXIT_SUCCESS);
229             break;
230 
231         case OTBR_OPT_RADIO_VERSION:
232             printRadioVersion = true;
233             break;
234 
235         case OTBR_OPT_AUTO_ATTACH:
236             if (optarg == nullptr)
237             {
238                 enableAutoAttach = true;
239             }
240             else
241             {
242                 VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
243                 enableAutoAttach = parseResult;
244             }
245             break;
246 
247         default:
248             PrintHelp(argv[0]);
249             ExitNow(ret = EXIT_FAILURE);
250             break;
251         }
252     }
253 
254     otbrLogInit(kSyslogIdent, logLevel, verbose);
255     otbrLogNotice("Running %s", OTBR_PACKAGE_VERSION);
256     otbrLogNotice("Thread version: %s", otbr::Ncp::ControllerOpenThread::GetThreadVersion());
257     otbrLogNotice("Thread interface: %s", interfaceName);
258 
259     if (backboneInterfaceNames.empty())
260     {
261         otbrLogNotice("Backbone interface is not specified");
262     }
263 
264     for (int i = optind; i < argc; i++)
265     {
266         otbrLogNotice("Radio URL: %s", argv[i]);
267         radioUrls.push_back(argv[i]);
268     }
269 
270     if (printRadioVersion)
271     {
272         PrintRadioVersionAndExit(radioUrls);
273         assert(false);
274     }
275 
276     {
277         otbr::Application app(interfaceName, backboneInterfaceNames, radioUrls, enableAutoAttach);
278 
279         gApp = &app;
280         app.Init();
281 
282         ret = app.Run();
283 
284         app.Deinit();
285     }
286 
287     otbrLogDeinit();
288 
289 exit:
290     return ret;
291 }
292 
otPlatReset(otInstance * aInstance)293 void otPlatReset(otInstance *aInstance)
294 {
295     OT_UNUSED_VARIABLE(aInstance);
296 
297     gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
298 
299     VerifyOrDie(gApp != nullptr, "gApp is null");
300     gApp->Deinit();
301     gApp = nullptr;
302 
303     longjmp(sResetJump, 1);
304     assert(false);
305 }
306 
main(int argc,char * argv[])307 int main(int argc, char *argv[])
308 {
309     if (setjmp(sResetJump))
310     {
311         std::vector<char *> args = AppendAutoAttachDisableArg(argc, argv);
312 
313         alarm(0);
314 #if OPENTHREAD_ENABLE_COVERAGE
315         __gcov_flush();
316 #endif
317 
318         execvp(args[0], args.data());
319     }
320 
321     return realmain(argc, argv);
322 }
323