• 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 
33 #include "string.h"
34 
35 #define OT_PSKC_MAX_LENGTH 16
36 #define OT_EXTENDED_PANID_LENGTH 8
37 
38 #define OT_REST_RESOURCE_PATH_DIAGNOETIC "/diagnostics"
39 #define OT_REST_RESOURCE_PATH_NODE "/node"
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_NETWORK "/networks"
49 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT "/networks/current"
50 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_COMMISSION "/networks/commission"
51 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_PREFIX "/networks/current/prefix"
52 
53 #define OT_REST_HTTP_STATUS_200 "200 OK"
54 #define OT_REST_HTTP_STATUS_404 "404 Not Found"
55 #define OT_REST_HTTP_STATUS_405 "405 Method Not Allowed"
56 #define OT_REST_HTTP_STATUS_408 "408 Request Timeout"
57 #define OT_REST_HTTP_STATUS_500 "500 Internal Server Error"
58 
59 using std::chrono::duration_cast;
60 using std::chrono::microseconds;
61 using std::chrono::steady_clock;
62 
63 using std::placeholders::_1;
64 using std::placeholders::_2;
65 
66 namespace otbr {
67 namespace rest {
68 
69 // MulticastAddr
70 static const char *kMulticastAddrAllRouters = "ff03::2";
71 
72 // Default TlvTypes for Diagnostic inforamtion
73 static const uint8_t kAllTlvTypes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 19};
74 
75 // Timeout (in Microseconds) for deleting outdated diagnostics
76 static const uint32_t kDiagResetTimeout = 3000000;
77 
78 // Timeout (in Microseconds) for collecting diagnostics
79 static const uint32_t kDiagCollectTimeout = 2000000;
80 
GetHttpStatus(HttpStatusCode aErrorCode)81 static std::string GetHttpStatus(HttpStatusCode aErrorCode)
82 {
83     std::string httpStatus;
84 
85     switch (aErrorCode)
86     {
87     case HttpStatusCode::kStatusOk:
88         httpStatus = OT_REST_HTTP_STATUS_200;
89         break;
90     case HttpStatusCode::kStatusResourceNotFound:
91         httpStatus = OT_REST_HTTP_STATUS_404;
92         break;
93     case HttpStatusCode::kStatusMethodNotAllowed:
94         httpStatus = OT_REST_HTTP_STATUS_405;
95         break;
96     case HttpStatusCode::kStatusRequestTimeout:
97         httpStatus = OT_REST_HTTP_STATUS_408;
98         break;
99     case HttpStatusCode::kStatusInternalServerError:
100         httpStatus = OT_REST_HTTP_STATUS_500;
101         break;
102     }
103 
104     return httpStatus;
105 }
106 
Resource(ControllerOpenThread * aNcp)107 Resource::Resource(ControllerOpenThread *aNcp)
108     : mInstance(nullptr)
109     , mNcp(aNcp)
110 {
111     // Resource Handler
112     mResourceMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOETIC, &Resource::Diagnostic);
113     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE, &Resource::NodeInfo);
114     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_STATE, &Resource::State);
115     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTADDRESS, &Resource::ExtendedAddr);
116     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NETWORKNAME, &Resource::NetworkName);
117     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC16, &Resource::Rloc16);
118     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_LEADERDATA, &Resource::LeaderData);
119     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER, &Resource::NumOfRoute);
120     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTPANID, &Resource::ExtendedPanId);
121     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC, &Resource::Rloc);
122 
123     // Resource callback handler
124     mResourceCallbackMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOETIC, &Resource::HandleDiagnosticCallback);
125 }
126 
Init(void)127 void Resource::Init(void)
128 {
129     mInstance = mNcp->GetThreadHelper()->GetInstance();
130 }
131 
Handle(Request & aRequest,Response & aResponse) const132 void Resource::Handle(Request &aRequest, Response &aResponse) const
133 {
134     std::string url = aRequest.GetUrl();
135     auto        it  = mResourceMap.find(url);
136 
137     if (it != mResourceMap.end())
138     {
139         ResourceHandler resourceHandler = it->second;
140         (this->*resourceHandler)(aRequest, aResponse);
141     }
142     else
143     {
144         ErrorHandler(aResponse, HttpStatusCode::kStatusResourceNotFound);
145     }
146 }
147 
HandleCallback(Request & aRequest,Response & aResponse)148 void Resource::HandleCallback(Request &aRequest, Response &aResponse)
149 {
150     std::string url = aRequest.GetUrl();
151     auto        it  = mResourceCallbackMap.find(url);
152 
153     if (it != mResourceCallbackMap.end())
154     {
155         ResourceCallbackHandler resourceHandler = it->second;
156         (this->*resourceHandler)(aRequest, aResponse);
157     }
158 }
159 
HandleDiagnosticCallback(const Request & aRequest,Response & aResponse)160 void Resource::HandleDiagnosticCallback(const Request &aRequest, Response &aResponse)
161 {
162     OT_UNUSED_VARIABLE(aRequest);
163     std::vector<std::vector<otNetworkDiagTlv>> diagContentSet;
164     std::string                                body;
165     std::string                                errorCode;
166 
167     auto duration = duration_cast<microseconds>(steady_clock::now() - aResponse.GetStartTime()).count();
168     if (duration >= kDiagCollectTimeout)
169     {
170         DeleteOutDatedDiagnostic();
171 
172         for (auto it = mDiagSet.begin(); it != mDiagSet.end(); ++it)
173         {
174             diagContentSet.push_back(it->second.mDiagContent);
175         }
176 
177         body      = Json::Diag2JsonString(diagContentSet);
178         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
179         aResponse.SetResponsCode(errorCode);
180         aResponse.SetBody(body);
181         aResponse.SetComplete();
182     }
183 }
184 
ErrorHandler(Response & aResponse,HttpStatusCode aErrorCode) const185 void Resource::ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const
186 {
187     std::string errorMessage = GetHttpStatus(aErrorCode);
188     std::string body         = Json::Error2JsonString(aErrorCode, errorMessage);
189 
190     aResponse.SetResponsCode(errorMessage);
191     aResponse.SetBody(body);
192     aResponse.SetComplete();
193 }
194 
GetNodeInfo(Response & aResponse) const195 void Resource::GetNodeInfo(Response &aResponse) const
196 {
197     otbrError       error = OTBR_ERROR_NONE;
198     struct NodeInfo node;
199     otRouterInfo    routerInfo;
200     uint8_t         maxRouterId;
201     std::string     body;
202     std::string     errorCode;
203 
204     VerifyOrExit(otThreadGetLeaderData(mInstance, &node.mLeaderData) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
205 
206     node.mNumOfRouter = 0;
207     maxRouterId       = otThreadGetMaxRouterId(mInstance);
208     for (uint8_t i = 0; i <= maxRouterId; ++i)
209     {
210         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
211         {
212             continue;
213         }
214         ++node.mNumOfRouter;
215     }
216 
217     node.mRole        = otThreadGetDeviceRole(mInstance);
218     node.mExtAddress  = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
219     node.mNetworkName = otThreadGetNetworkName(mInstance);
220     node.mRloc16      = otThreadGetRloc16(mInstance);
221     node.mExtPanId    = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
222     node.mRlocAddress = *otThreadGetRloc(mInstance);
223 
224     body = Json::Node2JsonString(node);
225     aResponse.SetBody(body);
226 
227 exit:
228     if (error == OTBR_ERROR_NONE)
229     {
230         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
231         aResponse.SetResponsCode(errorCode);
232     }
233     else
234     {
235         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
236     }
237 }
238 
NodeInfo(const Request & aRequest,Response & aResponse) const239 void Resource::NodeInfo(const Request &aRequest, Response &aResponse) const
240 {
241     std::string errorCode;
242     if (aRequest.GetMethod() == HttpMethod::kGet)
243     {
244         GetNodeInfo(aResponse);
245     }
246     else
247     {
248         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
249     }
250 }
251 
GetDataExtendedAddr(Response & aResponse) const252 void Resource::GetDataExtendedAddr(Response &aResponse) const
253 {
254     const uint8_t *extAddress = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
255     std::string    errorCode;
256     std::string    body = Json::Bytes2HexJsonString(extAddress, OT_EXT_ADDRESS_SIZE);
257 
258     aResponse.SetBody(body);
259     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
260     aResponse.SetResponsCode(errorCode);
261 }
262 
ExtendedAddr(const Request & aRequest,Response & aResponse) const263 void Resource::ExtendedAddr(const Request &aRequest, Response &aResponse) const
264 {
265     std::string errorCode;
266 
267     if (aRequest.GetMethod() == HttpMethod::kGet)
268     {
269         GetDataExtendedAddr(aResponse);
270     }
271     else
272     {
273         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
274     }
275 }
276 
GetDataState(Response & aResponse) const277 void Resource::GetDataState(Response &aResponse) const
278 {
279     std::string state;
280     std::string errorCode;
281     uint8_t     role;
282     // 0 : disabled
283     // 1 : detached
284     // 2 : child
285     // 3 : router
286     // 4 : leader
287 
288     role  = otThreadGetDeviceRole(mInstance);
289     state = Json::Number2JsonString(role);
290     aResponse.SetBody(state);
291     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
292     aResponse.SetResponsCode(errorCode);
293 }
294 
State(const Request & aRequest,Response & aResponse) const295 void Resource::State(const Request &aRequest, Response &aResponse) const
296 {
297     std::string errorCode;
298 
299     if (aRequest.GetMethod() == HttpMethod::kGet)
300     {
301         GetDataState(aResponse);
302     }
303     else
304     {
305         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
306     }
307 }
308 
GetDataNetworkName(Response & aResponse) const309 void Resource::GetDataNetworkName(Response &aResponse) const
310 {
311     std::string networkName;
312     std::string errorCode;
313 
314     networkName = otThreadGetNetworkName(mInstance);
315     networkName = Json::String2JsonString(networkName);
316 
317     aResponse.SetBody(networkName);
318     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
319     aResponse.SetResponsCode(errorCode);
320 }
321 
NetworkName(const Request & aRequest,Response & aResponse) const322 void Resource::NetworkName(const Request &aRequest, Response &aResponse) const
323 {
324     std::string errorCode;
325 
326     if (aRequest.GetMethod() == HttpMethod::kGet)
327     {
328         GetDataNetworkName(aResponse);
329     }
330     else
331     {
332         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
333     }
334 }
335 
GetDataLeaderData(Response & aResponse) const336 void Resource::GetDataLeaderData(Response &aResponse) const
337 {
338     otbrError    error = OTBR_ERROR_NONE;
339     otLeaderData leaderData;
340     std::string  body;
341     std::string  errorCode;
342 
343     VerifyOrExit(otThreadGetLeaderData(mInstance, &leaderData) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
344 
345     body = Json::LeaderData2JsonString(leaderData);
346 
347     aResponse.SetBody(body);
348 
349 exit:
350     if (error == OTBR_ERROR_NONE)
351     {
352         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
353         aResponse.SetResponsCode(errorCode);
354     }
355     else
356     {
357         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
358     }
359 }
360 
LeaderData(const Request & aRequest,Response & aResponse) const361 void Resource::LeaderData(const Request &aRequest, Response &aResponse) const
362 {
363     std::string errorCode;
364     if (aRequest.GetMethod() == HttpMethod::kGet)
365     {
366         GetDataLeaderData(aResponse);
367     }
368     else
369     {
370         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
371     }
372 }
373 
GetDataNumOfRoute(Response & aResponse) const374 void Resource::GetDataNumOfRoute(Response &aResponse) const
375 {
376     uint8_t      count = 0;
377     uint8_t      maxRouterId;
378     otRouterInfo routerInfo;
379     maxRouterId = otThreadGetMaxRouterId(mInstance);
380     std::string body;
381     std::string errorCode;
382 
383     for (uint8_t i = 0; i <= maxRouterId; ++i)
384     {
385         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
386         {
387             continue;
388         }
389         ++count;
390     }
391 
392     body = Json::Number2JsonString(count);
393 
394     aResponse.SetBody(body);
395     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
396     aResponse.SetResponsCode(errorCode);
397 }
398 
NumOfRoute(const Request & aRequest,Response & aResponse) const399 void Resource::NumOfRoute(const Request &aRequest, Response &aResponse) const
400 {
401     std::string errorCode;
402 
403     if (aRequest.GetMethod() == HttpMethod::kGet)
404     {
405         GetDataNumOfRoute(aResponse);
406     }
407     else
408     {
409         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
410     }
411 }
412 
GetDataRloc16(Response & aResponse) const413 void Resource::GetDataRloc16(Response &aResponse) const
414 {
415     uint16_t    rloc16 = otThreadGetRloc16(mInstance);
416     std::string body;
417     std::string errorCode;
418 
419     body = Json::Number2JsonString(rloc16);
420 
421     aResponse.SetBody(body);
422     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
423     aResponse.SetResponsCode(errorCode);
424 }
425 
Rloc16(const Request & aRequest,Response & aResponse) const426 void Resource::Rloc16(const Request &aRequest, Response &aResponse) const
427 {
428     std::string errorCode;
429 
430     if (aRequest.GetMethod() == HttpMethod::kGet)
431     {
432         GetDataRloc16(aResponse);
433     }
434     else
435     {
436         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
437     }
438 }
439 
GetDataExtendedPanId(Response & aResponse) const440 void Resource::GetDataExtendedPanId(Response &aResponse) const
441 {
442     const uint8_t *extPanId = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
443     std::string    body     = Json::Bytes2HexJsonString(extPanId, OT_EXT_PAN_ID_SIZE);
444     std::string    errorCode;
445 
446     aResponse.SetBody(body);
447     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
448     aResponse.SetResponsCode(errorCode);
449 }
450 
ExtendedPanId(const Request & aRequest,Response & aResponse) const451 void Resource::ExtendedPanId(const Request &aRequest, Response &aResponse) const
452 {
453     std::string errorCode;
454 
455     if (aRequest.GetMethod() == HttpMethod::kGet)
456     {
457         GetDataExtendedPanId(aResponse);
458     }
459     else
460     {
461         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
462     }
463 }
464 
GetDataRloc(Response & aResponse) const465 void Resource::GetDataRloc(Response &aResponse) const
466 {
467     otIp6Address rlocAddress = *otThreadGetRloc(mInstance);
468     std::string  body;
469     std::string  errorCode;
470 
471     body = Json::IpAddr2JsonString(rlocAddress);
472 
473     aResponse.SetBody(body);
474     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
475     aResponse.SetResponsCode(errorCode);
476 }
477 
Rloc(const Request & aRequest,Response & aResponse) const478 void Resource::Rloc(const Request &aRequest, Response &aResponse) const
479 {
480     std::string errorCode;
481 
482     if (aRequest.GetMethod() == HttpMethod::kGet)
483     {
484         GetDataRloc(aResponse);
485     }
486     else
487     {
488         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
489     }
490 }
491 
DeleteOutDatedDiagnostic(void)492 void Resource::DeleteOutDatedDiagnostic(void)
493 {
494     auto eraseIt = mDiagSet.begin();
495     for (eraseIt = mDiagSet.begin(); eraseIt != mDiagSet.end();)
496     {
497         auto diagInfo = eraseIt->second;
498         auto duration = duration_cast<microseconds>(steady_clock::now() - diagInfo.mStartTime).count();
499 
500         if (duration >= kDiagResetTimeout)
501         {
502             eraseIt = mDiagSet.erase(eraseIt);
503         }
504         else
505         {
506             eraseIt++;
507         }
508     }
509 }
510 
UpdateDiag(std::string aKey,std::vector<otNetworkDiagTlv> & aDiag)511 void Resource::UpdateDiag(std::string aKey, std::vector<otNetworkDiagTlv> &aDiag)
512 {
513     DiagInfo value;
514 
515     value.mStartTime = steady_clock::now();
516     value.mDiagContent.assign(aDiag.begin(), aDiag.end());
517     mDiagSet[aKey] = value;
518 }
519 
Diagnostic(const Request & aRequest,Response & aResponse) const520 void Resource::Diagnostic(const Request &aRequest, Response &aResponse) const
521 {
522     otbrError error = OTBR_ERROR_NONE;
523     OT_UNUSED_VARIABLE(aRequest);
524     struct otIp6Address rloc16address = *otThreadGetRloc(mInstance);
525     struct otIp6Address multicastAddress;
526 
527     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &rloc16address, kAllTlvTypes, sizeof(kAllTlvTypes),
528                                            &Resource::DiagnosticResponseHandler,
529                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
530                  error = OTBR_ERROR_REST);
531     VerifyOrExit(otIp6AddressFromString(kMulticastAddrAllRouters, &multicastAddress) == OT_ERROR_NONE,
532                  error = OTBR_ERROR_REST);
533     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &multicastAddress, kAllTlvTypes, sizeof(kAllTlvTypes),
534                                            &Resource::DiagnosticResponseHandler,
535                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
536                  error = OTBR_ERROR_REST);
537 
538 exit:
539 
540     if (error == OTBR_ERROR_NONE)
541     {
542         aResponse.SetStartTime(steady_clock::now());
543         aResponse.SetCallback();
544     }
545     else
546     {
547         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
548     }
549 }
550 
DiagnosticResponseHandler(otError aError,otMessage * aMessage,const otMessageInfo * aMessageInfo,void * aContext)551 void Resource::DiagnosticResponseHandler(otError              aError,
552                                          otMessage *          aMessage,
553                                          const otMessageInfo *aMessageInfo,
554                                          void *               aContext)
555 {
556     static_cast<Resource *>(aContext)->DiagnosticResponseHandler(aError, aMessage, aMessageInfo);
557 }
558 
DiagnosticResponseHandler(otError aError,const otMessage * aMessage,const otMessageInfo * aMessageInfo)559 void Resource::DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo)
560 {
561     std::vector<otNetworkDiagTlv> diagSet;
562     otNetworkDiagTlv              diagTlv;
563     otNetworkDiagIterator         iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT;
564     otError                       error;
565     char                          rloc[7];
566     std::string                   keyRloc = "0xffee";
567 
568     SuccessOrExit(aError);
569 
570     OTBR_UNUSED_VARIABLE(aMessageInfo);
571 
572     while ((error = otThreadGetNextDiagnosticTlv(aMessage, &iterator, &diagTlv)) == OT_ERROR_NONE)
573     {
574         if (diagTlv.mType == OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS)
575         {
576             sprintf(rloc, "0x%04x", diagTlv.mData.mAddr16);
577             keyRloc = Json::CString2JsonString(rloc);
578         }
579         diagSet.push_back(diagTlv);
580     }
581     UpdateDiag(keyRloc, diagSet);
582 
583 exit:
584     if (aError != OT_ERROR_NONE)
585     {
586         otbrLogWarning("Failed to get diagnostic data: %s", otThreadErrorToString(aError));
587     }
588 }
589 
590 } // namespace rest
591 } // namespace otbr
592