xref: /aosp_15_r20/external/ot-br-posix/src/rest/resource.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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 #define OT_PSKC_MAX_LENGTH 16
34 #define OT_EXTENDED_PANID_LENGTH 8
35 
36 #define OT_REST_RESOURCE_PATH_DIAGNOSTICS "/diagnostics"
37 #define OT_REST_RESOURCE_PATH_NODE "/node"
38 #define OT_REST_RESOURCE_PATH_NODE_BAID "/node/ba-id"
39 #define OT_REST_RESOURCE_PATH_NODE_RLOC "/node/rloc"
40 #define OT_REST_RESOURCE_PATH_NODE_RLOC16 "/node/rloc16"
41 #define OT_REST_RESOURCE_PATH_NODE_EXTADDRESS "/node/ext-address"
42 #define OT_REST_RESOURCE_PATH_NODE_STATE "/node/state"
43 #define OT_REST_RESOURCE_PATH_NODE_NETWORKNAME "/node/network-name"
44 #define OT_REST_RESOURCE_PATH_NODE_LEADERDATA "/node/leader-data"
45 #define OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER "/node/num-of-router"
46 #define OT_REST_RESOURCE_PATH_NODE_EXTPANID "/node/ext-panid"
47 #define OT_REST_RESOURCE_PATH_NODE_DATASET_ACTIVE "/node/dataset/active"
48 #define OT_REST_RESOURCE_PATH_NODE_DATASET_PENDING "/node/dataset/pending"
49 #define OT_REST_RESOURCE_PATH_NETWORK "/networks"
50 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT "/networks/current"
51 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_COMMISSION "/networks/commission"
52 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_PREFIX "/networks/current/prefix"
53 
54 #define OT_REST_HTTP_STATUS_200 "200 OK"
55 #define OT_REST_HTTP_STATUS_201 "201 Created"
56 #define OT_REST_HTTP_STATUS_204 "204 No Content"
57 #define OT_REST_HTTP_STATUS_400 "400 Bad Request"
58 #define OT_REST_HTTP_STATUS_404 "404 Not Found"
59 #define OT_REST_HTTP_STATUS_405 "405 Method Not Allowed"
60 #define OT_REST_HTTP_STATUS_408 "408 Request Timeout"
61 #define OT_REST_HTTP_STATUS_409 "409 Conflict"
62 #define OT_REST_HTTP_STATUS_500 "500 Internal Server Error"
63 
64 using std::chrono::duration_cast;
65 using std::chrono::microseconds;
66 using std::chrono::steady_clock;
67 
68 using std::placeholders::_1;
69 using std::placeholders::_2;
70 
71 namespace otbr {
72 namespace rest {
73 
74 // MulticastAddr
75 static const char *kMulticastAddrAllRouters = "ff03::2";
76 
77 // Default TlvTypes for Diagnostic inforamtion
78 static const uint8_t kAllTlvTypes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 19};
79 
80 // Timeout (in Microseconds) for deleting outdated diagnostics
81 static const uint32_t kDiagResetTimeout = 3000000;
82 
83 // Timeout (in Microseconds) for collecting diagnostics
84 static const uint32_t kDiagCollectTimeout = 2000000;
85 
GetHttpStatus(HttpStatusCode aErrorCode)86 static std::string GetHttpStatus(HttpStatusCode aErrorCode)
87 {
88     std::string httpStatus;
89 
90     switch (aErrorCode)
91     {
92     case HttpStatusCode::kStatusOk:
93         httpStatus = OT_REST_HTTP_STATUS_200;
94         break;
95     case HttpStatusCode::kStatusCreated:
96         httpStatus = OT_REST_HTTP_STATUS_201;
97         break;
98     case HttpStatusCode::kStatusNoContent:
99         httpStatus = OT_REST_HTTP_STATUS_204;
100         break;
101     case HttpStatusCode::kStatusBadRequest:
102         httpStatus = OT_REST_HTTP_STATUS_400;
103         break;
104     case HttpStatusCode::kStatusResourceNotFound:
105         httpStatus = OT_REST_HTTP_STATUS_404;
106         break;
107     case HttpStatusCode::kStatusMethodNotAllowed:
108         httpStatus = OT_REST_HTTP_STATUS_405;
109         break;
110     case HttpStatusCode::kStatusRequestTimeout:
111         httpStatus = OT_REST_HTTP_STATUS_408;
112         break;
113     case HttpStatusCode::kStatusConflict:
114         httpStatus = OT_REST_HTTP_STATUS_409;
115         break;
116     case HttpStatusCode::kStatusInternalServerError:
117         httpStatus = OT_REST_HTTP_STATUS_500;
118         break;
119     }
120 
121     return httpStatus;
122 }
123 
Resource(RcpHost * aHost)124 Resource::Resource(RcpHost *aHost)
125     : mInstance(nullptr)
126     , mHost(aHost)
127 {
128     // Resource Handler
129     mResourceMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOSTICS, &Resource::Diagnostic);
130     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE, &Resource::NodeInfo);
131     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_BAID, &Resource::BaId);
132     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_STATE, &Resource::State);
133     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTADDRESS, &Resource::ExtendedAddr);
134     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NETWORKNAME, &Resource::NetworkName);
135     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC16, &Resource::Rloc16);
136     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_LEADERDATA, &Resource::LeaderData);
137     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER, &Resource::NumOfRoute);
138     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTPANID, &Resource::ExtendedPanId);
139     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC, &Resource::Rloc);
140     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_DATASET_ACTIVE, &Resource::DatasetActive);
141     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_DATASET_PENDING, &Resource::DatasetPending);
142 
143     // Resource callback handler
144     mResourceCallbackMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOSTICS, &Resource::HandleDiagnosticCallback);
145 }
146 
Init(void)147 void Resource::Init(void)
148 {
149     mInstance = mHost->GetThreadHelper()->GetInstance();
150 }
151 
Handle(Request & aRequest,Response & aResponse) const152 void Resource::Handle(Request &aRequest, Response &aResponse) const
153 {
154     std::string url = aRequest.GetUrl();
155     auto        it  = mResourceMap.find(url);
156 
157     if (it != mResourceMap.end())
158     {
159         ResourceHandler resourceHandler = it->second;
160         (this->*resourceHandler)(aRequest, aResponse);
161     }
162     else
163     {
164         ErrorHandler(aResponse, HttpStatusCode::kStatusResourceNotFound);
165     }
166 }
167 
HandleCallback(Request & aRequest,Response & aResponse)168 void Resource::HandleCallback(Request &aRequest, Response &aResponse)
169 {
170     std::string url = aRequest.GetUrl();
171     auto        it  = mResourceCallbackMap.find(url);
172 
173     if (it != mResourceCallbackMap.end())
174     {
175         ResourceCallbackHandler resourceHandler = it->second;
176         (this->*resourceHandler)(aRequest, aResponse);
177     }
178 }
179 
HandleDiagnosticCallback(const Request & aRequest,Response & aResponse)180 void Resource::HandleDiagnosticCallback(const Request &aRequest, Response &aResponse)
181 {
182     OT_UNUSED_VARIABLE(aRequest);
183     std::vector<std::vector<otNetworkDiagTlv>> diagContentSet;
184     std::string                                body;
185     std::string                                errorCode;
186 
187     auto duration = duration_cast<microseconds>(steady_clock::now() - aResponse.GetStartTime()).count();
188     if (duration >= kDiagCollectTimeout)
189     {
190         DeleteOutDatedDiagnostic();
191 
192         for (auto it = mDiagSet.begin(); it != mDiagSet.end(); ++it)
193         {
194             diagContentSet.push_back(it->second.mDiagContent);
195         }
196 
197         body      = Json::Diag2JsonString(diagContentSet);
198         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
199         aResponse.SetResponsCode(errorCode);
200         aResponse.SetBody(body);
201         aResponse.SetComplete();
202     }
203 }
204 
ErrorHandler(Response & aResponse,HttpStatusCode aErrorCode) const205 void Resource::ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const
206 {
207     std::string errorMessage = GetHttpStatus(aErrorCode);
208     std::string body         = Json::Error2JsonString(aErrorCode, errorMessage);
209 
210     aResponse.SetResponsCode(errorMessage);
211     aResponse.SetBody(body);
212     aResponse.SetComplete();
213 }
214 
GetNodeInfo(Response & aResponse) const215 void Resource::GetNodeInfo(Response &aResponse) const
216 {
217     otbrError       error = OTBR_ERROR_NONE;
218     struct NodeInfo node  = {};
219     otRouterInfo    routerInfo;
220     uint8_t         maxRouterId;
221     std::string     body;
222     std::string     errorCode;
223 
224     VerifyOrExit(otBorderAgentGetId(mInstance, &node.mBaId) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
225     (void)otThreadGetLeaderData(mInstance, &node.mLeaderData);
226 
227     node.mNumOfRouter = 0;
228     maxRouterId       = otThreadGetMaxRouterId(mInstance);
229     for (uint8_t i = 0; i <= maxRouterId; ++i)
230     {
231         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
232         {
233             continue;
234         }
235         ++node.mNumOfRouter;
236     }
237 
238     node.mRole        = GetDeviceRoleName(otThreadGetDeviceRole(mInstance));
239     node.mExtAddress  = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
240     node.mNetworkName = otThreadGetNetworkName(mInstance);
241     node.mRloc16      = otThreadGetRloc16(mInstance);
242     node.mExtPanId    = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
243     node.mRlocAddress = *otThreadGetRloc(mInstance);
244 
245     body = Json::Node2JsonString(node);
246     aResponse.SetBody(body);
247 
248 exit:
249     if (error == OTBR_ERROR_NONE)
250     {
251         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
252         aResponse.SetResponsCode(errorCode);
253     }
254     else
255     {
256         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
257     }
258 }
259 
DeleteNodeInfo(Response & aResponse) const260 void Resource::DeleteNodeInfo(Response &aResponse) const
261 {
262     otbrError   error = OTBR_ERROR_NONE;
263     std::string errorCode;
264 
265     VerifyOrExit(mHost->GetThreadHelper()->Detach() == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
266     VerifyOrExit(otInstanceErasePersistentInfo(mInstance) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
267     mHost->Reset();
268 
269 exit:
270     if (error == OTBR_ERROR_NONE)
271     {
272         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
273         aResponse.SetResponsCode(errorCode);
274     }
275     else if (error == OTBR_ERROR_INVALID_STATE)
276     {
277         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
278     }
279     else if (error != OTBR_ERROR_NONE)
280     {
281         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
282     }
283 }
284 
NodeInfo(const Request & aRequest,Response & aResponse) const285 void Resource::NodeInfo(const Request &aRequest, Response &aResponse) const
286 {
287     std::string errorCode;
288 
289     switch (aRequest.GetMethod())
290     {
291     case HttpMethod::kGet:
292         GetNodeInfo(aResponse);
293         break;
294     case HttpMethod::kDelete:
295         DeleteNodeInfo(aResponse);
296         break;
297     default:
298         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
299         break;
300     }
301 }
302 
GetDataBaId(Response & aResponse) const303 void Resource::GetDataBaId(Response &aResponse) const
304 {
305     otbrError       error = OTBR_ERROR_NONE;
306     otBorderAgentId id;
307     std::string     body;
308     std::string     errorCode;
309 
310     VerifyOrExit(otBorderAgentGetId(mInstance, &id) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
311 
312     body = Json::Bytes2HexJsonString(id.mId, sizeof(id));
313     aResponse.SetBody(body);
314 
315 exit:
316     if (error == OTBR_ERROR_NONE)
317     {
318         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
319         aResponse.SetResponsCode(errorCode);
320     }
321     else
322     {
323         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
324     }
325 }
326 
BaId(const Request & aRequest,Response & aResponse) const327 void Resource::BaId(const Request &aRequest, Response &aResponse) const
328 {
329     std::string errorCode;
330 
331     if (aRequest.GetMethod() == HttpMethod::kGet)
332     {
333         GetDataBaId(aResponse);
334     }
335     else
336     {
337         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
338     }
339 }
340 
GetDataExtendedAddr(Response & aResponse) const341 void Resource::GetDataExtendedAddr(Response &aResponse) const
342 {
343     const uint8_t *extAddress = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
344     std::string    errorCode;
345     std::string    body = Json::Bytes2HexJsonString(extAddress, OT_EXT_ADDRESS_SIZE);
346 
347     aResponse.SetBody(body);
348     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
349     aResponse.SetResponsCode(errorCode);
350 }
351 
ExtendedAddr(const Request & aRequest,Response & aResponse) const352 void Resource::ExtendedAddr(const Request &aRequest, Response &aResponse) const
353 {
354     std::string errorCode;
355 
356     if (aRequest.GetMethod() == HttpMethod::kGet)
357     {
358         GetDataExtendedAddr(aResponse);
359     }
360     else
361     {
362         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
363     }
364 }
365 
GetDataState(Response & aResponse) const366 void Resource::GetDataState(Response &aResponse) const
367 {
368     std::string  state;
369     std::string  errorCode;
370     otDeviceRole role;
371 
372     role  = otThreadGetDeviceRole(mInstance);
373     state = Json::String2JsonString(GetDeviceRoleName(role));
374     aResponse.SetBody(state);
375     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
376     aResponse.SetResponsCode(errorCode);
377 }
378 
SetDataState(const Request & aRequest,Response & aResponse) const379 void Resource::SetDataState(const Request &aRequest, Response &aResponse) const
380 {
381     otbrError   error = OTBR_ERROR_NONE;
382     std::string errorCode;
383     std::string body;
384 
385     VerifyOrExit(Json::JsonString2String(aRequest.GetBody(), body), error = OTBR_ERROR_INVALID_ARGS);
386     if (body == "enable")
387     {
388         if (!otIp6IsEnabled(mInstance))
389         {
390             VerifyOrExit(otIp6SetEnabled(mInstance, true) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
391         }
392         VerifyOrExit(otThreadSetEnabled(mInstance, true) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
393     }
394     else if (body == "disable")
395     {
396         VerifyOrExit(otThreadSetEnabled(mInstance, false) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
397         VerifyOrExit(otIp6SetEnabled(mInstance, false) == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE);
398     }
399     else
400     {
401         ExitNow(error = OTBR_ERROR_INVALID_ARGS);
402     }
403 
404     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
405     aResponse.SetResponsCode(errorCode);
406 
407 exit:
408     if (error == OTBR_ERROR_INVALID_STATE)
409     {
410         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
411     }
412     if (error == OTBR_ERROR_INVALID_ARGS)
413     {
414         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
415     }
416     else if (error != OTBR_ERROR_NONE)
417     {
418         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
419     }
420 }
421 
State(const Request & aRequest,Response & aResponse) const422 void Resource::State(const Request &aRequest, Response &aResponse) const
423 {
424     std::string errorCode;
425 
426     switch (aRequest.GetMethod())
427     {
428     case HttpMethod::kGet:
429         GetDataState(aResponse);
430         break;
431     case HttpMethod::kPut:
432         SetDataState(aRequest, aResponse);
433         break;
434     case HttpMethod::kOptions:
435         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
436         aResponse.SetResponsCode(errorCode);
437         aResponse.SetComplete();
438         break;
439     default:
440         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
441         break;
442     }
443 }
444 
GetDataNetworkName(Response & aResponse) const445 void Resource::GetDataNetworkName(Response &aResponse) const
446 {
447     std::string networkName;
448     std::string errorCode;
449 
450     networkName = otThreadGetNetworkName(mInstance);
451     networkName = Json::String2JsonString(networkName);
452 
453     aResponse.SetBody(networkName);
454     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
455     aResponse.SetResponsCode(errorCode);
456 }
457 
NetworkName(const Request & aRequest,Response & aResponse) const458 void Resource::NetworkName(const Request &aRequest, Response &aResponse) const
459 {
460     std::string errorCode;
461 
462     if (aRequest.GetMethod() == HttpMethod::kGet)
463     {
464         GetDataNetworkName(aResponse);
465     }
466     else
467     {
468         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
469     }
470 }
471 
GetDataLeaderData(Response & aResponse) const472 void Resource::GetDataLeaderData(Response &aResponse) const
473 {
474     otbrError    error = OTBR_ERROR_NONE;
475     otLeaderData leaderData;
476     std::string  body;
477     std::string  errorCode;
478 
479     VerifyOrExit(otThreadGetLeaderData(mInstance, &leaderData) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
480 
481     body = Json::LeaderData2JsonString(leaderData);
482 
483     aResponse.SetBody(body);
484 
485 exit:
486     if (error == OTBR_ERROR_NONE)
487     {
488         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
489         aResponse.SetResponsCode(errorCode);
490     }
491     else
492     {
493         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
494     }
495 }
496 
LeaderData(const Request & aRequest,Response & aResponse) const497 void Resource::LeaderData(const Request &aRequest, Response &aResponse) const
498 {
499     std::string errorCode;
500     if (aRequest.GetMethod() == HttpMethod::kGet)
501     {
502         GetDataLeaderData(aResponse);
503     }
504     else
505     {
506         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
507     }
508 }
509 
GetDataNumOfRoute(Response & aResponse) const510 void Resource::GetDataNumOfRoute(Response &aResponse) const
511 {
512     uint8_t      count = 0;
513     uint8_t      maxRouterId;
514     otRouterInfo routerInfo;
515     maxRouterId = otThreadGetMaxRouterId(mInstance);
516     std::string body;
517     std::string errorCode;
518 
519     for (uint8_t i = 0; i <= maxRouterId; ++i)
520     {
521         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
522         {
523             continue;
524         }
525         ++count;
526     }
527 
528     body = Json::Number2JsonString(count);
529 
530     aResponse.SetBody(body);
531     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
532     aResponse.SetResponsCode(errorCode);
533 }
534 
NumOfRoute(const Request & aRequest,Response & aResponse) const535 void Resource::NumOfRoute(const Request &aRequest, Response &aResponse) const
536 {
537     std::string errorCode;
538 
539     if (aRequest.GetMethod() == HttpMethod::kGet)
540     {
541         GetDataNumOfRoute(aResponse);
542     }
543     else
544     {
545         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
546     }
547 }
548 
GetDataRloc16(Response & aResponse) const549 void Resource::GetDataRloc16(Response &aResponse) const
550 {
551     uint16_t    rloc16 = otThreadGetRloc16(mInstance);
552     std::string body;
553     std::string errorCode;
554 
555     body = Json::Number2JsonString(rloc16);
556 
557     aResponse.SetBody(body);
558     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
559     aResponse.SetResponsCode(errorCode);
560 }
561 
Rloc16(const Request & aRequest,Response & aResponse) const562 void Resource::Rloc16(const Request &aRequest, Response &aResponse) const
563 {
564     std::string errorCode;
565 
566     if (aRequest.GetMethod() == HttpMethod::kGet)
567     {
568         GetDataRloc16(aResponse);
569     }
570     else
571     {
572         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
573     }
574 }
575 
GetDataExtendedPanId(Response & aResponse) const576 void Resource::GetDataExtendedPanId(Response &aResponse) const
577 {
578     const uint8_t *extPanId = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
579     std::string    body     = Json::Bytes2HexJsonString(extPanId, OT_EXT_PAN_ID_SIZE);
580     std::string    errorCode;
581 
582     aResponse.SetBody(body);
583     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
584     aResponse.SetResponsCode(errorCode);
585 }
586 
ExtendedPanId(const Request & aRequest,Response & aResponse) const587 void Resource::ExtendedPanId(const Request &aRequest, Response &aResponse) const
588 {
589     std::string errorCode;
590 
591     if (aRequest.GetMethod() == HttpMethod::kGet)
592     {
593         GetDataExtendedPanId(aResponse);
594     }
595     else
596     {
597         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
598     }
599 }
600 
GetDataRloc(Response & aResponse) const601 void Resource::GetDataRloc(Response &aResponse) const
602 {
603     otIp6Address rlocAddress = *otThreadGetRloc(mInstance);
604     std::string  body;
605     std::string  errorCode;
606 
607     body = Json::IpAddr2JsonString(rlocAddress);
608 
609     aResponse.SetBody(body);
610     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
611     aResponse.SetResponsCode(errorCode);
612 }
613 
Rloc(const Request & aRequest,Response & aResponse) const614 void Resource::Rloc(const Request &aRequest, Response &aResponse) const
615 {
616     std::string errorCode;
617 
618     if (aRequest.GetMethod() == HttpMethod::kGet)
619     {
620         GetDataRloc(aResponse);
621     }
622     else
623     {
624         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
625     }
626 }
627 
GetDataset(DatasetType aDatasetType,const Request & aRequest,Response & aResponse) const628 void Resource::GetDataset(DatasetType aDatasetType, const Request &aRequest, Response &aResponse) const
629 {
630     otbrError                error = OTBR_ERROR_NONE;
631     struct NodeInfo          node;
632     std::string              body;
633     std::string              errorCode;
634     otOperationalDataset     dataset;
635     otOperationalDatasetTlvs datasetTlvs;
636 
637     if (aRequest.GetHeaderValue(OT_REST_ACCEPT_HEADER) == OT_REST_CONTENT_TYPE_PLAIN)
638     {
639         if (aDatasetType == DatasetType::kActive)
640         {
641             VerifyOrExit(otDatasetGetActiveTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE,
642                          error = OTBR_ERROR_NOT_FOUND);
643         }
644         else if (aDatasetType == DatasetType::kPending)
645         {
646             VerifyOrExit(otDatasetGetPendingTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE,
647                          error = OTBR_ERROR_NOT_FOUND);
648         }
649 
650         aResponse.SetContentType(OT_REST_CONTENT_TYPE_PLAIN);
651         body = Utils::Bytes2Hex(datasetTlvs.mTlvs, datasetTlvs.mLength);
652     }
653     else
654     {
655         if (aDatasetType == DatasetType::kActive)
656         {
657             VerifyOrExit(otDatasetGetActive(mInstance, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_NOT_FOUND);
658             body = Json::ActiveDataset2JsonString(dataset);
659         }
660         else if (aDatasetType == DatasetType::kPending)
661         {
662             VerifyOrExit(otDatasetGetPending(mInstance, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_NOT_FOUND);
663             body = Json::PendingDataset2JsonString(dataset);
664         }
665     }
666 
667     aResponse.SetBody(body);
668 
669 exit:
670     if (error == OTBR_ERROR_NONE)
671     {
672         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
673         aResponse.SetResponsCode(errorCode);
674     }
675     else if (error == OTBR_ERROR_NOT_FOUND)
676     {
677         errorCode = GetHttpStatus(HttpStatusCode::kStatusNoContent);
678         aResponse.SetResponsCode(errorCode);
679     }
680     else
681     {
682         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
683     }
684 }
685 
SetDataset(DatasetType aDatasetType,const Request & aRequest,Response & aResponse) const686 void Resource::SetDataset(DatasetType aDatasetType, const Request &aRequest, Response &aResponse) const
687 {
688     otError                  errorOt = OT_ERROR_NONE;
689     otbrError                error   = OTBR_ERROR_NONE;
690     struct NodeInfo          node;
691     std::string              body;
692     std::string              errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
693     otOperationalDataset     dataset   = {};
694     otOperationalDatasetTlvs datasetTlvs;
695     otOperationalDatasetTlvs datasetUpdateTlvs;
696     int                      ret;
697     bool                     isTlv;
698 
699     if (aDatasetType == DatasetType::kActive)
700     {
701         VerifyOrExit(otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED, error = OTBR_ERROR_INVALID_STATE);
702         errorOt = otDatasetGetActiveTlvs(mInstance, &datasetTlvs);
703     }
704     else if (aDatasetType == DatasetType::kPending)
705     {
706         errorOt = otDatasetGetPendingTlvs(mInstance, &datasetTlvs);
707     }
708 
709     // Create a new operational dataset if it doesn't exist.
710     if (errorOt == OT_ERROR_NOT_FOUND)
711     {
712         VerifyOrExit(otDatasetCreateNewNetwork(mInstance, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
713         otDatasetConvertToTlvs(&dataset, &datasetTlvs);
714         errorCode = GetHttpStatus(HttpStatusCode::kStatusCreated);
715     }
716 
717     isTlv = aRequest.GetHeaderValue(OT_REST_CONTENT_TYPE_HEADER) == OT_REST_CONTENT_TYPE_PLAIN;
718 
719     if (isTlv)
720     {
721         ret = Json::Hex2BytesJsonString(aRequest.GetBody(), datasetUpdateTlvs.mTlvs, OT_OPERATIONAL_DATASET_MAX_LENGTH);
722         VerifyOrExit(ret >= 0, error = OTBR_ERROR_INVALID_ARGS);
723         datasetUpdateTlvs.mLength = ret;
724 
725         VerifyOrExit(otDatasetParseTlvs(&datasetUpdateTlvs, &dataset) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
726         VerifyOrExit(otDatasetUpdateTlvs(&dataset, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
727     }
728     else
729     {
730         if (aDatasetType == DatasetType::kActive)
731         {
732             VerifyOrExit(Json::JsonActiveDatasetString2Dataset(aRequest.GetBody(), dataset),
733                          error = OTBR_ERROR_INVALID_ARGS);
734         }
735         else if (aDatasetType == DatasetType::kPending)
736         {
737             VerifyOrExit(Json::JsonPendingDatasetString2Dataset(aRequest.GetBody(), dataset),
738                          error = OTBR_ERROR_INVALID_ARGS);
739             VerifyOrExit(dataset.mComponents.mIsDelayPresent, error = OTBR_ERROR_INVALID_ARGS);
740         }
741         VerifyOrExit(otDatasetUpdateTlvs(&dataset, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
742     }
743 
744     if (aDatasetType == DatasetType::kActive)
745     {
746         VerifyOrExit(otDatasetSetActiveTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
747     }
748     else if (aDatasetType == DatasetType::kPending)
749     {
750         VerifyOrExit(otDatasetSetPendingTlvs(mInstance, &datasetTlvs) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
751     }
752 
753     aResponse.SetResponsCode(errorCode);
754 
755 exit:
756     if (error == OTBR_ERROR_INVALID_ARGS)
757     {
758         ErrorHandler(aResponse, HttpStatusCode::kStatusBadRequest);
759     }
760     else if (error == OTBR_ERROR_INVALID_STATE)
761     {
762         ErrorHandler(aResponse, HttpStatusCode::kStatusConflict);
763     }
764     else if (error != OTBR_ERROR_NONE)
765     {
766         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
767     }
768 }
769 
Dataset(DatasetType aDatasetType,const Request & aRequest,Response & aResponse) const770 void Resource::Dataset(DatasetType aDatasetType, const Request &aRequest, Response &aResponse) const
771 {
772     std::string errorCode;
773 
774     switch (aRequest.GetMethod())
775     {
776     case HttpMethod::kGet:
777         GetDataset(aDatasetType, aRequest, aResponse);
778         break;
779     case HttpMethod::kPut:
780         SetDataset(aDatasetType, aRequest, aResponse);
781         break;
782     case HttpMethod::kOptions:
783         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
784         aResponse.SetResponsCode(errorCode);
785         aResponse.SetComplete();
786         break;
787     default:
788         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
789         break;
790     }
791 }
792 
DatasetActive(const Request & aRequest,Response & aResponse) const793 void Resource::DatasetActive(const Request &aRequest, Response &aResponse) const
794 {
795     Dataset(DatasetType::kActive, aRequest, aResponse);
796 }
797 
DatasetPending(const Request & aRequest,Response & aResponse) const798 void Resource::DatasetPending(const Request &aRequest, Response &aResponse) const
799 {
800     Dataset(DatasetType::kPending, aRequest, aResponse);
801 }
802 
DeleteOutDatedDiagnostic(void)803 void Resource::DeleteOutDatedDiagnostic(void)
804 {
805     auto eraseIt = mDiagSet.begin();
806     for (eraseIt = mDiagSet.begin(); eraseIt != mDiagSet.end();)
807     {
808         auto diagInfo = eraseIt->second;
809         auto duration = duration_cast<microseconds>(steady_clock::now() - diagInfo.mStartTime).count();
810 
811         if (duration >= kDiagResetTimeout)
812         {
813             eraseIt = mDiagSet.erase(eraseIt);
814         }
815         else
816         {
817             eraseIt++;
818         }
819     }
820 }
821 
UpdateDiag(std::string aKey,std::vector<otNetworkDiagTlv> & aDiag)822 void Resource::UpdateDiag(std::string aKey, std::vector<otNetworkDiagTlv> &aDiag)
823 {
824     DiagInfo value;
825 
826     value.mStartTime = steady_clock::now();
827     value.mDiagContent.assign(aDiag.begin(), aDiag.end());
828     mDiagSet[aKey] = value;
829 }
830 
Diagnostic(const Request & aRequest,Response & aResponse) const831 void Resource::Diagnostic(const Request &aRequest, Response &aResponse) const
832 {
833     otbrError error = OTBR_ERROR_NONE;
834     OT_UNUSED_VARIABLE(aRequest);
835     struct otIp6Address rloc16address = *otThreadGetRloc(mInstance);
836     struct otIp6Address multicastAddress;
837 
838     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &rloc16address, kAllTlvTypes, sizeof(kAllTlvTypes),
839                                            &Resource::DiagnosticResponseHandler,
840                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
841                  error = OTBR_ERROR_REST);
842     VerifyOrExit(otIp6AddressFromString(kMulticastAddrAllRouters, &multicastAddress) == OT_ERROR_NONE,
843                  error = OTBR_ERROR_REST);
844     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &multicastAddress, kAllTlvTypes, sizeof(kAllTlvTypes),
845                                            &Resource::DiagnosticResponseHandler,
846                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
847                  error = OTBR_ERROR_REST);
848 
849 exit:
850 
851     if (error == OTBR_ERROR_NONE)
852     {
853         aResponse.SetStartTime(steady_clock::now());
854         aResponse.SetCallback();
855     }
856     else
857     {
858         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
859     }
860 }
861 
DiagnosticResponseHandler(otError aError,otMessage * aMessage,const otMessageInfo * aMessageInfo,void * aContext)862 void Resource::DiagnosticResponseHandler(otError              aError,
863                                          otMessage           *aMessage,
864                                          const otMessageInfo *aMessageInfo,
865                                          void                *aContext)
866 {
867     static_cast<Resource *>(aContext)->DiagnosticResponseHandler(aError, aMessage, aMessageInfo);
868 }
869 
DiagnosticResponseHandler(otError aError,const otMessage * aMessage,const otMessageInfo * aMessageInfo)870 void Resource::DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo)
871 {
872     std::vector<otNetworkDiagTlv> diagSet;
873     otNetworkDiagTlv              diagTlv;
874     otNetworkDiagIterator         iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT;
875     otError                       error;
876     char                          rloc[7];
877     std::string                   keyRloc = "0xffee";
878 
879     SuccessOrExit(aError);
880 
881     OTBR_UNUSED_VARIABLE(aMessageInfo);
882 
883     while ((error = otThreadGetNextDiagnosticTlv(aMessage, &iterator, &diagTlv)) == OT_ERROR_NONE)
884     {
885         if (diagTlv.mType == OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS)
886         {
887             snprintf(rloc, sizeof(rloc), "0x%04x", diagTlv.mData.mAddr16);
888             keyRloc = Json::CString2JsonString(rloc);
889         }
890         diagSet.push_back(diagTlv);
891     }
892     UpdateDiag(keyRloc, diagSet);
893 
894 exit:
895     if (aError != OT_ERROR_NONE)
896     {
897         otbrLogWarning("Failed to get diagnostic data: %s", otThreadErrorToString(aError));
898     }
899 }
900 
901 } // namespace rest
902 } // namespace otbr
903