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