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 #define OTBR_LOG_TAG "WEB"
35
36 #include "web/web-service/wpan_service.hpp"
37
38 #include <sstream>
39
40 #include <inttypes.h>
41 #include <stdio.h>
42 #include <unistd.h>
43
44 #include "common/byteswap.hpp"
45 #include "common/code_utils.hpp"
46
47 namespace otbr {
48 namespace Web {
49
50 #define WPAN_RESPONSE_SUCCESS "successful"
51 #define WPAN_RESPONSE_FAILURE "failed"
52 #define CREDENTIAL_TYPE_NETWORK_KEY "networkKeyType"
53 #define CREDENTIAL_TYPE_PSKD "pskdType"
54
HandleGetQRCodeRequest()55 std::string WpanService::HandleGetQRCodeRequest()
56 {
57 Json::Value root, networkInfo;
58 Json::FastWriter jsonWriter;
59 std::string response;
60 int ret = kWpanStatus_Ok;
61 otbr::Web::OpenThreadClient client(mIfName);
62 char * rval;
63
64 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
65
66 // eui64 is the only required information to generate the QR code.
67 VerifyOrExit((rval = client.Execute("eui64")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
68
69 exit:
70
71 root.clear();
72 root["result"] = WPAN_RESPONSE_SUCCESS;
73
74 if (ret == kWpanStatus_Ok)
75 {
76 root["eui64"] = rval;
77 }
78 else
79 {
80 root["result"] = WPAN_RESPONSE_FAILURE;
81 otbrLogErr("Wpan service error: %d", ret);
82 }
83
84 response = jsonWriter.write(root);
85 return response;
86 }
87
HandleJoinNetworkRequest(const std::string & aJoinRequest)88 std::string WpanService::HandleJoinNetworkRequest(const std::string &aJoinRequest)
89 {
90 Json::Value root;
91 Json::Reader reader;
92 Json::FastWriter jsonWriter;
93 std::string response;
94 int index;
95 std::string credentialType;
96 std::string networkKey;
97 std::string pskd;
98 std::string prefix;
99 bool defaultRoute;
100 int ret = kWpanStatus_Ok;
101 otbr::Web::OpenThreadClient client(mIfName);
102 char * rval;
103
104 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
105
106 VerifyOrExit(reader.parse(aJoinRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
107 index = root["index"].asUInt();
108 credentialType = root["credentialType"].asString();
109 networkKey = root["networkKey"].asString();
110 pskd = root["pskd"].asString();
111 prefix = root["prefix"].asString();
112 defaultRoute = root["defaultRoute"].asBool();
113
114 if (prefix.find('/') == std::string::npos)
115 {
116 prefix += "/64";
117 }
118
119 VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed);
120
121 if (credentialType == CREDENTIAL_TYPE_NETWORK_KEY)
122 {
123 VerifyOrExit((ret = joinActiveDataset(client, networkKey, mNetworks[index].mChannel,
124 mNetworks[index].mPanId)) == kWpanStatus_Ok);
125 VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_JoinFailed);
126 }
127 else if (credentialType == CREDENTIAL_TYPE_PSKD)
128 {
129 VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_JoinFailed);
130 VerifyOrExit(client.Execute("joiner start %s", pskd.c_str()) != nullptr, ret = kWpanStatus_JoinFailed);
131 VerifyOrExit((rval = client.Read("Join ", 5000)) != nullptr, ret = kWpanStatus_JoinFailed);
132 if (strstr(rval, "Join success"))
133 {
134 ExitNow();
135 }
136 else if (strstr(rval, "Join failed [NotFound]"))
137 {
138 ExitNow(ret = kWpanStatus_JoinFailed_NotFound);
139 }
140 else if (strstr(rval, "Join failed [Security]"))
141 {
142 ExitNow(ret = kWpanStatus_JoinFailed_Security);
143 }
144 else
145 {
146 ExitNow(ret = kWpanStatus_JoinFailed);
147 }
148 }
149 else
150 {
151 ExitNow(ret = kWpanStatus_JoinFailed);
152 }
153
154 VerifyOrExit(client.Execute("thread start") != nullptr, ret = kWpanStatus_JoinFailed);
155 VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
156 ret = kWpanStatus_SetFailed);
157
158 exit:
159
160 root.clear();
161 root["result"] = WPAN_RESPONSE_SUCCESS;
162
163 root["error"] = ret;
164 if (ret != kWpanStatus_Ok)
165 {
166 otbrLogErr("Wpan service error: %d", ret);
167 root["result"] = WPAN_RESPONSE_FAILURE;
168 }
169
170 root["message"] = "";
171 if (ret == kWpanStatus_JoinFailed_NotFound)
172 {
173 root["message"] = "Please make sure this joiner has been added by an active commissioner.";
174 }
175 else if (ret == kWpanStatus_JoinFailed_Security)
176 {
177 root["message"] = "Please make sure the provided PSKd matches the one given to the commissioner.";
178 }
179
180 response = jsonWriter.write(root);
181 return response;
182 }
183
HandleFormNetworkRequest(const std::string & aFormRequest)184 std::string WpanService::HandleFormNetworkRequest(const std::string &aFormRequest)
185 {
186 Json::Value root;
187 Json::FastWriter jsonWriter;
188 Json::Reader reader;
189 std::string response;
190 otbr::Psk::Pskc psk;
191 char pskcStr[OT_PSKC_MAX_LENGTH * 2 + 1];
192 uint8_t extPanIdBytes[OT_EXTENDED_PANID_LENGTH];
193 std::string networkKey;
194 std::string prefix;
195 uint16_t channel;
196 std::string networkName;
197 std::string passphrase;
198 uint16_t panId;
199 uint64_t extPanId;
200 bool defaultRoute;
201 int ret = kWpanStatus_Ok;
202 otbr::Web::OpenThreadClient client(mIfName);
203
204 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
205
206 pskcStr[OT_PSKC_MAX_LENGTH * 2] = '\0'; // for manipulating with strlen
207 VerifyOrExit(reader.parse(aFormRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
208 networkKey = root["networkKey"].asString();
209 prefix = root["prefix"].asString();
210 channel = root["channel"].asUInt();
211 networkName = root["networkName"].asString();
212 passphrase = root["passphrase"].asString();
213 VerifyOrExit(sscanf(root["panId"].asString().c_str(), "%hx", &panId) == 1, ret = kWpanStatus_ParseRequestFailed);
214 VerifyOrExit(sscanf(root["extPanId"].asString().c_str(), "%" PRIx64, &extPanId) == 1,
215 ret = kWpanStatus_ParseRequestFailed);
216 defaultRoute = root["defaultRoute"].asBool();
217
218 otbr::Utils::Hex2Bytes(root["extPanId"].asString().c_str(), extPanIdBytes, OT_EXTENDED_PANID_LENGTH);
219 otbr::Utils::Bytes2Hex(psk.ComputePskc(extPanIdBytes, networkName.c_str(), passphrase.c_str()), OT_PSKC_MAX_LENGTH,
220 pskcStr);
221
222 if (prefix.find('/') == std::string::npos)
223 {
224 prefix += "/64";
225 }
226
227 VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed);
228 VerifyOrExit((ret = formActiveDataset(client, networkKey, networkName, pskcStr, channel, extPanId, panId)) ==
229 kWpanStatus_Ok);
230 VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_FormFailed);
231 VerifyOrExit(client.Execute("thread start") != nullptr, ret = kWpanStatus_FormFailed);
232 VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
233 ret = kWpanStatus_SetFailed);
234 exit:
235
236 root.clear();
237
238 root["result"] = WPAN_RESPONSE_SUCCESS;
239 root["error"] = ret;
240 if (ret != kWpanStatus_Ok)
241 {
242 otbrLogErr("Wpan service error: %d", ret);
243 root["result"] = WPAN_RESPONSE_FAILURE;
244 }
245 response = jsonWriter.write(root);
246 return response;
247 }
248
HandleAddPrefixRequest(const std::string & aAddPrefixRequest)249 std::string WpanService::HandleAddPrefixRequest(const std::string &aAddPrefixRequest)
250 {
251 Json::Value root;
252 Json::FastWriter jsonWriter;
253 Json::Reader reader;
254 std::string response;
255 std::string prefix;
256 bool defaultRoute;
257 int ret = kWpanStatus_Ok;
258 otbr::Web::OpenThreadClient client(mIfName);
259
260 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
261
262 VerifyOrExit(reader.parse(aAddPrefixRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
263 prefix = root["prefix"].asString();
264 defaultRoute = root["defaultRoute"].asBool();
265
266 if (prefix.find('/') == std::string::npos)
267 {
268 prefix += "/64";
269 }
270
271 VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr,
272 ret = kWpanStatus_SetGatewayFailed);
273 VerifyOrExit(client.Execute("netdata register") != nullptr, ret = kWpanStatus_SetGatewayFailed);
274 exit:
275
276 root.clear();
277
278 root["result"] = WPAN_RESPONSE_SUCCESS;
279 root["error"] = ret;
280 if (ret != kWpanStatus_Ok)
281 {
282 otbrLogErr("Wpan service error: %d", ret);
283 root["result"] = WPAN_RESPONSE_FAILURE;
284 }
285 response = jsonWriter.write(root);
286 return response;
287 }
288
HandleDeletePrefixRequest(const std::string & aDeleteRequest)289 std::string WpanService::HandleDeletePrefixRequest(const std::string &aDeleteRequest)
290 {
291 Json::Value root;
292 Json::FastWriter jsonWriter;
293 Json::Reader reader;
294 std::string response;
295 std::string prefix;
296 int ret = kWpanStatus_Ok;
297 otbr::Web::OpenThreadClient client(mIfName);
298
299 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
300
301 VerifyOrExit(reader.parse(aDeleteRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
302 prefix = root["prefix"].asString();
303
304 if (prefix.find('/') == std::string::npos)
305 {
306 prefix += "/64";
307 }
308
309 VerifyOrExit(client.Execute("prefix remove %s", prefix.c_str()) != nullptr, ret = kWpanStatus_SetGatewayFailed);
310 VerifyOrExit(client.Execute("netdata register") != nullptr, ret = kWpanStatus_SetGatewayFailed);
311 exit:
312
313 root.clear();
314 root["result"] = WPAN_RESPONSE_SUCCESS;
315
316 root["error"] = ret;
317 if (ret != kWpanStatus_Ok)
318 {
319 otbrLogErr("Wpan service error: %d", ret);
320 root["result"] = WPAN_RESPONSE_FAILURE;
321 }
322 response = jsonWriter.write(root);
323 return response;
324 }
325
HandleStatusRequest()326 std::string WpanService::HandleStatusRequest()
327 {
328 Json::Value root, networkInfo;
329 Json::FastWriter jsonWriter;
330 std::string response, networkName, extPanId, propertyValue;
331 int ret = kWpanStatus_Ok;
332 otbr::Web::OpenThreadClient client(mIfName);
333 char * rval;
334
335 networkInfo["WPAN service"] = "uninitialized";
336 VerifyOrExit(client.Connect(), ret = kWpanStatus_SetFailed);
337
338 VerifyOrExit((rval = client.Execute("state")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
339 networkInfo["RCP:State"] = rval;
340
341 if (!strcmp(rval, "disabled"))
342 {
343 networkInfo["WPAN service"] = "offline";
344 ExitNow();
345 }
346 else if (!strcmp(rval, "detached"))
347 {
348 networkInfo["WPAN service"] = "associating";
349 ExitNow();
350 }
351 else
352 {
353 networkInfo["WPAN service"] = "associated";
354 }
355
356 VerifyOrExit((rval = client.Execute("version")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
357 networkInfo["OpenThread:Version"] = rval;
358
359 VerifyOrExit((rval = client.Execute("version api")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
360 networkInfo["OpenThread:Version API"] = rval;
361
362 VerifyOrExit((rval = client.Execute("rcp version")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
363 networkInfo["RCP:Version"] = rval;
364
365 VerifyOrExit((rval = client.Execute("eui64")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
366 networkInfo["RCP:EUI64"] = rval;
367
368 VerifyOrExit((rval = client.Execute("channel")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
369 networkInfo["RCP:Channel"] = rval;
370
371 VerifyOrExit((rval = client.Execute("txpower")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
372 networkInfo["RCP:TxPower"] = rval;
373
374 VerifyOrExit((rval = client.Execute("networkname")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
375 networkInfo["Network:Name"] = rval;
376
377 VerifyOrExit((rval = client.Execute("extpanid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
378 networkInfo["Network:XPANID"] = rval;
379
380 VerifyOrExit((rval = client.Execute("panid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
381 networkInfo["Network:PANID"] = rval;
382
383 VerifyOrExit((rval = client.Execute("partitionid")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
384 networkInfo["Network:PartitionID"] = rval;
385
386 {
387 static const char kMeshLocalPrefixLocator[] = "Mesh Local Prefix: ";
388 static const char kMeshLocalAddressTokenLocator[] = "0:ff:fe00:";
389 static const char localAddressToken[] = "fd";
390 static const char linkLocalAddressToken[] = "fe80";
391 std::string meshLocalPrefix = "";
392
393 VerifyOrExit((rval = client.Execute("dataset active")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
394 rval = strstr(rval, kMeshLocalPrefixLocator);
395 if (rval != nullptr)
396 {
397 rval += sizeof(kMeshLocalPrefixLocator) - 1;
398 *strstr(rval, "\r\n") = '\0';
399 networkInfo["IPv6:MeshLocalPrefix"] = rval;
400
401 meshLocalPrefix = rval;
402 meshLocalPrefix.resize(meshLocalPrefix.find(":/"));
403 }
404
405 VerifyOrExit((rval = client.Execute("ipaddr")) != nullptr, ret = kWpanStatus_GetPropertyFailed);
406
407 for (rval = strtok(rval, "\r\n"); rval != nullptr; rval = strtok(nullptr, "\r\n"))
408 {
409 char *meshLocalAddressToken = nullptr;
410
411 if (strstr(rval, "> ") != nullptr)
412 {
413 rval += 2;
414 }
415
416 if (strstr(rval, linkLocalAddressToken) == rval)
417 {
418 networkInfo["IPv6:LinkLocalAddress"] = rval;
419 continue;
420 }
421
422 meshLocalAddressToken = strstr(rval, kMeshLocalAddressTokenLocator);
423
424 if (meshLocalAddressToken == nullptr)
425 {
426 if ((meshLocalPrefix.size() > 0) && (strstr(rval, meshLocalPrefix.c_str()) == rval))
427 {
428 networkInfo["IPv6:MeshLocalAddress"] = rval;
429 continue;
430 }
431
432 if (strstr(rval, localAddressToken) != rval)
433 {
434 networkInfo["IPv6:GlobalAddress"] = rval;
435 }
436 else
437 {
438 networkInfo["IPv6:LocalAddress"] = rval;
439 }
440 }
441 else
442 {
443 *meshLocalAddressToken = '\0';
444 meshLocalPrefix = rval;
445 networkInfo["IPv6:MeshLocalPrefix"] = rval;
446 std::string la = networkInfo.get("IPv6:LocalAddress", "unknown").asString();
447 if (strstr(rval, la.c_str()) != nullptr)
448 {
449 networkInfo["IPv6:MeshLocalAddress"] = networkInfo.get("IPv6:LocalAddress", "notfound").asString();
450 networkInfo.removeMember("IPv6:LocalAddress");
451 }
452 }
453 }
454 }
455
456 exit:
457 root["result"] = networkInfo;
458
459 if (ret != kWpanStatus_Ok)
460 {
461 root["result"] = WPAN_RESPONSE_FAILURE;
462 otbrLogErr("Wpan service error: %d", ret);
463 }
464 root["error"] = ret;
465 response = jsonWriter.write(root);
466 return response;
467 }
468
HandleAvailableNetworkRequest()469 std::string WpanService::HandleAvailableNetworkRequest()
470 {
471 Json::Value root, networks, networkInfo;
472 Json::FastWriter jsonWriter;
473 std::string response;
474 int ret = kWpanStatus_Ok;
475 otbr::Web::OpenThreadClient client(mIfName);
476
477 VerifyOrExit(client.Connect(), ret = kWpanStatus_ScanFailed);
478 VerifyOrExit((mNetworksCount = client.Scan(mNetworks, sizeof(mNetworks) / sizeof(mNetworks[0]))) > 0,
479 ret = kWpanStatus_NetworkNotFound);
480
481 for (int i = 0; i < mNetworksCount; i++)
482 {
483 char panId[OT_PANID_LENGTH * 2 + 3], hardwareAddress[OT_HARDWARE_ADDRESS_LENGTH * 2 + 1];
484 otbr::Utils::Bytes2Hex(mNetworks[i].mHardwareAddress, OT_HARDWARE_ADDRESS_LENGTH, hardwareAddress);
485 sprintf(panId, "0x%X", mNetworks[i].mPanId);
486 networkInfo[i]["pi"] = panId;
487 networkInfo[i]["ch"] = mNetworks[i].mChannel;
488 networkInfo[i]["ha"] = hardwareAddress;
489 }
490
491 root["result"] = networkInfo;
492
493 exit:
494 if (ret != kWpanStatus_Ok)
495 {
496 root["result"] = WPAN_RESPONSE_FAILURE;
497 otbrLogErr("Error is %d", ret);
498 }
499 root["error"] = ret;
500 response = jsonWriter.write(root);
501 return response;
502 }
503
GetWpanServiceStatus(std::string & aNetworkName,std::string & aExtPanId) const504 int WpanService::GetWpanServiceStatus(std::string &aNetworkName, std::string &aExtPanId) const
505 {
506 int status = kWpanStatus_Ok;
507 otbr::Web::OpenThreadClient client(mIfName);
508 const char * rval;
509
510 VerifyOrExit(client.Connect(), status = kWpanStatus_Uninitialized);
511 rval = client.Execute("state");
512 VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
513 if (!strcmp(rval, "disabled"))
514 {
515 status = kWpanStatus_Offline;
516 }
517 else if (!strcmp(rval, "detached"))
518 {
519 status = kWpanStatus_Associating;
520 }
521 else
522 {
523 rval = client.Execute("networkname");
524 VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
525 aNetworkName = rval;
526
527 rval = client.Execute("extpanid");
528 VerifyOrExit(rval != nullptr, status = kWpanStatus_Down);
529 aExtPanId = rval;
530 }
531
532 exit:
533
534 return status;
535 }
536
HandleCommission(const std::string & aCommissionRequest)537 std::string WpanService::HandleCommission(const std::string &aCommissionRequest)
538 {
539 Json::Value root;
540 Json::Reader reader;
541 Json::FastWriter jsonWriter;
542 int ret = kWpanStatus_Ok;
543 std::string pskd;
544 std::string response;
545 const char * rval;
546
547 VerifyOrExit(reader.parse(aCommissionRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed);
548 pskd = root["pskd"].asString();
549
550 {
551 otbr::Web::OpenThreadClient client(mIfName);
552
553 VerifyOrExit(client.Connect(), ret = kWpanStatus_Uninitialized);
554
555 for (int i = 0; i < 5; i++)
556 {
557 VerifyOrExit((rval = client.Execute("commissioner state")) != nullptr, ret = kWpanStatus_Down);
558
559 if (strcmp(rval, "disabled") == 0)
560 {
561 VerifyOrExit((rval = client.Execute("commissioner start")) != nullptr, ret = kWpanStatus_Down);
562 }
563 else if (strcmp(rval, "active") == 0)
564 {
565 VerifyOrExit(client.Execute("commissioner joiner add * %s", pskd.c_str()) != nullptr,
566 ret = kWpanStatus_Down);
567 root["error"] = ret;
568 ExitNow();
569 }
570
571 sleep(1);
572 }
573
574 client.Execute("commissioner stop");
575 }
576
577 ret = kWpanStatus_SetFailed;
578
579 exit:
580
581 root.clear();
582 root["result"] = WPAN_RESPONSE_SUCCESS;
583 root["error"] = ret;
584
585 if (ret != kWpanStatus_Ok)
586 {
587 root["result"] = WPAN_RESPONSE_FAILURE;
588 otbrLogErr("error: %d", ret);
589 }
590 response = jsonWriter.write(root);
591
592 return response;
593 }
594
joinActiveDataset(otbr::Web::OpenThreadClient & aClient,const std::string & aNetworkKey,uint16_t aChannel,uint16_t aPanId)595 int WpanService::joinActiveDataset(otbr::Web::OpenThreadClient &aClient,
596 const std::string & aNetworkKey,
597 uint16_t aChannel,
598 uint16_t aPanId)
599 {
600 int ret = kWpanStatus_Ok;
601
602 VerifyOrExit(aClient.Execute("dataset clear") != nullptr, ret = kWpanStatus_SetFailed);
603 VerifyOrExit(aClient.Execute("dataset networkkey %s", aNetworkKey.c_str()) != nullptr, ret = kWpanStatus_SetFailed);
604 VerifyOrExit(aClient.Execute("dataset channel %u", aChannel) != nullptr, ret = kWpanStatus_SetFailed);
605 VerifyOrExit(aClient.Execute("dataset panid %u", aPanId) != nullptr, ret = kWpanStatus_SetFailed);
606 VerifyOrExit(aClient.Execute("dataset commit active") != nullptr, ret = kWpanStatus_SetFailed);
607
608 exit:
609 return ret;
610 }
611
formActiveDataset(otbr::Web::OpenThreadClient & aClient,const std::string & aNetworkKey,const std::string & aNetworkName,const std::string & aPskc,uint16_t aChannel,uint64_t aExtPanId,uint16_t aPanId)612 int WpanService::formActiveDataset(otbr::Web::OpenThreadClient &aClient,
613 const std::string & aNetworkKey,
614 const std::string & aNetworkName,
615 const std::string & aPskc,
616 uint16_t aChannel,
617 uint64_t aExtPanId,
618 uint16_t aPanId)
619 {
620 int ret = kWpanStatus_Ok;
621
622 VerifyOrExit(aClient.Execute("dataset init new") != nullptr, ret = kWpanStatus_SetFailed);
623 VerifyOrExit(aClient.Execute("dataset networkkey %s", aNetworkKey.c_str()) != nullptr, ret = kWpanStatus_SetFailed);
624 VerifyOrExit(aClient.Execute("dataset networkname %s", escapeOtCliEscapable(aNetworkName).c_str()) != nullptr,
625 ret = kWpanStatus_SetFailed);
626 VerifyOrExit(aClient.Execute("dataset pskc %s", aPskc.c_str()) != nullptr, ret = kWpanStatus_SetFailed);
627 VerifyOrExit(aClient.Execute("dataset channel %u", aChannel) != nullptr, ret = kWpanStatus_SetFailed);
628 VerifyOrExit(aClient.Execute("dataset extpanid %016" PRIx64, aExtPanId) != nullptr, ret = kWpanStatus_SetFailed);
629 VerifyOrExit(aClient.Execute("dataset panid %u", aPanId) != nullptr, ret = kWpanStatus_SetFailed);
630 VerifyOrExit(aClient.Execute("dataset commit active") != nullptr, ret = kWpanStatus_SetFailed);
631
632 exit:
633 return ret;
634 }
635
escapeOtCliEscapable(const std::string & aArg)636 std::string WpanService::escapeOtCliEscapable(const std::string &aArg)
637 {
638 std::stringbuf strbuf;
639
640 for (char c : aArg)
641 {
642 switch (c)
643 {
644 case ' ':
645 case '\t':
646 case '\r':
647 case '\n':
648 case '\\':
649 strbuf.sputc('\\');
650 // Fallthrough
651 default:
652 strbuf.sputc(c);
653 }
654 }
655
656 return strbuf.str();
657 }
658
659 } // namespace Web
660 } // namespace otbr
661