• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020, 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 "REST"
30 
31 #include "rest/resource.hpp"
32 #include <openthread/commissioner.h>
33 
34 #define OT_PSKC_MAX_LENGTH 16
35 #define OT_EXTENDED_PANID_LENGTH 8
36 
37 #define OT_REST_RESOURCE_PATH_DIAGNOSTICS "/diagnostics"
38 #define OT_REST_RESOURCE_PATH_NODE "/node"
39 #define OT_REST_RESOURCE_PATH_NODE_BAID "/node/ba-id"
40 #define OT_REST_RESOURCE_PATH_NODE_RLOC "/node/rloc"
41 #define OT_REST_RESOURCE_PATH_NODE_RLOC16 "/node/rloc16"
42 #define OT_REST_RESOURCE_PATH_NODE_EXTADDRESS "/node/ext-address"
43 #define OT_REST_RESOURCE_PATH_NODE_STATE "/node/state"
44 #define OT_REST_RESOURCE_PATH_NODE_NETWORKNAME "/node/network-name"
45 #define OT_REST_RESOURCE_PATH_NODE_LEADERDATA "/node/leader-data"
46 #define OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER "/node/num-of-router"
47 #define OT_REST_RESOURCE_PATH_NODE_EXTPANID "/node/ext-panid"
48 #define OT_REST_RESOURCE_PATH_NODE_DATASET_ACTIVE "/node/dataset/active"
49 #define OT_REST_RESOURCE_PATH_NODE_DATASET_PENDING "/node/dataset/pending"
50 #define OT_REST_RESOURCE_PATH_NODE_COMMISSIONER_STATE "/node/commissioner/state"
51 #define OT_REST_RESOURCE_PATH_NODE_COMMISSIONER_JOINER "/node/commissioner/joiner"
52 #define OT_REST_RESOURCE_PATH_NODE_COPROCESSOR "/node/coprocessor"
53 #define OT_REST_RESOURCE_PATH_NODE_COPROCESSOR_VERSION "/node/coprocessor/version"
54 #define OT_REST_RESOURCE_PATH_NETWORK "/networks"
55 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT "/networks/current"
56 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_COMMISSION "/networks/commission"
57 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_PREFIX "/networks/current/prefix"
58 
59 #define OT_REST_HTTP_STATUS_200 "200 OK"
60 #define OT_REST_HTTP_STATUS_201 "201 Created"
61 #define OT_REST_HTTP_STATUS_204 "204 No Content"
62 #define OT_REST_HTTP_STATUS_400 "400 Bad Request"
63 #define OT_REST_HTTP_STATUS_404 "404 Not Found"
64 #define OT_REST_HTTP_STATUS_405 "405 Method Not Allowed"
65 #define OT_REST_HTTP_STATUS_408 "408 Request Timeout"
66 #define OT_REST_HTTP_STATUS_409 "409 Conflict"
67 #define OT_REST_HTTP_STATUS_500 "500 Internal Server Error"
68 #define OT_REST_HTTP_STATUS_507 "507 Insufficient Storage"
69 
70 using std::chrono::duration_cast;
71 using std::chrono::microseconds;
72 using std::chrono::steady_clock;
73 
74 using std::placeholders::_1;
75 using std::placeholders::_2;
76 
77 namespace otbr {
78 namespace rest {
79 
80 // MulticastAddr
81 static const char *kMulticastAddrAllRouters = "ff03::2";
82 
83 // Default TlvTypes for Diagnostic inforamtion
84 static const uint8_t kAllTlvTypes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 19};
85 
86 // Timeout (in Microseconds) for deleting outdated diagnostics
87 static const uint32_t kDiagResetTimeout = 3000000;
88 
89 // Timeout (in Microseconds) for collecting diagnostics
90 static const uint32_t kDiagCollectTimeout = 2000000;
91 
GetHttpStatus(HttpStatusCode aErrorCode)92 static std::string GetHttpStatus(HttpStatusCode aErrorCode)
93 {
94     std::string httpStatus;
95 
96     switch (aErrorCode)
97     {
98     case HttpStatusCode::kStatusOk:
99         httpStatus = OT_REST_HTTP_STATUS_200;
100         break;
101     case HttpStatusCode::kStatusCreated:
102         httpStatus = OT_REST_HTTP_STATUS_201;
103         break;
104     case HttpStatusCode::kStatusNoContent:
105         httpStatus = OT_REST_HTTP_STATUS_204;
106         break;
107     case HttpStatusCode::kStatusBadRequest:
108         httpStatus = OT_REST_HTTP_STATUS_400;
109         break;
110     case HttpStatusCode::kStatusResourceNotFound:
111         httpStatus = OT_REST_HTTP_STATUS_404;
112         break;
113     case HttpStatusCode::kStatusMethodNotAllowed:
114         httpStatus = OT_REST_HTTP_STATUS_405;
115         break;
116     case HttpStatusCode::kStatusRequestTimeout:
117         httpStatus = OT_REST_HTTP_STATUS_408;
118         break;
119     case HttpStatusCode::kStatusConflict:
120         httpStatus = OT_REST_HTTP_STATUS_409;
121         break;
122     case HttpStatusCode::kStatusInternalServerError:
123         httpStatus = OT_REST_HTTP_STATUS_500;
124         break;
125     case HttpStatusCode::kStatusInsufficientStorage:
126         httpStatus = OT_REST_HTTP_STATUS_507;
127         break;
128     }
129 
130     return httpStatus;
131 }
132 
Resource(RcpHost * aHost)133 Resource::Resource(RcpHost *aHost)
134     : mInstance(nullptr)
135     , mHost(aHost)
136 {
137     // Resource Handler
138     mResourceMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOSTICS, &Resource::Diagnostic);
139     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE, &Resource::NodeInfo);
140     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_BAID, &Resource::BaId);
141     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_STATE, &Resource::State);
142     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTADDRESS, &Resource::ExtendedAddr);
143     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NETWORKNAME, &Resource::NetworkName);
144     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC16, &Resource::Rloc16);
145     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_LEADERDATA, &Resource::LeaderData);
146     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER, &Resource::NumOfRoute);
147     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTPANID, &Resource::ExtendedPanId);
148     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC, &Resource::Rloc);
149     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_DATASET_ACTIVE, &Resource::DatasetActive);
150     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_DATASET_PENDING, &Resource::DatasetPending);
151     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_COMMISSIONER_STATE, &Resource::CommissionerState);
152     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_COMMISSIONER_JOINER, &Resource::CommissionerJoiner);
153     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_COPROCESSOR_VERSION, &Resource::CoprocessorVersion);
154 
155     // Resource callback handler
156     mResourceCallbackMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOSTICS, &Resource::HandleDiagnosticCallback);
157 }
158 
Init(void)159 void Resource::Init(void)
160 {
161     mInstance = mHost->GetThreadHelper()->GetInstance();
162 }
163 
Handle(Request & aRequest,Response & aResponse) const164 void Resource::Handle(Request &aRequest, Response &aResponse) const
165 {
166     std::string url = aRequest.GetUrl();
167     auto        it  = mResourceMap.find(url);
168 
169     if (it != mResourceMap.end())
170     {
171         ResourceHandler resourceHandler = it->second;
172         (this->*resourceHandler)(aRequest, aResponse);
173     }
174     else
175     {
176         ErrorHandler(aResponse, HttpStatusCode::kStatusResourceNotFound);
177     }
178 }
179 
HandleCallback(Request & aRequest,Response & aResponse)180 void Resource::HandleCallback(Request &aRequest, Response &aResponse)
181 {
182     std::string url = aRequest.GetUrl();
183     auto        it  = mResourceCallbackMap.find(url);
184 
185     if (it != mResourceCallbackMap.end())
186     {
187         ResourceCallbackHandler resourceHandler = it->second;
188         (this->*resourceHandler)(aRequest, aResponse);
189     }
190 }
191 
HandleDiagnosticCallback(const Request & aRequest,Response & aResponse)192 void Resource::HandleDiagnosticCallback(const Request &aRequest, Response &aResponse)
193 {
194     OT_UNUSED_VARIABLE(aRequest);
195     std::vector<std::vector<otNetworkDiagTlv>> diagContentSet;
196     std::string                                body;
197     std::string                                errorCode;
198 
199     auto duration = duration_cast<microseconds>(steady_clock::now() - aResponse.GetStartTime()).count();
200     if (duration >= kDiagCollectTimeout)
201     {
202         DeleteOutDatedDiagnostic();
203 
204         for (auto it = mDiagSet.begin(); it != mDiagSet.end(); ++it)
205         {
206             diagContentSet.push_back(it->second.mDiagContent);
207         }
208 
209         body      = Json::Diag2JsonString(diagContentSet);
210         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
211         aResponse.SetResponsCode(errorCode);
212         aResponse.SetBody(body);
213         aResponse.SetComplete();
214     }
215 }
216 
ErrorHandler(Response & aResponse,HttpStatusCode aErrorCode) const217 void Resource::ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const
218 {
219     std::string errorMessage = GetHttpStatus(aErrorCode);
220     std::string body         = Json::Error2JsonString(aErrorCode, errorMessage);
221 
222     aResponse.SetResponsCode(errorMessage);
223     aResponse.SetBody(body);
224     aResponse.SetComplete();
225 }
226 
GetNodeInfo(Response & aResponse) const227 void Resource::GetNodeInfo(Response &aResponse) const
228 {
229     otbrError       error = OTBR_ERROR_NONE;
230     struct NodeInfo node  = {};
231     otRouterInfo    routerInfo;
232     uint8_t         maxRouterId;
233     std::string     body;
234     std::string     errorCode;
235 
236     VerifyOrExit(otBorderAgentGetId(mInstance, &node.mBaId) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
237     (void)otThreadGetLeaderData(mInstance, &node.mLeaderData);
238 
239     node.mNumOfRouter = 0;
240     maxRouterId       = otThreadGetMaxRouterId(mInstance);
241     for (uint8_t i = 0; i <= maxRouterId; ++i)
242     {
243         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
244         {
245             continue;
246         }
247         ++node.mNumOfRouter;
248     }
249 
250     node.mRole        = GetDeviceRoleName(otThreadGetDeviceRole(mInstance));
251     node.mExtAddress  = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
252     node.mNetworkName = otThreadGetNetworkName(mInstance);
253     node.mRloc16      = otThreadGetRloc16(mInstance);
254     node.mExtPanId    = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
255     node.mRlocAddress = *otThreadGetRloc(mInstance);
256 
257     body = Json::Node2JsonString(node);
258     aResponse.SetBody(body);
259 
260 exit:
261     if (error == OTBR_ERROR_NONE)
262     {
263         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
264         aResponse.SetResponsCode(errorCode);
265     }
266     else
267     {
268         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
269     }
270 }
271 
DeleteNodeInfo(Response & aResponse) const272 void Resource::DeleteNodeInfo(Response &aResponse) const
273 {
274     otbrError   error = OTBR_ERROR_NONE;
275     std::string errorCode;
276 
277     VerifyOrExit(mHost->GetThreadHelper()->Detach() == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
278     VerifyOrExit(otInstanceErasePersistentInfo(mInstance) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
279     mHost->Reset();
280 
281 exit:
282     if (error == OTBR_ERROR_NONE)
283     {
284         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
285         aResponse.SetResponsCode(errorCode);
286     }
287     else if (error == OTBR_ERROR_INVALID_STATE)
288     {
289         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
290     }
291     else if (error != OTBR_ERROR_NONE)
292     {
293         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
294     }
295 }
296 
NodeInfo(const Request & aRequest,Response & aResponse) const297 void Resource::NodeInfo(const Request &aRequest, Response &aResponse) const
298 {
299     std::string errorCode;
300 
301     switch (aRequest.GetMethod())
302     {
303     case HttpMethod::kGet:
304         GetNodeInfo(aResponse);
305         break;
306     case HttpMethod::kDelete:
307         DeleteNodeInfo(aResponse);
308         break;
309     default:
310         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
311         break;
312     }
313 }
314 
GetDataBaId(Response & aResponse) const315 void Resource::GetDataBaId(Response &aResponse) const
316 {
317     otbrError       error = OTBR_ERROR_NONE;
318     otBorderAgentId id;
319     std::string     body;
320     std::string     errorCode;
321 
322     VerifyOrExit(otBorderAgentGetId(mInstance, &id) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
323 
324     body = Json::Bytes2HexJsonString(id.mId, sizeof(id));
325     aResponse.SetBody(body);
326 
327 exit:
328     if (error == OTBR_ERROR_NONE)
329     {
330         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
331         aResponse.SetResponsCode(errorCode);
332     }
333     else
334     {
335         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
336     }
337 }
338 
BaId(const Request & aRequest,Response & aResponse) const339 void Resource::BaId(const Request &aRequest, Response &aResponse) const
340 {
341     std::string errorCode;
342 
343     if (aRequest.GetMethod() == HttpMethod::kGet)
344     {
345         GetDataBaId(aResponse);
346     }
347     else
348     {
349         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
350     }
351 }
352 
GetDataExtendedAddr(Response & aResponse) const353 void Resource::GetDataExtendedAddr(Response &aResponse) const
354 {
355     const uint8_t *extAddress = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
356     std::string    errorCode;
357     std::string    body = Json::Bytes2HexJsonString(extAddress, OT_EXT_ADDRESS_SIZE);
358 
359     aResponse.SetBody(body);
360     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
361     aResponse.SetResponsCode(errorCode);
362 }
363 
ExtendedAddr(const Request & aRequest,Response & aResponse) const364 void Resource::ExtendedAddr(const Request &aRequest, Response &aResponse) const
365 {
366     std::string errorCode;
367 
368     if (aRequest.GetMethod() == HttpMethod::kGet)
369     {
370         GetDataExtendedAddr(aResponse);
371     }
372     else
373     {
374         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
375     }
376 }
377 
GetDataState(Response & aResponse) const378 void Resource::GetDataState(Response &aResponse) const
379 {
380     std::string  state;
381     std::string  errorCode;
382     otDeviceRole role;
383 
384     role  = otThreadGetDeviceRole(mInstance);
385     state = Json::String2JsonString(GetDeviceRoleName(role));
386     aResponse.SetBody(state);
387     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
388     aResponse.SetResponsCode(errorCode);
389 }
390 
SetDataState(const Request & aRequest,Response & aResponse) const391 void Resource::SetDataState(const Request &aRequest, Response &aResponse) const
392 {
393     otbrError   error = OTBR_ERROR_NONE;
394     std::string errorCode;
395     std::string body;
396 
397     VerifyOrExit(Json::JsonString2String(aRequest.GetBody(), body), error = OTBR_ERROR_INVALID_ARGS);
398     if (body == "enable")
399     {
400         if (!otIp6IsEnabled(mInstance))
401         {
402             VerifyOrExit(otIp6SetEnabled(mInstance, true) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
403         }
404         VerifyOrExit(otThreadSetEnabled(mInstance, true) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
405     }
406     else if (body == "disable")
407     {
408         VerifyOrExit(otThreadSetEnabled(mInstance, false) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
409         VerifyOrExit(otIp6SetEnabled(mInstance, false) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
410     }
411     else
412     {
413         ExitNow(error = OTBR_ERROR_INVALID_ARGS);
414     }
415 
416     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
417     aResponse.SetResponsCode(errorCode);
418 
419 exit:
420     if (error == OTBR_ERROR_INVALID_STATE)
421     {
422         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
423     }
424     if (error == OTBR_ERROR_INVALID_ARGS)
425     {
426         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
427     }
428     else if (error != OTBR_ERROR_NONE)
429     {
430         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
431     }
432 }
433 
State(const Request & aRequest,Response & aResponse) const434 void Resource::State(const Request &aRequest, Response &aResponse) const
435 {
436     std::string errorCode;
437 
438     switch (aRequest.GetMethod())
439     {
440     case HttpMethod::kGet:
441         GetDataState(aResponse);
442         break;
443     case HttpMethod::kPut:
444         SetDataState(aRequest, aResponse);
445         break;
446     case HttpMethod::kOptions:
447         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
448         aResponse.SetResponsCode(errorCode);
449         aResponse.SetComplete();
450         break;
451     default:
452         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
453         break;
454     }
455 }
456 
GetDataNetworkName(Response & aResponse) const457 void Resource::GetDataNetworkName(Response &aResponse) const
458 {
459     std::string networkName;
460     std::string errorCode;
461 
462     networkName = otThreadGetNetworkName(mInstance);
463     networkName = Json::String2JsonString(networkName);
464 
465     aResponse.SetBody(networkName);
466     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
467     aResponse.SetResponsCode(errorCode);
468 }
469 
NetworkName(const Request & aRequest,Response & aResponse) const470 void Resource::NetworkName(const Request &aRequest, Response &aResponse) const
471 {
472     std::string errorCode;
473 
474     if (aRequest.GetMethod() == HttpMethod::kGet)
475     {
476         GetDataNetworkName(aResponse);
477     }
478     else
479     {
480         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
481     }
482 }
483 
GetDataLeaderData(Response & aResponse) const484 void Resource::GetDataLeaderData(Response &aResponse) const
485 {
486     otbrError    error = OTBR_ERROR_NONE;
487     otLeaderData leaderData;
488     std::string  body;
489     std::string  errorCode;
490 
491     VerifyOrExit(otThreadGetLeaderData(mInstance, &leaderData) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
492 
493     body = Json::LeaderData2JsonString(leaderData);
494 
495     aResponse.SetBody(body);
496 
497 exit:
498     if (error == OTBR_ERROR_NONE)
499     {
500         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
501         aResponse.SetResponsCode(errorCode);
502     }
503     else
504     {
505         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
506     }
507 }
508 
LeaderData(const Request & aRequest,Response & aResponse) const509 void Resource::LeaderData(const Request &aRequest, Response &aResponse) const
510 {
511     std::string errorCode;
512     if (aRequest.GetMethod() == HttpMethod::kGet)
513     {
514         GetDataLeaderData(aResponse);
515     }
516     else
517     {
518         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
519     }
520 }
521 
GetDataNumOfRoute(Response & aResponse) const522 void Resource::GetDataNumOfRoute(Response &aResponse) const
523 {
524     uint8_t      count = 0;
525     uint8_t      maxRouterId;
526     otRouterInfo routerInfo;
527     maxRouterId = otThreadGetMaxRouterId(mInstance);
528     std::string body;
529     std::string errorCode;
530 
531     for (uint8_t i = 0; i <= maxRouterId; ++i)
532     {
533         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
534         {
535             continue;
536         }
537         ++count;
538     }
539 
540     body = Json::Number2JsonString(count);
541 
542     aResponse.SetBody(body);
543     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
544     aResponse.SetResponsCode(errorCode);
545 }
546 
NumOfRoute(const Request & aRequest,Response & aResponse) const547 void Resource::NumOfRoute(const Request &aRequest, Response &aResponse) const
548 {
549     std::string errorCode;
550 
551     if (aRequest.GetMethod() == HttpMethod::kGet)
552     {
553         GetDataNumOfRoute(aResponse);
554     }
555     else
556     {
557         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
558     }
559 }
560 
GetDataRloc16(Response & aResponse) const561 void Resource::GetDataRloc16(Response &aResponse) const
562 {
563     uint16_t    rloc16 = otThreadGetRloc16(mInstance);
564     std::string body;
565     std::string errorCode;
566 
567     body = Json::Number2JsonString(rloc16);
568 
569     aResponse.SetBody(body);
570     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
571     aResponse.SetResponsCode(errorCode);
572 }
573 
Rloc16(const Request & aRequest,Response & aResponse) const574 void Resource::Rloc16(const Request &aRequest, Response &aResponse) const
575 {
576     std::string errorCode;
577 
578     if (aRequest.GetMethod() == HttpMethod::kGet)
579     {
580         GetDataRloc16(aResponse);
581     }
582     else
583     {
584         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
585     }
586 }
587 
GetDataExtendedPanId(Response & aResponse) const588 void Resource::GetDataExtendedPanId(Response &aResponse) const
589 {
590     const uint8_t *extPanId = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
591     std::string    body     = Json::Bytes2HexJsonString(extPanId, OT_EXT_PAN_ID_SIZE);
592     std::string    errorCode;
593 
594     aResponse.SetBody(body);
595     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
596     aResponse.SetResponsCode(errorCode);
597 }
598 
ExtendedPanId(const Request & aRequest,Response & aResponse) const599 void Resource::ExtendedPanId(const Request &aRequest, Response &aResponse) const
600 {
601     std::string errorCode;
602 
603     if (aRequest.GetMethod() == HttpMethod::kGet)
604     {
605         GetDataExtendedPanId(aResponse);
606     }
607     else
608     {
609         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
610     }
611 }
612 
GetDataRloc(Response & aResponse) const613 void Resource::GetDataRloc(Response &aResponse) const
614 {
615     otIp6Address rlocAddress = *otThreadGetRloc(mInstance);
616     std::string  body;
617     std::string  errorCode;
618 
619     body = Json::IpAddr2JsonString(rlocAddress);
620 
621     aResponse.SetBody(body);
622     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
623     aResponse.SetResponsCode(errorCode);
624 }
625 
Rloc(const Request & aRequest,Response & aResponse) const626 void Resource::Rloc(const Request &aRequest, Response &aResponse) const
627 {
628     std::string errorCode;
629 
630     if (aRequest.GetMethod() == HttpMethod::kGet)
631     {
632         GetDataRloc(aResponse);
633     }
634     else
635     {
636         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
637     }
638 }
639 
GetDataset(DatasetType aDatasetType,const Request & aRequest,Response & aResponse) const640 void Resource::GetDataset(DatasetType aDatasetType, const Request &aRequest, Response &aResponse) const
641 {
642     otbrError                error = OTBR_ERROR_NONE;
643     struct NodeInfo          node;
644     std::string              body;
645     std::string              errorCode;
646     otOperationalDataset     dataset;
647     otOperationalDatasetTlvs datasetTlvs;
648 
649     if (aRequest.GetHeaderValue(OT_REST_ACCEPT_HEADER) == OT_REST_CONTENT_TYPE_PLAIN)
650     {
651         if (aDatasetType == DatasetType::kActive)
652         {
653             VerifyOrExit(otDatasetGetActiveTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE,
654                          error = OTBR_ERROR_NOT_FOUND);
655         }
656         else if (aDatasetType == DatasetType::kPending)
657         {
658             VerifyOrExit(otDatasetGetPendingTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE,
659                          error = OTBR_ERROR_NOT_FOUND);
660         }
661 
662         aResponse.SetContentType(OT_REST_CONTENT_TYPE_PLAIN);
663         body = Utils::Bytes2Hex(datasetTlvs.mTlvs, datasetTlvs.mLength);
664     }
665     else
666     {
667         if (aDatasetType == DatasetType::kActive)
668         {
669             VerifyOrExit(otDatasetGetActive(mInstance, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_NOT_FOUND);
670             body = Json::ActiveDataset2JsonString(dataset);
671         }
672         else if (aDatasetType == DatasetType::kPending)
673         {
674             VerifyOrExit(otDatasetGetPending(mInstance, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_NOT_FOUND);
675             body = Json::PendingDataset2JsonString(dataset);
676         }
677     }
678 
679     aResponse.SetBody(body);
680 
681 exit:
682     if (error == OTBR_ERROR_NONE)
683     {
684         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
685         aResponse.SetResponsCode(errorCode);
686     }
687     else if (error == OTBR_ERROR_NOT_FOUND)
688     {
689         errorCode = GetHttpStatus(HttpStatusCode::kStatusNoContent);
690         aResponse.SetResponsCode(errorCode);
691     }
692     else
693     {
694         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
695     }
696 }
697 
SetDataset(DatasetType aDatasetType,const Request & aRequest,Response & aResponse) const698 void Resource::SetDataset(DatasetType aDatasetType, const Request &aRequest, Response &aResponse) const
699 {
700     otError                  errorOt = OT_ERROR_NONE;
701     otbrError                error   = OTBR_ERROR_NONE;
702     struct NodeInfo          node;
703     std::string              body;
704     std::string              errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
705     otOperationalDataset     dataset   = {};
706     otOperationalDatasetTlvs datasetTlvs;
707     otOperationalDatasetTlvs datasetUpdateTlvs;
708     int                      ret;
709     bool                     isTlv;
710 
711     if (aDatasetType == DatasetType::kActive)
712     {
713         VerifyOrExit(otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED, error = OTBR_ERROR_INVALID_STATE);
714         errorOt = otDatasetGetActiveTlvs(mInstance, &datasetTlvs);
715     }
716     else if (aDatasetType == DatasetType::kPending)
717     {
718         errorOt = otDatasetGetPendingTlvs(mInstance, &datasetTlvs);
719     }
720 
721     // Create a new operational dataset if it doesn't exist.
722     if (errorOt == OT_ERROR_NOT_FOUND)
723     {
724         VerifyOrExit(otDatasetCreateNewNetwork(mInstance, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
725         otDatasetConvertToTlvs(&dataset, &datasetTlvs);
726         errorCode = GetHttpStatus(HttpStatusCode::kStatusCreated);
727     }
728 
729     isTlv = aRequest.GetHeaderValue(OT_REST_CONTENT_TYPE_HEADER) == OT_REST_CONTENT_TYPE_PLAIN;
730 
731     if (isTlv)
732     {
733         ret = Json::Hex2BytesJsonString(aRequest.GetBody(), datasetUpdateTlvs.mTlvs, OT_OPERATIONAL_DATASET_MAX_LENGTH);
734         VerifyOrExit(ret >= 0, error = OTBR_ERROR_INVALID_ARGS);
735         datasetUpdateTlvs.mLength = ret;
736 
737         VerifyOrExit(otDatasetParseTlvs(&datasetUpdateTlvs, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
738         VerifyOrExit(otDatasetUpdateTlvs(&dataset, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
739     }
740     else
741     {
742         if (aDatasetType == DatasetType::kActive)
743         {
744             VerifyOrExit(Json::JsonActiveDatasetString2Dataset(aRequest.GetBody(), dataset),
745                          error = OTBR_ERROR_INVALID_ARGS);
746         }
747         else if (aDatasetType == DatasetType::kPending)
748         {
749             VerifyOrExit(Json::JsonPendingDatasetString2Dataset(aRequest.GetBody(), dataset),
750                          error = OTBR_ERROR_INVALID_ARGS);
751             VerifyOrExit(dataset.mComponents.mIsDelayPresent, error = OTBR_ERROR_INVALID_ARGS);
752         }
753         VerifyOrExit(otDatasetUpdateTlvs(&dataset, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
754     }
755 
756     if (aDatasetType == DatasetType::kActive)
757     {
758         VerifyOrExit(otDatasetSetActiveTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
759     }
760     else if (aDatasetType == DatasetType::kPending)
761     {
762         VerifyOrExit(otDatasetSetPendingTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
763     }
764 
765     aResponse.SetResponsCode(errorCode);
766 
767 exit:
768     if (error == OTBR_ERROR_INVALID_ARGS)
769     {
770         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
771     }
772     else if (error == OTBR_ERROR_INVALID_STATE)
773     {
774         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
775     }
776     else if (error != OTBR_ERROR_NONE)
777     {
778         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
779     }
780 }
781 
Dataset(DatasetType aDatasetType,const Request & aRequest,Response & aResponse) const782 void Resource::Dataset(DatasetType aDatasetType, const Request &aRequest, Response &aResponse) const
783 {
784     std::string errorCode;
785 
786     switch (aRequest.GetMethod())
787     {
788     case HttpMethod::kGet:
789         GetDataset(aDatasetType, aRequest, aResponse);
790         break;
791     case HttpMethod::kPut:
792         SetDataset(aDatasetType, aRequest, aResponse);
793         break;
794     case HttpMethod::kOptions:
795         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
796         aResponse.SetResponsCode(errorCode);
797         aResponse.SetComplete();
798         break;
799     default:
800         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
801         break;
802     }
803 }
804 
DatasetActive(const Request & aRequest,Response & aResponse) const805 void Resource::DatasetActive(const Request &aRequest, Response &aResponse) const
806 {
807     Dataset(DatasetType::kActive, aRequest, aResponse);
808 }
809 
DatasetPending(const Request & aRequest,Response & aResponse) const810 void Resource::DatasetPending(const Request &aRequest, Response &aResponse) const
811 {
812     Dataset(DatasetType::kPending, aRequest, aResponse);
813 }
814 
GetCommissionerState(Response & aResponse) const815 void Resource::GetCommissionerState(Response &aResponse) const
816 {
817     std::string         state;
818     std::string         errorCode;
819     otCommissionerState stateCode;
820 
821     stateCode = otCommissionerGetState(mInstance);
822     state     = Json::String2JsonString(GetCommissionerStateName(stateCode));
823     aResponse.SetBody(state);
824     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
825     aResponse.SetResponsCode(errorCode);
826 }
827 
SetCommissionerState(const Request & aRequest,Response & aResponse) const828 void Resource::SetCommissionerState(const Request &aRequest, Response &aResponse) const
829 {
830     otbrError   error = OTBR_ERROR_NONE;
831     std::string errorCode;
832     std::string body;
833 
834     VerifyOrExit(Json::JsonString2String(aRequest.GetBody(), body), error = OTBR_ERROR_INVALID_ARGS);
835     if (body == "enable")
836     {
837         VerifyOrExit(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_DISABLED, error = OTBR_ERROR_NONE);
838         VerifyOrExit(otCommissionerStart(mInstance, NULL, NULL, NULL) == OT_ERROR_NONE,
839                      error = OTBR_ERROR_INVALID_STATE);
840     }
841     else if (body == "disable")
842     {
843         VerifyOrExit(otCommissionerGetState(mInstance) != OT_COMMISSIONER_STATE_DISABLED, error = OTBR_ERROR_NONE);
844         VerifyOrExit(otCommissionerStop(mInstance) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
845     }
846     else
847     {
848         ExitNow(error = OTBR_ERROR_INVALID_ARGS);
849     }
850 
851 exit:
852     switch (error)
853     {
854     case OTBR_ERROR_NONE:
855         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
856         aResponse.SetResponsCode(errorCode);
857         break;
858     case OTBR_ERROR_INVALID_STATE:
859         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
860         break;
861     case OTBR_ERROR_INVALID_ARGS:
862         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
863         break;
864     default:
865         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
866         break;
867     }
868 }
869 
CommissionerState(const Request & aRequest,Response & aResponse) const870 void Resource::CommissionerState(const Request &aRequest, Response &aResponse) const
871 {
872     std::string errorCode;
873 
874     switch (aRequest.GetMethod())
875     {
876     case HttpMethod::kGet:
877         GetCommissionerState(aResponse);
878         break;
879     case HttpMethod::kPut:
880         SetCommissionerState(aRequest, aResponse);
881         break;
882     case HttpMethod::kOptions:
883         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
884         aResponse.SetResponsCode(errorCode);
885         aResponse.SetComplete();
886         break;
887     default:
888         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
889         break;
890     }
891 }
892 
GetJoiners(Response & aResponse) const893 void Resource::GetJoiners(Response &aResponse) const
894 {
895     uint16_t                  iter = 0;
896     otJoinerInfo              joinerInfo;
897     std::vector<otJoinerInfo> joinerTable;
898     std::string               joinerJson;
899     std::string               errorCode;
900 
901     while (otCommissionerGetNextJoinerInfo(mInstance, &iter, &joinerInfo) == OT_ERROR_NONE)
902     {
903         joinerTable.push_back(joinerInfo);
904     }
905 
906     joinerJson = Json::JoinerTable2JsonString(joinerTable);
907     aResponse.SetBody(joinerJson);
908     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
909     aResponse.SetResponsCode(errorCode);
910 }
911 
AddJoiner(const Request & aRequest,Response & aResponse) const912 void Resource::AddJoiner(const Request &aRequest, Response &aResponse) const
913 {
914     otbrError           error   = OTBR_ERROR_NONE;
915     otError             errorOt = OT_ERROR_NONE;
916     std::string         errorCode;
917     otJoinerInfo        joiner;
918     const otExtAddress *addrPtr                         = nullptr;
919     const uint8_t       emptyArray[OT_EXT_ADDRESS_SIZE] = {0};
920 
921     VerifyOrExit(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE, error = OTBR_ERROR_INVALID_STATE);
922 
923     VerifyOrExit(Json::JsonJoinerInfoString2JoinerInfo(aRequest.GetBody(), joiner), error = OTBR_ERROR_INVALID_ARGS);
924 
925     addrPtr = &joiner.mSharedId.mEui64;
926     if (memcmp(&joiner.mSharedId.mEui64, emptyArray, OT_EXT_ADDRESS_SIZE) == 0)
927     {
928         addrPtr = nullptr;
929     }
930 
931     if (joiner.mType == OT_JOINER_INFO_TYPE_DISCERNER)
932     {
933         errorOt = otCommissionerAddJoinerWithDiscerner(mInstance, &joiner.mSharedId.mDiscerner, joiner.mPskd.m8,
934                                                        joiner.mExpirationTime);
935     }
936     else
937     {
938         errorOt = otCommissionerAddJoiner(mInstance, addrPtr, joiner.mPskd.m8, joiner.mExpirationTime);
939     }
940     VerifyOrExit(errorOt == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
941 
942 exit:
943     switch (error)
944     {
945     case OTBR_ERROR_NONE:
946         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
947         aResponse.SetResponsCode(errorCode);
948         break;
949     case OTBR_ERROR_INVALID_STATE:
950         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
951         break;
952     case OTBR_ERROR_INVALID_ARGS:
953         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
954         break;
955     case OTBR_ERROR_OPENTHREAD:
956         switch (errorOt)
957         {
958         case OT_ERROR_INVALID_ARGS:
959             ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
960             break;
961         case OT_ERROR_NO_BUFS:
962             ErrorHandler(aResponse, HttpStatusCode::kStatusInsufficientStorage);
963             break;
964         default:
965             ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
966             break;
967         }
968         break;
969     default:
970         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
971         break;
972     }
973 }
974 
RemoveJoiner(const Request & aRequest,Response & aResponse) const975 void Resource::RemoveJoiner(const Request &aRequest, Response &aResponse) const
976 {
977     otbrError         error = OTBR_ERROR_NONE;
978     std::string       errorCode;
979     otExtAddress      eui64;
980     otExtAddress     *addrPtr   = nullptr;
981     otJoinerDiscerner discerner = {
982         .mValue  = 0,
983         .mLength = 0,
984     };
985     std::string body;
986 
987     VerifyOrExit(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE, error = OTBR_ERROR_INVALID_STATE);
988 
989     VerifyOrExit(Json::JsonString2String(aRequest.GetBody(), body), error = OTBR_ERROR_INVALID_ARGS);
990     if (body != "*")
991     {
992         error = Json::StringDiscerner2Discerner(const_cast<char *>(body.c_str()), discerner);
993         if (error == OTBR_ERROR_NOT_FOUND)
994         {
995             error = OTBR_ERROR_NONE;
996             VerifyOrExit(Json::Hex2BytesJsonString(body, eui64.m8, OT_EXT_ADDRESS_SIZE) == OT_EXT_ADDRESS_SIZE,
997                          error = OTBR_ERROR_INVALID_ARGS);
998             addrPtr = &eui64;
999         }
1000         else if (error != OTBR_ERROR_NONE)
1001         {
1002             ExitNow(error = OTBR_ERROR_INVALID_ARGS);
1003         }
1004     }
1005 
1006     // These functions should only return OT_ERROR_NONE or OT_ERROR_NOT_FOUND both treated as successful
1007     if (discerner.mLength == 0)
1008     {
1009         (void)otCommissionerRemoveJoiner(mInstance, addrPtr);
1010     }
1011     else
1012     {
1013         (void)otCommissionerRemoveJoinerWithDiscerner(mInstance, &discerner);
1014     }
1015 
1016 exit:
1017     switch (error)
1018     {
1019     case OTBR_ERROR_NONE:
1020         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
1021         aResponse.SetResponsCode(errorCode);
1022         break;
1023     case OTBR_ERROR_INVALID_STATE:
1024         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
1025         break;
1026     case OTBR_ERROR_INVALID_ARGS:
1027         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
1028         break;
1029     default:
1030         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
1031         break;
1032     }
1033 }
1034 
CommissionerJoiner(const Request & aRequest,Response & aResponse) const1035 void Resource::CommissionerJoiner(const Request &aRequest, Response &aResponse) const
1036 {
1037     std::string errorCode;
1038 
1039     switch (aRequest.GetMethod())
1040     {
1041     case HttpMethod::kGet:
1042         GetJoiners(aResponse);
1043         break;
1044     case HttpMethod::kPost:
1045         AddJoiner(aRequest, aResponse);
1046         break;
1047     case HttpMethod::kDelete:
1048         RemoveJoiner(aRequest, aResponse);
1049         break;
1050 
1051     case HttpMethod::kOptions:
1052         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
1053         aResponse.SetResponsCode(errorCode);
1054         aResponse.SetComplete();
1055         break;
1056     default:
1057         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
1058         break;
1059     }
1060 }
1061 
GetCoprocessorVersion(Response & aResponse) const1062 void Resource::GetCoprocessorVersion(Response &aResponse) const
1063 {
1064     std::string coprocessorVersion;
1065     std::string errorCode;
1066 
1067     coprocessorVersion = mHost->GetCoprocessorVersion();
1068     coprocessorVersion = Json::String2JsonString(coprocessorVersion);
1069 
1070     aResponse.SetBody(coprocessorVersion);
1071     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
1072     aResponse.SetResponsCode(errorCode);
1073 }
1074 
CoprocessorVersion(const Request & aRequest,Response & aResponse) const1075 void Resource::CoprocessorVersion(const Request &aRequest, Response &aResponse) const
1076 {
1077     std::string errorCode;
1078 
1079     if (aRequest.GetMethod() == HttpMethod::kGet)
1080     {
1081         GetCoprocessorVersion(aResponse);
1082     }
1083     else
1084     {
1085         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
1086     }
1087 }
1088 
DeleteOutDatedDiagnostic(void)1089 void Resource::DeleteOutDatedDiagnostic(void)
1090 {
1091     auto eraseIt = mDiagSet.begin();
1092     for (eraseIt = mDiagSet.begin(); eraseIt != mDiagSet.end();)
1093     {
1094         auto diagInfo = eraseIt->second;
1095         auto duration = duration_cast<microseconds>(steady_clock::now() - diagInfo.mStartTime).count();
1096 
1097         if (duration >= kDiagResetTimeout)
1098         {
1099             eraseIt = mDiagSet.erase(eraseIt);
1100         }
1101         else
1102         {
1103             eraseIt++;
1104         }
1105     }
1106 }
1107 
UpdateDiag(std::string aKey,std::vector<otNetworkDiagTlv> & aDiag)1108 void Resource::UpdateDiag(std::string aKey, std::vector<otNetworkDiagTlv> &aDiag)
1109 {
1110     DiagInfo value;
1111 
1112     value.mStartTime = steady_clock::now();
1113     value.mDiagContent.assign(aDiag.begin(), aDiag.end());
1114     mDiagSet[aKey] = value;
1115 }
1116 
Diagnostic(const Request & aRequest,Response & aResponse) const1117 void Resource::Diagnostic(const Request &aRequest, Response &aResponse) const
1118 {
1119     otbrError error = OTBR_ERROR_NONE;
1120     OT_UNUSED_VARIABLE(aRequest);
1121     struct otIp6Address rloc16address = *otThreadGetRloc(mInstance);
1122     struct otIp6Address multicastAddress;
1123 
1124     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &rloc16address, kAllTlvTypes, sizeof(kAllTlvTypes),
1125                                            &Resource::DiagnosticResponseHandler,
1126                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
1127                  error = OTBR_ERROR_REST);
1128     VerifyOrExit(otIp6AddressFromString(kMulticastAddrAllRouters, &multicastAddress) == OT_ERROR_NONE,
1129                  error = OTBR_ERROR_REST);
1130     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &multicastAddress, kAllTlvTypes, sizeof(kAllTlvTypes),
1131                                            &Resource::DiagnosticResponseHandler,
1132                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
1133                  error = OTBR_ERROR_REST);
1134 
1135 exit:
1136 
1137     if (error == OTBR_ERROR_NONE)
1138     {
1139         aResponse.SetStartTime(steady_clock::now());
1140         aResponse.SetCallback();
1141     }
1142     else
1143     {
1144         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
1145     }
1146 }
1147 
DiagnosticResponseHandler(otError aError,otMessage * aMessage,const otMessageInfo * aMessageInfo,void * aContext)1148 void Resource::DiagnosticResponseHandler(otError              aError,
1149                                          otMessage           *aMessage,
1150                                          const otMessageInfo *aMessageInfo,
1151                                          void                *aContext)
1152 {
1153     static_cast<Resource *>(aContext)->DiagnosticResponseHandler(aError, aMessage, aMessageInfo);
1154 }
1155 
DiagnosticResponseHandler(otError aError,const otMessage * aMessage,const otMessageInfo * aMessageInfo)1156 void Resource::DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo)
1157 {
1158     std::vector<otNetworkDiagTlv> diagSet;
1159     otNetworkDiagTlv              diagTlv;
1160     otNetworkDiagIterator         iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT;
1161     otError                       error;
1162     char                          rloc[7];
1163     std::string                   keyRloc = "0xffee";
1164 
1165     SuccessOrExit(aError);
1166 
1167     OTBR_UNUSED_VARIABLE(aMessageInfo);
1168 
1169     while ((error = otThreadGetNextDiagnosticTlv(aMessage, &iterator, &diagTlv)) == OT_ERROR_NONE)
1170     {
1171         if (diagTlv.mType == OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS)
1172         {
1173             snprintf(rloc, sizeof(rloc), "0x%04x", diagTlv.mData.mAddr16);
1174             keyRloc = Json::CString2JsonString(rloc);
1175         }
1176         diagSet.push_back(diagTlv);
1177     }
1178     UpdateDiag(keyRloc, diagSet);
1179 
1180 exit:
1181     if (aError != OT_ERROR_NONE)
1182     {
1183         otbrLogWarning("Failed to get diagnostic data: %s", otThreadErrorToString(aError));
1184     }
1185 }
1186 
1187 } // namespace rest
1188 } // namespace otbr
1189