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