Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / web / web-service / wpan_service.cpp
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 /**
30  * @file
31  *   This file implements the wpan controller service
32  */
33
34 #include "web/web-service/wpan_service.hpp"
35
36 #include <inttypes.h>
37 #include <sstream>
38 #include <stdio.h>
39
40 #include "common/byteswap.hpp"
41 #include "common/code_utils.hpp"
42
43 namespace otbr {
44 namespace Web {
45
46 const char *WpanService::kBorderAgentHost = "127.0.0.1";
47 const char *WpanService::kBorderAgentPort = "49191";
48
49 #define WPAN_RESPONSE_SUCCESS "successful"
50 #define WPAN_RESPONSE_FAILURE "failed"
51
52 std::string WpanService::HandleJoinNetworkRequest(const std::string &aJoinRequest)
53 {
54     Json::Value                 root;
55     Json::Reader                reader;
56     Json::FastWriter            jsonWriter;
57     std::string                 response;
58     int                         index;
59     std::string                 masterKey;
60     std::string                 prefix;
61     bool                        defaultRoute;
62     int                         ret = kWpanStatus_Ok;
63     otbr::Web::OpenThreadClient client;
64
65     VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
66
67     VerifyOrExit(reader.parse(aJoinRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
68     index        = root["index"].asUInt();
69     masterKey    = root["masterKey"].asString();
70     prefix       = root["prefix"].asString();
71     defaultRoute = root["defaultRoute"].asBool();
72
73     if (prefix.find('/') == std::string::npos)
74     {
75         prefix += "/64";
76     }
77
78     VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed);
79     VerifyOrExit((ret = commitActiveDataset(client, masterKey, mNetworks[index].mNetworkName, mNetworks[index].mChannel,
80                                             mNetworks[index].mExtPanId, mNetworks[index].mPanId)) == kWpanStatus_Ok);
81     VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_JoinFailed);
82     VerifyOrExit(client.Execute("thread start") != nullptr, ret = kWpanStatus_JoinFailed);
83     VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
84                  ret = kWpanStatus_SetFailed);
85 exit:
86
87     root.clear();
88     root["result"] = WPAN_RESPONSE_SUCCESS;
89
90     root["error"] = ret;
91     if (ret != kWpanStatus_Ok)
92     {
93         otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
94         root["result"] = WPAN_RESPONSE_FAILURE;
95     }
96     response = jsonWriter.write(root);
97     return response;
98 }
99
100 std::string WpanService::HandleFormNetworkRequest(const std::string &aFormRequest)
101 {
102     Json::Value                 root;
103     Json::FastWriter            jsonWriter;
104     Json::Reader                reader;
105     std::string                 response;
106     otbr::Psk::Pskc             psk;
107     char                        pskcStr[OT_PSKC_MAX_LENGTH * 2 + 1];
108     uint8_t                     extPanIdBytes[OT_EXTENDED_PANID_LENGTH];
109     std::string                 masterKey;
110     std::string                 prefix;
111     uint16_t                    channel;
112     std::string                 networkName;
113     std::string                 passphrase;
114     uint16_t                    panId;
115     uint64_t                    extPanId;
116     bool                        defaultRoute;
117     int                         ret = kWpanStatus_Ok;
118     otbr::Web::OpenThreadClient client;
119
120     VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
121
122     pskcStr[OT_PSKC_MAX_LENGTH * 2] = '\0'; // for manipulating with strlen
123     VerifyOrExit(reader.parse(aFormRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
124     masterKey   = root["masterKey"].asString();
125     prefix      = root["prefix"].asString();
126     channel     = root["channel"].asUInt();
127     networkName = root["networkName"].asString();
128     passphrase  = root["passphrase"].asString();
129     VerifyOrExit(sscanf(root["panId"].asString().c_str(), "%hx", &panId) == 1, ret = kWpanStatus_ParseRequestFailed);
130     VerifyOrExit(sscanf(root["extPanId"].asString().c_str(), "%" PRIx64, &extPanId) == 1,
131                  ret = kWpanStatus_ParseRequestFailed);
132     defaultRoute = root["defaultRoute"].asBool();
133
134     otbr::Utils::Hex2Bytes(root["extPanId"].asString().c_str(), extPanIdBytes, OT_EXTENDED_PANID_LENGTH);
135     otbr::Utils::Bytes2Hex(psk.ComputePskc(extPanIdBytes, networkName.c_str(), passphrase.c_str()), OT_PSKC_MAX_LENGTH,
136                            pskcStr);
137
138     if (prefix.find('/') == std::string::npos)
139     {
140         prefix += "/64";
141     }
142
143     VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed);
144     VerifyOrExit((ret = commitActiveDataset(client, masterKey, networkName, channel, extPanId, panId)) ==
145                  kWpanStatus_Ok);
146     VerifyOrExit(client.Execute("pskc %s", pskcStr) != nullptr, ret = kWpanStatus_SetFailed);
147     VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_FormFailed);
148     VerifyOrExit(client.Execute("thread start") != nullptr, ret = kWpanStatus_FormFailed);
149     VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
150                  ret = kWpanStatus_SetFailed);
151 exit:
152
153     root.clear();
154
155     root["result"] = WPAN_RESPONSE_SUCCESS;
156     root["error"]  = ret;
157     if (ret != kWpanStatus_Ok)
158     {
159         otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
160         root["result"] = WPAN_RESPONSE_FAILURE;
161     }
162     response = jsonWriter.write(root);
163     return response;
164 }
165
166 std::string WpanService::HandleAddPrefixRequest(const std::string &aAddPrefixRequest)
167 {
168     Json::Value                 root;
169     Json::FastWriter            jsonWriter;
170     Json::Reader                reader;
171     std::string                 response;
172     std::string                 prefix;
173     bool                        defaultRoute;
174     int                         ret = kWpanStatus_Ok;
175     otbr::Web::OpenThreadClient client;
176
177     VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
178
179     VerifyOrExit(reader.parse(aAddPrefixRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
180     prefix       = root["prefix"].asString();
181     defaultRoute = root["defaultRoute"].asBool();
182
183     VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
184                  ret = kWpanStatus_SetGatewayFailed);
185 exit:
186
187     root.clear();
188
189     root["result"] = WPAN_RESPONSE_SUCCESS;
190     root["error"]  = ret;
191     if (ret != kWpanStatus_Ok)
192     {
193         otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
194         root["result"] = WPAN_RESPONSE_FAILURE;
195     }
196     response = jsonWriter.write(root);
197     return response;
198 }
199
200 std::string WpanService::HandleDeletePrefixRequest(const std::string &aDeleteRequest)
201 {
202     Json::Value                 root;
203     Json::FastWriter            jsonWriter;
204     Json::Reader                reader;
205     std::string                 response;
206     std::string                 prefix;
207     int                         ret = kWpanStatus_Ok;
208     otbr::Web::OpenThreadClient client;
209
210     VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
211
212     VerifyOrExit(reader.parse(aDeleteRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
213     prefix = root["prefix"].asString();
214
215     VerifyOrExit(client.Execute("prefix remove %s", prefix.c_str()) != nullptr, ret = kWpanStatus_SetGatewayFailed);
216 exit:
217
218     root.clear();
219     root["result"] = WPAN_RESPONSE_SUCCESS;
220
221     root["error"] = ret;
222     if (ret != kWpanStatus_Ok)
223     {
224         otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
225         root["result"] = WPAN_RESPONSE_FAILURE;
226     }
227     response = jsonWriter.write(root);
228     return response;
229 }
230
231 std::string WpanService::HandleStatusRequest()
232 {
233     Json::Value                 root, networkInfo;
234     Json::FastWriter            jsonWriter;
235     std::string                 response, networkName, extPanId, propertyValue;
236     int                         ret = kWpanStatus_Ok;
237     otbr::Web::OpenThreadClient client;
238     char *                      rval;
239
240     networkInfo["WPAN service"] = "uninitialized";
241     VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
242
243     VerifyOrExit((rval = client.Execute("state")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
244     networkInfo["NCP:State"] = rval;
245
246     if (!strcmp(rval, "disabled"))
247     {
248         networkInfo["WPAN service"] = "offline";
249         ExitNow();
250     }
251     else if (!strcmp(rval, "detached"))
252     {
253         networkInfo["WPAN service"] = "associating";
254         ExitNow();
255     }
256     else
257     {
258         networkInfo["WPAN service"] = "associated";
259     }
260
261     VerifyOrExit((rval = client.Execute("version")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
262     networkInfo["NCP:Version"] = rval;
263
264     VerifyOrExit((rval = client.Execute("eui64")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
265     networkInfo["NCP:HardwareAddress"] = rval;
266
267     VerifyOrExit((rval = client.Execute("channel")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
268     networkInfo["NCP:Channel"] = rval;
269
270     VerifyOrExit((rval = client.Execute("state")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
271     networkInfo["Network:NodeType"] = rval;
272
273     VerifyOrExit((rval = client.Execute("networkname")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
274     networkInfo["Network:Name"] = rval;
275
276     VerifyOrExit((rval = client.Execute("extpanid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
277     networkInfo["Network:XPANID"] = rval;
278
279     VerifyOrExit((rval = client.Execute("panid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
280     networkInfo["Network:PANID"] = rval;
281
282     {
283         static const char kMeshLocalPrefixLocator[]       = "Mesh Local Prefix: ";
284         static const char kMeshLocalAddressTokenLocator[] = "0:ff:fe00:";
285         std::string       meshLocalPrefix;
286
287         VerifyOrExit((rval = client.Execute("dataset active")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
288         rval = strstr(rval, kMeshLocalPrefixLocator);
289         rval += sizeof(kMeshLocalPrefixLocator) - 1;
290         *strstr(rval, "\r\n") = '\0';
291
292         networkInfo["IPv6:MeshLocalPrefix"] = rval;
293
294         meshLocalPrefix = rval;
295         meshLocalPrefix.resize(meshLocalPrefix.find(":/"));
296
297         VerifyOrExit((rval = client.Execute("ipaddr")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
298
299         for (rval = strtok(rval, "\r\n"); rval != nullptr; rval = strtok(nullptr, "\r\n"))
300         {
301             char *meshLocalAddressToken = nullptr;
302
303             if (strstr(rval, meshLocalPrefix.c_str()) != rval)
304             {
305                 continue;
306             }
307
308             meshLocalAddressToken = strstr(rval, kMeshLocalAddressTokenLocator);
309
310             if (meshLocalAddressToken == nullptr)
311             {
312                 break;
313             }
314
315             // In case this address is not ends with 0:ff:fe00:xxxx
316             if (strchr(meshLocalAddressToken + sizeof(kMeshLocalAddressTokenLocator) - 1, ':') != nullptr)
317             {
318                 break;
319             }
320         }
321
322         networkInfo["IPv6:MeshLocalAddress"] = rval;
323     }
324
325 exit:
326     root["result"] = networkInfo;
327
328     if (ret != kWpanStatus_Ok)
329     {
330         root["result"] = WPAN_RESPONSE_FAILURE;
331         otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
332     }
333     root["error"] = ret;
334     response      = jsonWriter.write(root);
335     return response;
336 }
337
338 std::string WpanService::HandleAvailableNetworkRequest()
339 {
340     Json::Value                 root, networks, networkInfo;
341     Json::FastWriter            jsonWriter;
342     std::string                 response;
343     int                         ret = kWpanStatus_Ok;
344     otbr::Web::OpenThreadClient client;
345
346     VerifyOrExit(client.Connect(), ret = kWpanStatus_ScanFailed);
347     VerifyOrExit((mNetworksCount = client.Scan(mNetworks, sizeof(mNetworks) / sizeof(mNetworks[0]))) > 0,
348                  ret = kWpanStatus_NetworkNotFound);
349
350     for (int i = 0; i < mNetworksCount; i++)
351     {
352         char extPanId[OT_EXTENDED_PANID_LENGTH * 2 + 1], panId[OT_PANID_LENGTH * 2 + 3],
353             hardwareAddress[OT_HARDWARE_ADDRESS_LENGTH * 2 + 1];
354         otbr::Utils::Long2Hex(bswap_64(mNetworks[i].mExtPanId), extPanId);
355         otbr::Utils::Bytes2Hex(mNetworks[i].mHardwareAddress, OT_HARDWARE_ADDRESS_LENGTH, hardwareAddress);
356         sprintf(panId, "0x%X", mNetworks[i].mPanId);
357         networkInfo[i]["nn"] = mNetworks[i].mNetworkName;
358         networkInfo[i]["xp"] = extPanId;
359         networkInfo[i]["pi"] = panId;
360         networkInfo[i]["ch"] = mNetworks[i].mChannel;
361         networkInfo[i]["ha"] = hardwareAddress;
362     }
363
364     root["result"] = networkInfo;
365
366 exit:
367     if (ret != kWpanStatus_Ok)
368     {
369         root["result"] = WPAN_RESPONSE_FAILURE;
370         otbrLog(OTBR_LOG_ERR, "Error is %d", ret);
371     }
372     root["error"] = ret;
373     response      = jsonWriter.write(root);
374     return response;
375 }
376
377 int WpanService::GetWpanServiceStatus(std::string &aNetworkName, std::string &aExtPanId) const
378 {
379     int                         status = kWpanStatus_Ok;
380     otbr::Web::OpenThreadClient client;
381     const char *                rval;
382
383     VerifyOrExit(client.Connect(), status = kWpanStatus_Uninitialized);
384     rval = client.Execute("state");
385     VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
386     if (!strcmp(rval, "disabled"))
387     {
388         status = kWpanStatus_Offline;
389     }
390     else if (!strcmp(rval, "detached"))
391     {
392         status = kWpanStatus_Associating;
393     }
394     else
395     {
396         rval = client.Execute("networkname");
397         VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
398         aNetworkName = rval;
399
400         rval = client.Execute("extpanid");
401         VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
402         aExtPanId = rval;
403     }
404
405 exit:
406
407     return status;
408 }
409
410 std::string WpanService::HandleCommission(const std::string &aCommissionRequest)
411 {
412     Json::Value  root;
413     Json::Reader reader;
414     int          ret = kWpanStatus_Ok;
415     std::string  pskd;
416     std::string  response;
417
418     VerifyOrExit(reader.parse(aCommissionRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
419     pskd = root["pskd"].asString();
420     {
421         otbr::Web::OpenThreadClient client;
422         const char *                rval;
423
424         VerifyOrExit(client.Connect(), ret = kWpanStatus_Uninitialized);
425         rval = client.Execute("commissioner start");
426         VerifyOrExit(rval != nullptr, ret = kWpanStatus_Down);
427         rval = client.Execute("commissioner joiner add * %s", pskd.c_str());
428         VerifyOrExit(rval != nullptr, ret = kWpanStatus_Down);
429         root["error"] = ret;
430     }
431 exit:
432     if (ret != kWpanStatus_Ok)
433     {
434         root["result"] = WPAN_RESPONSE_FAILURE;
435         otbrLog(OTBR_LOG_ERR, "error: %d", ret);
436     }
437     return response;
438 }
439
440 int WpanService::commitActiveDataset(otbr::Web::OpenThreadClient &aClient,
441                                      const std::string &          aMasterKey,
442                                      const std::string &          aNetworkName,
443                                      uint16_t                     aChannel,
444                                      uint64_t                     aExtPanId,
445                                      uint16_t                     aPanId)
446 {
447     int ret = kWpanStatus_Ok;
448
449     VerifyOrExit(aClient.Execute("dataset init new") != nullptr, ret = kWpanStatus_SetFailed);
450     VerifyOrExit(aClient.Execute("dataset masterkey %s", aMasterKey.c_str()) != nullptr, ret = kWpanStatus_SetFailed);
451     VerifyOrExit(aClient.Execute("dataset networkname %s", escapeOtCliEscapable(aNetworkName).c_str()) != nullptr,
452                  ret = kWpanStatus_SetFailed);
453     VerifyOrExit(aClient.Execute("dataset channel %u", aChannel) != nullptr, ret = kWpanStatus_SetFailed);
454     VerifyOrExit(aClient.Execute("dataset extpanid %016" PRIx64, aExtPanId) != nullptr, ret = kWpanStatus_SetFailed);
455     VerifyOrExit(aClient.Execute("dataset panid %u", aPanId) != nullptr, ret = kWpanStatus_SetFailed);
456     VerifyOrExit(aClient.Execute("dataset commit active") != nullptr, ret = kWpanStatus_SetFailed);
457
458 exit:
459     return ret;
460 }
461
462 std::string WpanService::escapeOtCliEscapable(const std::string &aArg)
463 {
464     std::stringbuf strbuf;
465
466     for (char c : aArg)
467     {
468         switch (c)
469         {
470         case ' ':
471         case '\t':
472         case '\r':
473         case '\n':
474         case '\\':
475             strbuf.sputc('\\');
476             // Fallthrough
477         default:
478             strbuf.sputc(c);
479         }
480     }
481
482     return strbuf.str();
483 }
484
485 } // namespace Web
486 } // namespace otbr