2 * Copyright (c) 2017, The OpenThread Authors.
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.
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.
31 * This file implements the wpan controller service
34 #include "web/web-service/wpan_service.hpp"
40 #include "common/byteswap.hpp"
41 #include "common/code_utils.hpp"
46 const char *WpanService::kBorderAgentHost = "127.0.0.1";
47 const char *WpanService::kBorderAgentPort = "49191";
49 #define WPAN_RESPONSE_SUCCESS "successful"
50 #define WPAN_RESPONSE_FAILURE "failed"
52 std::string WpanService::HandleJoinNetworkRequest(const std::string &aJoinRequest)
56 Json::FastWriter jsonWriter;
59 std::string masterKey;
62 int ret = kWpanStatus_Ok;
63 otbr::Web::OpenThreadClient client;
65 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
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();
73 if (prefix.find('/') == std::string::npos)
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);
88 root["result"] = WPAN_RESPONSE_SUCCESS;
91 if (ret != kWpanStatus_Ok)
93 otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
94 root["result"] = WPAN_RESPONSE_FAILURE;
96 response = jsonWriter.write(root);
100 std::string WpanService::HandleFormNetworkRequest(const std::string &aFormRequest)
103 Json::FastWriter jsonWriter;
105 std::string response;
107 char pskcStr[OT_PSKC_MAX_LENGTH * 2 + 1];
108 uint8_t extPanIdBytes[OT_EXTENDED_PANID_LENGTH];
109 std::string masterKey;
112 std::string networkName;
113 std::string passphrase;
117 int ret = kWpanStatus_Ok;
118 otbr::Web::OpenThreadClient client;
120 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
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();
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,
138 if (prefix.find('/') == std::string::npos)
143 VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed);
144 VerifyOrExit((ret = commitActiveDataset(client, masterKey, networkName, channel, extPanId, panId)) ==
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);
155 root["result"] = WPAN_RESPONSE_SUCCESS;
157 if (ret != kWpanStatus_Ok)
159 otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
160 root["result"] = WPAN_RESPONSE_FAILURE;
162 response = jsonWriter.write(root);
166 std::string WpanService::HandleAddPrefixRequest(const std::string &aAddPrefixRequest)
169 Json::FastWriter jsonWriter;
171 std::string response;
174 int ret = kWpanStatus_Ok;
175 otbr::Web::OpenThreadClient client;
177 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
179 VerifyOrExit(reader.parse(aAddPrefixRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
180 prefix = root["prefix"].asString();
181 defaultRoute = root["defaultRoute"].asBool();
183 VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
184 ret = kWpanStatus_SetGatewayFailed);
189 root["result"] = WPAN_RESPONSE_SUCCESS;
191 if (ret != kWpanStatus_Ok)
193 otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
194 root["result"] = WPAN_RESPONSE_FAILURE;
196 response = jsonWriter.write(root);
200 std::string WpanService::HandleDeletePrefixRequest(const std::string &aDeleteRequest)
203 Json::FastWriter jsonWriter;
205 std::string response;
207 int ret = kWpanStatus_Ok;
208 otbr::Web::OpenThreadClient client;
210 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
212 VerifyOrExit(reader.parse(aDeleteRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
213 prefix = root["prefix"].asString();
215 VerifyOrExit(client.Execute("prefix remove %s", prefix.c_str()) != nullptr, ret = kWpanStatus_SetGatewayFailed);
219 root["result"] = WPAN_RESPONSE_SUCCESS;
222 if (ret != kWpanStatus_Ok)
224 otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
225 root["result"] = WPAN_RESPONSE_FAILURE;
227 response = jsonWriter.write(root);
231 std::string WpanService::HandleStatusRequest()
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;
240 networkInfo["WPAN service"] = "uninitialized";
241 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
243 VerifyOrExit((rval = client.Execute("state")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
244 networkInfo["NCP:State"] = rval;
246 if (!strcmp(rval, "disabled"))
248 networkInfo["WPAN service"] = "offline";
251 else if (!strcmp(rval, "detached"))
253 networkInfo["WPAN service"] = "associating";
258 networkInfo["WPAN service"] = "associated";
261 VerifyOrExit((rval = client.Execute("version")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
262 networkInfo["NCP:Version"] = rval;
264 VerifyOrExit((rval = client.Execute("eui64")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
265 networkInfo["NCP:HardwareAddress"] = rval;
267 VerifyOrExit((rval = client.Execute("channel")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
268 networkInfo["NCP:Channel"] = rval;
270 VerifyOrExit((rval = client.Execute("state")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
271 networkInfo["Network:NodeType"] = rval;
273 VerifyOrExit((rval = client.Execute("networkname")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
274 networkInfo["Network:Name"] = rval;
276 VerifyOrExit((rval = client.Execute("extpanid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
277 networkInfo["Network:XPANID"] = rval;
279 VerifyOrExit((rval = client.Execute("panid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
280 networkInfo["Network:PANID"] = rval;
283 static const char kMeshLocalPrefixLocator[] = "Mesh Local Prefix: ";
284 static const char kMeshLocalAddressTokenLocator[] = "0:ff:fe00:";
285 std::string meshLocalPrefix;
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';
292 networkInfo["IPv6:MeshLocalPrefix"] = rval;
294 meshLocalPrefix = rval;
295 meshLocalPrefix.resize(meshLocalPrefix.find(":/"));
297 VerifyOrExit((rval = client.Execute("ipaddr")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
299 for (rval = strtok(rval, "\r\n"); rval != nullptr; rval = strtok(nullptr, "\r\n"))
301 char *meshLocalAddressToken = nullptr;
303 if (strstr(rval, meshLocalPrefix.c_str()) != rval)
308 meshLocalAddressToken = strstr(rval, kMeshLocalAddressTokenLocator);
310 if (meshLocalAddressToken == nullptr)
315 // In case this address is not ends with 0:ff:fe00:xxxx
316 if (strchr(meshLocalAddressToken + sizeof(kMeshLocalAddressTokenLocator) - 1, ':') != nullptr)
322 networkInfo["IPv6:MeshLocalAddress"] = rval;
326 root["result"] = networkInfo;
328 if (ret != kWpanStatus_Ok)
330 root["result"] = WPAN_RESPONSE_FAILURE;
331 otbrLog(OTBR_LOG_ERR, "wpan service error: %d", ret);
334 response = jsonWriter.write(root);
338 std::string WpanService::HandleAvailableNetworkRequest()
340 Json::Value root, networks, networkInfo;
341 Json::FastWriter jsonWriter;
342 std::string response;
343 int ret = kWpanStatus_Ok;
344 otbr::Web::OpenThreadClient client;
346 VerifyOrExit(client.Connect(), ret = kWpanStatus_ScanFailed);
347 VerifyOrExit((mNetworksCount = client.Scan(mNetworks, sizeof(mNetworks) / sizeof(mNetworks[0]))) > 0,
348 ret = kWpanStatus_NetworkNotFound);
350 for (int i = 0; i < mNetworksCount; i++)
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;
364 root["result"] = networkInfo;
367 if (ret != kWpanStatus_Ok)
369 root["result"] = WPAN_RESPONSE_FAILURE;
370 otbrLog(OTBR_LOG_ERR, "Error is %d", ret);
373 response = jsonWriter.write(root);
377 int WpanService::GetWpanServiceStatus(std::string &aNetworkName, std::string &aExtPanId) const
379 int status = kWpanStatus_Ok;
380 otbr::Web::OpenThreadClient client;
383 VerifyOrExit(client.Connect(), status = kWpanStatus_Uninitialized);
384 rval = client.Execute("state");
385 VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
386 if (!strcmp(rval, "disabled"))
388 status = kWpanStatus_Offline;
390 else if (!strcmp(rval, "detached"))
392 status = kWpanStatus_Associating;
396 rval = client.Execute("networkname");
397 VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
400 rval = client.Execute("extpanid");
401 VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
410 std::string WpanService::HandleCommission(const std::string &aCommissionRequest)
414 int ret = kWpanStatus_Ok;
416 std::string response;
418 VerifyOrExit(reader.parse(aCommissionRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
419 pskd = root["pskd"].asString();
421 otbr::Web::OpenThreadClient client;
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);
432 if (ret != kWpanStatus_Ok)
434 root["result"] = WPAN_RESPONSE_FAILURE;
435 otbrLog(OTBR_LOG_ERR, "error: %d", ret);
440 int WpanService::commitActiveDataset(otbr::Web::OpenThreadClient &aClient,
441 const std::string & aMasterKey,
442 const std::string & aNetworkName,
447 int ret = kWpanStatus_Ok;
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);
462 std::string WpanService::escapeOtCliEscapable(const std::string &aArg)
464 std::stringbuf strbuf;