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 "UTILS"
30
31 #include "utils/thread_helper.hpp"
32
33 #include <assert.h>
34 #include <limits.h>
35 #include <string.h>
36 #include <time.h>
37
38 #include <string>
39
40 #include <openthread/border_router.h>
41 #include <openthread/channel_manager.h>
42 #include <openthread/jam_detection.h>
43 #include <openthread/joiner.h>
44 #include <openthread/thread_ftd.h>
45 #include <openthread/platform/radio.h>
46
47 #include "common/byteswap.hpp"
48 #include "common/code_utils.hpp"
49 #include "common/logging.hpp"
50 #include "common/tlv.hpp"
51 #include "ncp/ncp_openthread.hpp"
52
53 namespace otbr {
54 namespace agent {
55 namespace {
FindTlv(uint8_t aTlvType,const uint8_t * aTlvs,int aTlvsSize)56 const Tlv *FindTlv(uint8_t aTlvType, const uint8_t *aTlvs, int aTlvsSize)
57 {
58 const Tlv *result = nullptr;
59
60 for (const Tlv *tlv = reinterpret_cast<const Tlv *>(aTlvs);
61 reinterpret_cast<const uint8_t *>(tlv) + sizeof(Tlv) < aTlvs + aTlvsSize; tlv = tlv->GetNext())
62 {
63 if (tlv->GetType() == aTlvType)
64 {
65 ExitNow(result = tlv);
66 }
67 }
68
69 exit:
70 return result;
71 }
72 } // namespace
73
ThreadHelper(otInstance * aInstance,otbr::Ncp::ControllerOpenThread * aNcp)74 ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp)
75 : mInstance(aInstance)
76 , mNcp(aNcp)
77 {
78 }
79
StateChangedCallback(otChangedFlags aFlags)80 void ThreadHelper::StateChangedCallback(otChangedFlags aFlags)
81 {
82 if (aFlags & OT_CHANGED_THREAD_ROLE)
83 {
84 otDeviceRole role = otThreadGetDeviceRole(mInstance);
85
86 for (const auto &handler : mDeviceRoleHandlers)
87 {
88 handler(role);
89 }
90
91 if (role != OT_DEVICE_ROLE_DISABLED && role != OT_DEVICE_ROLE_DETACHED)
92 {
93 if (mAttachHandler != nullptr)
94 {
95 if (mAttachPendingDatasetTlvs.mLength == 0)
96 {
97 AttachHandler handler = mAttachHandler;
98
99 mAttachHandler = nullptr;
100 handler(OT_ERROR_NONE, mAttachDelayMs);
101 }
102 else
103 {
104 otOperationalDataset emptyDataset = {};
105 otError error =
106 otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, mAttachPendingDatasetTlvs.mTlvs,
107 mAttachPendingDatasetTlvs.mLength, MgmtSetResponseHandler, this);
108 if (error != OT_ERROR_NONE)
109 {
110 AttachHandler handler = mAttachHandler;
111
112 mAttachHandler = nullptr;
113 mAttachPendingDatasetTlvs = {};
114 handler(error, 0);
115 }
116 }
117 }
118 else if (mJoinerHandler != nullptr)
119 {
120 mJoinerHandler(OT_ERROR_NONE);
121 mJoinerHandler = nullptr;
122 }
123 }
124 }
125
126 if (aFlags & OT_CHANGED_ACTIVE_DATASET)
127 {
128 ActiveDatasetChangedCallback();
129 }
130 }
131
ActiveDatasetChangedCallback()132 void ThreadHelper::ActiveDatasetChangedCallback()
133 {
134 otError error;
135 otOperationalDatasetTlvs datasetTlvs;
136
137 SuccessOrExit(error = otDatasetGetActiveTlvs(mInstance, &datasetTlvs));
138
139 for (const auto &handler : mActiveDatasetChangeHandlers)
140 {
141 handler(datasetTlvs);
142 }
143
144 exit:
145 if (error != OT_ERROR_NONE)
146 {
147 otbrLogWarning("Error handling active dataset change: %s", otThreadErrorToString(error));
148 }
149 }
150
151 #if OTBR_ENABLE_DBUS_SERVER
OnUpdateMeshCopTxt(std::map<std::string,std::vector<uint8_t>> aUpdate)152 void ThreadHelper::OnUpdateMeshCopTxt(std::map<std::string, std::vector<uint8_t>> aUpdate)
153 {
154 if (mUpdateMeshCopTxtHandler)
155 {
156 mUpdateMeshCopTxtHandler(std::move(aUpdate));
157 }
158 else
159 {
160 otbrLogErr("No UpdateMeshCopTxtHandler");
161 }
162 }
163 #endif
164
AddDeviceRoleHandler(DeviceRoleHandler aHandler)165 void ThreadHelper::AddDeviceRoleHandler(DeviceRoleHandler aHandler)
166 {
167 mDeviceRoleHandlers.emplace_back(aHandler);
168 }
169
Scan(ScanHandler aHandler)170 void ThreadHelper::Scan(ScanHandler aHandler)
171 {
172 otError error = OT_ERROR_NONE;
173
174 VerifyOrExit(aHandler != nullptr);
175 mScanHandler = aHandler;
176 mScanResults.clear();
177
178 error =
179 otLinkActiveScan(mInstance, /*scanChannels =*/0, /*scanDuration=*/0, &ThreadHelper::ActiveScanHandler, this);
180
181 exit:
182 if (error != OT_ERROR_NONE)
183 {
184 if (aHandler)
185 {
186 mScanHandler(error, {});
187 }
188 mScanHandler = nullptr;
189 }
190 }
191
EnergyScan(uint32_t aScanDuration,EnergyScanHandler aHandler)192 void ThreadHelper::EnergyScan(uint32_t aScanDuration, EnergyScanHandler aHandler)
193 {
194 otError error = OT_ERROR_NONE;
195 uint32_t preferredChannels = otPlatRadioGetPreferredChannelMask(mInstance);
196
197 VerifyOrExit(aHandler != nullptr, error = OT_ERROR_BUSY);
198 VerifyOrExit(aScanDuration < UINT16_MAX, error = OT_ERROR_INVALID_ARGS);
199 mEnergyScanHandler = aHandler;
200 mEnergyScanResults.clear();
201
202 error = otLinkEnergyScan(mInstance, preferredChannels, static_cast<uint16_t>(aScanDuration),
203 &ThreadHelper::EnergyScanCallback, this);
204
205 exit:
206 if (error != OT_ERROR_NONE)
207 {
208 if (aHandler)
209 {
210 mEnergyScanHandler(error, {});
211 }
212 mEnergyScanHandler = nullptr;
213 }
214 }
215
RandomFill(void * aBuf,size_t size)216 void ThreadHelper::RandomFill(void *aBuf, size_t size)
217 {
218 std::uniform_int_distribution<> dist(0, UINT8_MAX);
219 uint8_t * buf = static_cast<uint8_t *>(aBuf);
220
221 for (size_t i = 0; i < size; i++)
222 {
223 buf[i] = static_cast<uint8_t>(dist(mRandomDevice));
224 }
225 }
226
ActiveScanHandler(otActiveScanResult * aResult,void * aThreadHelper)227 void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper)
228 {
229 ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
230
231 helper->ActiveScanHandler(aResult);
232 }
233
ActiveScanHandler(otActiveScanResult * aResult)234 void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult)
235 {
236 if (aResult == nullptr)
237 {
238 if (mScanHandler != nullptr)
239 {
240 mScanHandler(OT_ERROR_NONE, mScanResults);
241 }
242 }
243 else
244 {
245 mScanResults.push_back(*aResult);
246 }
247 }
248
EnergyScanCallback(otEnergyScanResult * aResult,void * aThreadHelper)249 void ThreadHelper::EnergyScanCallback(otEnergyScanResult *aResult, void *aThreadHelper)
250 {
251 ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
252
253 helper->EnergyScanCallback(aResult);
254 }
255
EnergyScanCallback(otEnergyScanResult * aResult)256 void ThreadHelper::EnergyScanCallback(otEnergyScanResult *aResult)
257 {
258 if (aResult == nullptr)
259 {
260 if (mEnergyScanHandler != nullptr)
261 {
262 mEnergyScanHandler(OT_ERROR_NONE, mEnergyScanResults);
263 }
264 }
265 else
266 {
267 mEnergyScanResults.push_back(*aResult);
268 }
269 }
270
RandomChannelFromChannelMask(uint32_t aChannelMask)271 uint8_t ThreadHelper::RandomChannelFromChannelMask(uint32_t aChannelMask)
272 {
273 // 8 bit per byte
274 constexpr uint8_t kNumChannels = sizeof(aChannelMask) * 8;
275 uint8_t channels[kNumChannels];
276 uint8_t numValidChannels = 0;
277
278 for (uint8_t i = 0; i < kNumChannels; i++)
279 {
280 if (aChannelMask & (1 << i))
281 {
282 channels[numValidChannels++] = i;
283 }
284 }
285
286 return channels[std::uniform_int_distribution<unsigned int>(0, numValidChannels - 1)(mRandomDevice)];
287 }
288
ToOtExtendedPanId(uint64_t aExtPanId)289 static otExtendedPanId ToOtExtendedPanId(uint64_t aExtPanId)
290 {
291 otExtendedPanId extPanId;
292 uint64_t mask = UINT8_MAX;
293
294 for (size_t i = 0; i < sizeof(uint64_t); i++)
295 {
296 extPanId.m8[i] = static_cast<uint8_t>((aExtPanId >> ((sizeof(uint64_t) - i - 1) * 8)) & mask);
297 }
298
299 return extPanId;
300 }
301
Attach(const std::string & aNetworkName,uint16_t aPanId,uint64_t aExtPanId,const std::vector<uint8_t> & aNetworkKey,const std::vector<uint8_t> & aPSKc,uint32_t aChannelMask,AttachHandler aHandler)302 void ThreadHelper::Attach(const std::string & aNetworkName,
303 uint16_t aPanId,
304 uint64_t aExtPanId,
305 const std::vector<uint8_t> &aNetworkKey,
306 const std::vector<uint8_t> &aPSKc,
307 uint32_t aChannelMask,
308 AttachHandler aHandler)
309
310 {
311 otError error = OT_ERROR_NONE;
312 otExtendedPanId extPanId;
313 otNetworkKey networkKey;
314 otPskc pskc;
315 uint32_t channelMask;
316 uint8_t channel;
317
318 VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS);
319 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
320 VerifyOrExit(aNetworkKey.empty() || aNetworkKey.size() == sizeof(networkKey.m8), error = OT_ERROR_INVALID_ARGS);
321 VerifyOrExit(aPSKc.empty() || aPSKc.size() == sizeof(pskc.m8), error = OT_ERROR_INVALID_ARGS);
322 VerifyOrExit(aChannelMask != 0, error = OT_ERROR_INVALID_ARGS);
323
324 while (aPanId == UINT16_MAX)
325 {
326 RandomFill(&aPanId, sizeof(aPanId));
327 }
328
329 if (aExtPanId != UINT64_MAX)
330 {
331 extPanId = ToOtExtendedPanId(aExtPanId);
332 }
333 else
334 {
335 *reinterpret_cast<uint64_t *>(&extPanId) = UINT64_MAX;
336
337 while (*reinterpret_cast<uint64_t *>(&extPanId) == UINT64_MAX)
338 {
339 RandomFill(extPanId.m8, sizeof(extPanId.m8));
340 }
341 }
342
343 if (!aNetworkKey.empty())
344 {
345 memcpy(networkKey.m8, &aNetworkKey[0], sizeof(networkKey.m8));
346 }
347 else
348 {
349 RandomFill(networkKey.m8, sizeof(networkKey.m8));
350 }
351
352 if (!aPSKc.empty())
353 {
354 memcpy(pskc.m8, &aPSKc[0], sizeof(pskc.m8));
355 }
356 else
357 {
358 RandomFill(pskc.m8, sizeof(pskc.m8));
359 }
360
361 if (!otIp6IsEnabled(mInstance))
362 {
363 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
364 }
365
366 SuccessOrExit(error = otThreadSetNetworkName(mInstance, aNetworkName.c_str()));
367 SuccessOrExit(error = otLinkSetPanId(mInstance, aPanId));
368 SuccessOrExit(error = otThreadSetExtendedPanId(mInstance, &extPanId));
369 SuccessOrExit(error = otThreadSetNetworkKey(mInstance, &networkKey));
370
371 channelMask = otPlatRadioGetPreferredChannelMask(mInstance) & aChannelMask;
372
373 if (channelMask == 0)
374 {
375 channelMask = otLinkGetSupportedChannelMask(mInstance) & aChannelMask;
376 }
377 VerifyOrExit(channelMask != 0, otbrLogWarning("Invalid channel mask"), error = OT_ERROR_INVALID_ARGS);
378
379 channel = RandomChannelFromChannelMask(channelMask);
380 SuccessOrExit(otLinkSetChannel(mInstance, channel));
381
382 SuccessOrExit(error = otThreadSetPskc(mInstance, &pskc));
383
384 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
385 mAttachDelayMs = 0;
386 mAttachHandler = aHandler;
387
388 exit:
389 if (error != OT_ERROR_NONE)
390 {
391 if (aHandler)
392 {
393 aHandler(error, 0);
394 }
395 }
396 }
397
Attach(AttachHandler aHandler)398 void ThreadHelper::Attach(AttachHandler aHandler)
399 {
400 otError error = OT_ERROR_NONE;
401
402 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
403
404 if (!otIp6IsEnabled(mInstance))
405 {
406 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
407 }
408 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
409 mAttachHandler = aHandler;
410
411 exit:
412 if (error != OT_ERROR_NONE)
413 {
414 if (aHandler)
415 {
416 aHandler(error, 0);
417 }
418 }
419 }
420
Detach(void)421 otError ThreadHelper::Detach(void)
422 {
423 otError error = OT_ERROR_NONE;
424
425 SuccessOrExit(error = otThreadSetEnabled(mInstance, false));
426 SuccessOrExit(error = otIp6SetEnabled(mInstance, false));
427
428 exit:
429 return error;
430 }
431
Reset(void)432 otError ThreadHelper::Reset(void)
433 {
434 mDeviceRoleHandlers.clear();
435 otInstanceReset(mInstance);
436
437 return OT_ERROR_NONE;
438 }
439
JoinerStart(const std::string & aPskd,const std::string & aProvisioningUrl,const std::string & aVendorName,const std::string & aVendorModel,const std::string & aVendorSwVersion,const std::string & aVendorData,ResultHandler aHandler)440 void ThreadHelper::JoinerStart(const std::string &aPskd,
441 const std::string &aProvisioningUrl,
442 const std::string &aVendorName,
443 const std::string &aVendorModel,
444 const std::string &aVendorSwVersion,
445 const std::string &aVendorData,
446 ResultHandler aHandler)
447 {
448 otError error = OT_ERROR_NONE;
449
450 VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS);
451 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
452
453 if (!otIp6IsEnabled(mInstance))
454 {
455 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
456 }
457 SuccessOrExit(error = otJoinerStart(mInstance, aPskd.c_str(), aProvisioningUrl.c_str(), aVendorName.c_str(),
458 aVendorModel.c_str(), aVendorSwVersion.c_str(), aVendorData.c_str(),
459 JoinerCallback, this));
460 mJoinerHandler = aHandler;
461
462 exit:
463 if (error != OT_ERROR_NONE)
464 {
465 if (aHandler)
466 {
467 aHandler(error);
468 }
469 }
470 }
471
JoinerCallback(otError aError,void * aThreadHelper)472 void ThreadHelper::JoinerCallback(otError aError, void *aThreadHelper)
473 {
474 ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
475
476 helper->JoinerCallback(aError);
477 }
478
JoinerCallback(otError aError)479 void ThreadHelper::JoinerCallback(otError aError)
480 {
481 if (aError != OT_ERROR_NONE)
482 {
483 otbrLogWarning("Failed to join Thread network: %s", otThreadErrorToString(aError));
484 mJoinerHandler(aError);
485 mJoinerHandler = nullptr;
486 }
487 else
488 {
489 LogOpenThreadResult("Start Thread network", otThreadSetEnabled(mInstance, true));
490 }
491 }
492
TryResumeNetwork(void)493 otError ThreadHelper::TryResumeNetwork(void)
494 {
495 otError error = OT_ERROR_NONE;
496
497 if (otLinkGetPanId(mInstance) != UINT16_MAX && otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED)
498 {
499 if (!otIp6IsEnabled(mInstance))
500 {
501 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
502 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
503 }
504 }
505
506 exit:
507 if (error != OT_ERROR_NONE)
508 {
509 (void)otIp6SetEnabled(mInstance, false);
510 }
511
512 return error;
513 }
514
LogOpenThreadResult(const char * aAction,otError aError)515 void ThreadHelper::LogOpenThreadResult(const char *aAction, otError aError)
516 {
517 if (aError == OT_ERROR_NONE)
518 {
519 otbrLogInfo("%s: %s", aAction, otThreadErrorToString(aError));
520 }
521 else
522 {
523 otbrLogWarning("%s: %s", aAction, otThreadErrorToString(aError));
524 }
525 }
526
AttachAllNodesTo(const std::vector<uint8_t> & aDatasetTlvs,AttachHandler aHandler)527 void ThreadHelper::AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, AttachHandler aHandler)
528 {
529 constexpr uint32_t kDelayTimerMilliseconds = 300 * 1000;
530
531 otError error = OT_ERROR_NONE;
532 otOperationalDatasetTlvs datasetTlvs;
533 otOperationalDataset dataset;
534 otOperationalDataset emptyDataset{};
535 otDeviceRole role = otThreadGetDeviceRole(mInstance);
536 Tlv * tlv;
537 uint64_t pendingTimestamp = 0;
538 timespec currentTime;
539
540 assert(aHandler != nullptr);
541 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_BUSY);
542
543 VerifyOrExit(aDatasetTlvs.size() <= sizeof(datasetTlvs.mTlvs), error = OT_ERROR_INVALID_ARGS);
544 std::copy(aDatasetTlvs.begin(), aDatasetTlvs.end(), datasetTlvs.mTlvs);
545 datasetTlvs.mLength = aDatasetTlvs.size();
546
547 SuccessOrExit(error = otDatasetParseTlvs(&datasetTlvs, &dataset));
548 VerifyOrExit(dataset.mComponents.mIsActiveTimestampPresent, error = OT_ERROR_INVALID_ARGS);
549 VerifyOrExit(dataset.mComponents.mIsNetworkKeyPresent, error = OT_ERROR_INVALID_ARGS);
550 VerifyOrExit(dataset.mComponents.mIsNetworkNamePresent, error = OT_ERROR_INVALID_ARGS);
551 VerifyOrExit(dataset.mComponents.mIsExtendedPanIdPresent, error = OT_ERROR_INVALID_ARGS);
552 VerifyOrExit(dataset.mComponents.mIsMeshLocalPrefixPresent, error = OT_ERROR_INVALID_ARGS);
553 VerifyOrExit(dataset.mComponents.mIsPanIdPresent, error = OT_ERROR_INVALID_ARGS);
554 VerifyOrExit(dataset.mComponents.mIsChannelPresent, error = OT_ERROR_INVALID_ARGS);
555 VerifyOrExit(dataset.mComponents.mIsPskcPresent, error = OT_ERROR_INVALID_ARGS);
556 VerifyOrExit(dataset.mComponents.mIsSecurityPolicyPresent, error = OT_ERROR_INVALID_ARGS);
557 VerifyOrExit(dataset.mComponents.mIsChannelMaskPresent, error = OT_ERROR_INVALID_ARGS);
558
559 VerifyOrExit(FindTlv(OT_MESHCOP_TLV_PENDINGTIMESTAMP, datasetTlvs.mTlvs, datasetTlvs.mLength) == nullptr &&
560 FindTlv(OT_MESHCOP_TLV_DELAYTIMER, datasetTlvs.mTlvs, datasetTlvs.mLength) == nullptr,
561 error = OT_ERROR_INVALID_ARGS);
562
563 // There must be sufficient space for a Pending Timestamp TLV and a Delay Timer TLV.
564 VerifyOrExit(
565 static_cast<int>(datasetTlvs.mLength +
566 (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t)) // Pending Timestamp TLV (10 bytes)
567 + (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t))) // Delay Timer TLV (6 bytes)
568 <= int{sizeof(datasetTlvs.mTlvs)},
569 error = OT_ERROR_INVALID_ARGS);
570
571 tlv = reinterpret_cast<Tlv *>(datasetTlvs.mTlvs + datasetTlvs.mLength);
572 tlv->SetType(OT_MESHCOP_TLV_PENDINGTIMESTAMP);
573 clock_gettime(CLOCK_REALTIME, ¤tTime);
574 pendingTimestamp |= (static_cast<uint64_t>(currentTime.tv_sec) << 16);
575 pendingTimestamp |= (((static_cast<uint64_t>(currentTime.tv_nsec) * 32768 / 1000000000) & 0x7fff) << 1);
576 tlv->SetValue(pendingTimestamp);
577
578 tlv = tlv->GetNext();
579 tlv->SetType(OT_MESHCOP_TLV_DELAYTIMER);
580 tlv->SetValue(kDelayTimerMilliseconds);
581
582 datasetTlvs.mLength = reinterpret_cast<uint8_t *>(tlv->GetNext()) - datasetTlvs.mTlvs;
583
584 assert(datasetTlvs.mLength > 0);
585
586 if (role == OT_DEVICE_ROLE_DISABLED || role == OT_DEVICE_ROLE_DETACHED)
587 {
588 otOperationalDataset existingDataset;
589 bool hasActiveDataset;
590
591 error = otDatasetGetActive(mInstance, &existingDataset);
592 VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_NOT_FOUND);
593
594 hasActiveDataset = (error == OT_ERROR_NONE);
595
596 if (!hasActiveDataset)
597 {
598 SuccessOrExit(error = otDatasetSetActiveTlvs(mInstance, &datasetTlvs));
599 }
600
601 if (!otIp6IsEnabled(mInstance))
602 {
603 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
604 }
605 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
606
607 if (hasActiveDataset)
608 {
609 mAttachDelayMs = kDelayTimerMilliseconds;
610 mAttachPendingDatasetTlvs = datasetTlvs;
611 }
612 else
613 {
614 mAttachDelayMs = 0;
615 mAttachPendingDatasetTlvs = {};
616 }
617 mAttachHandler = aHandler;
618 ExitNow();
619 }
620
621 SuccessOrExit(error = otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, datasetTlvs.mTlvs, datasetTlvs.mLength,
622 MgmtSetResponseHandler, this));
623 mAttachDelayMs = kDelayTimerMilliseconds;
624 mAttachHandler = aHandler;
625
626 exit:
627 if (error != OT_ERROR_NONE)
628 {
629 aHandler(error, 0);
630 }
631 }
632
MgmtSetResponseHandler(otError aResult,void * aContext)633 void ThreadHelper::MgmtSetResponseHandler(otError aResult, void *aContext)
634 {
635 static_cast<ThreadHelper *>(aContext)->MgmtSetResponseHandler(aResult);
636 }
637
MgmtSetResponseHandler(otError aResult)638 void ThreadHelper::MgmtSetResponseHandler(otError aResult)
639 {
640 AttachHandler handler;
641 int64_t attachDelayMs;
642
643 LogOpenThreadResult("MgmtSetResponseHandler()", aResult);
644
645 assert(mAttachHandler != nullptr);
646
647 switch (aResult)
648 {
649 case OT_ERROR_NONE:
650 case OT_ERROR_REJECTED:
651 break;
652 default:
653 aResult = OT_ERROR_FAILED;
654 break;
655 }
656
657 attachDelayMs = mAttachDelayMs;
658 handler = mAttachHandler;
659 mAttachDelayMs = 0;
660 mAttachHandler = nullptr;
661 mAttachPendingDatasetTlvs = {};
662 if (aResult == OT_ERROR_NONE)
663 {
664 handler(aResult, attachDelayMs);
665 }
666 else
667 {
668 handler(aResult, 0);
669 }
670 }
671
672 #if OTBR_ENABLE_UNSECURE_JOIN
PermitUnsecureJoin(uint16_t aPort,uint32_t aSeconds)673 otError ThreadHelper::PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds)
674 {
675 otError error = OT_ERROR_NONE;
676 otExtAddress steeringData;
677
678 // 0xff to allow all devices to join
679 memset(&steeringData.m8, 0xff, sizeof(steeringData.m8));
680 SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, aPort));
681 otThreadSetSteeringData(mInstance, &steeringData);
682
683 if (aSeconds > 0)
684 {
685 auto delay = Milliseconds(aSeconds * 1000);
686
687 ++mUnsecurePortRefCounter[aPort];
688
689 mNcp->PostTimerTask(delay, [this, aPort]() {
690 assert(mUnsecurePortRefCounter.find(aPort) != mUnsecurePortRefCounter.end());
691 assert(mUnsecurePortRefCounter[aPort] > 0);
692
693 if (--mUnsecurePortRefCounter[aPort] == 0)
694 {
695 otExtAddress noneAddress;
696
697 // 0 to clean steering data
698 memset(&noneAddress.m8, 0, sizeof(noneAddress.m8));
699 (void)otIp6RemoveUnsecurePort(mInstance, aPort);
700 otThreadSetSteeringData(mInstance, &noneAddress);
701 mUnsecurePortRefCounter.erase(aPort);
702 }
703 });
704 }
705 else
706 {
707 otExtAddress noneAddress;
708
709 memset(&noneAddress.m8, 0, sizeof(noneAddress.m8));
710 (void)otIp6RemoveUnsecurePort(mInstance, aPort);
711 otThreadSetSteeringData(mInstance, &noneAddress);
712 }
713
714 exit:
715 return error;
716 }
717 #endif
718
AddActiveDatasetChangeHandler(DatasetChangeHandler aHandler)719 void ThreadHelper::AddActiveDatasetChangeHandler(DatasetChangeHandler aHandler)
720 {
721 mActiveDatasetChangeHandlers.push_back(std::move(aHandler));
722 }
723
724 } // namespace agent
725 } // namespace otbr
726