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