2 * Copyright (c) 2020, The OpenThread Authors.
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.
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.
29 #include "agent/thread_helper.hpp"
37 #include <openthread/border_router.h>
38 #include <openthread/channel_manager.h>
39 #include <openthread/jam_detection.h>
40 #include <openthread/joiner.h>
41 #include <openthread/thread_ftd.h>
42 #include <openthread/platform/radio.h>
44 #include "agent/ncp_openthread.hpp"
45 #include "common/byteswap.hpp"
46 #include "common/code_utils.hpp"
47 #include "common/logging.hpp"
52 ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp)
53 : mInstance(aInstance)
58 void ThreadHelper::StateChangedCallback(otChangedFlags aFlags)
60 if (aFlags & OT_CHANGED_THREAD_ROLE)
62 otDeviceRole role = otThreadGetDeviceRole(mInstance);
64 for (const auto &handler : mDeviceRoleHandlers)
69 if (role != OT_DEVICE_ROLE_DISABLED && role != OT_DEVICE_ROLE_DETACHED)
71 if (mAttachHandler != nullptr)
73 mAttachHandler(OT_ERROR_NONE);
74 mAttachHandler = nullptr;
76 else if (mJoinerHandler != nullptr)
78 mJoinerHandler(OT_ERROR_NONE);
79 mJoinerHandler = nullptr;
85 void ThreadHelper::AddDeviceRoleHandler(DeviceRoleHandler aHandler)
87 mDeviceRoleHandlers.emplace_back(aHandler);
90 void ThreadHelper::Scan(ScanHandler aHandler)
92 otError error = OT_ERROR_NONE;
94 VerifyOrExit(aHandler != nullptr);
95 mScanHandler = aHandler;
99 otLinkActiveScan(mInstance, /*scanChannels =*/0, /*scanDuration=*/0, &ThreadHelper::sActiveScanHandler, this);
102 if (error != OT_ERROR_NONE)
106 mScanHandler(error, {});
108 mScanHandler = nullptr;
112 void ThreadHelper::RandomFill(void *aBuf, size_t size)
114 std::uniform_int_distribution<> dist(0, UINT8_MAX);
115 uint8_t * buf = static_cast<uint8_t *>(aBuf);
117 for (size_t i = 0; i < size; i++)
119 buf[i] = static_cast<uint8_t>(dist(mRandomDevice));
123 void ThreadHelper::sActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper)
125 ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
127 helper->ActiveScanHandler(aResult);
130 void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult)
132 if (aResult == nullptr)
134 if (mScanHandler != nullptr)
136 mScanHandler(OT_ERROR_NONE, mScanResults);
141 mScanResults.push_back(*aResult);
145 uint8_t ThreadHelper::RandomChannelFromChannelMask(uint32_t aChannelMask)
148 constexpr uint8_t kNumChannels = sizeof(aChannelMask) * 8;
149 uint8_t channels[kNumChannels];
150 uint8_t numValidChannels = 0;
152 for (uint8_t i = 0; i < kNumChannels; i++)
154 if (aChannelMask & (1 << i))
156 channels[numValidChannels++] = i;
160 return channels[std::uniform_int_distribution<unsigned int>(0, numValidChannels - 1)(mRandomDevice)];
163 static otExtendedPanId ToOtExtendedPanId(uint64_t aExtPanId)
165 otExtendedPanId extPanId;
166 uint64_t mask = UINT8_MAX;
168 for (size_t i = 0; i < sizeof(uint64_t); i++)
170 extPanId.m8[i] = static_cast<uint8_t>((aExtPanId >> ((sizeof(uint64_t) - i - 1) * 8)) & mask);
176 void ThreadHelper::Attach(const std::string & aNetworkName,
179 const std::vector<uint8_t> &aMasterKey,
180 const std::vector<uint8_t> &aPSKc,
181 uint32_t aChannelMask,
182 ResultHandler aHandler)
185 otError error = OT_ERROR_NONE;
186 otExtendedPanId extPanId;
187 otMasterKey masterKey;
189 uint32_t channelMask;
192 VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS);
193 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
194 mAttachHandler = aHandler;
195 VerifyOrExit(aMasterKey.empty() || aMasterKey.size() == sizeof(masterKey.m8), error = OT_ERROR_INVALID_ARGS);
196 VerifyOrExit(aPSKc.empty() || aPSKc.size() == sizeof(pskc.m8), error = OT_ERROR_INVALID_ARGS);
197 VerifyOrExit(aChannelMask != 0, error = OT_ERROR_INVALID_ARGS);
199 while (aPanId == UINT16_MAX)
201 RandomFill(&aPanId, sizeof(aPanId));
204 if (aExtPanId != UINT64_MAX)
206 extPanId = ToOtExtendedPanId(aExtPanId);
210 *reinterpret_cast<uint64_t *>(&extPanId) = UINT64_MAX;
212 while (*reinterpret_cast<uint64_t *>(&extPanId) == UINT64_MAX)
214 RandomFill(extPanId.m8, sizeof(extPanId.m8));
218 if (!aMasterKey.empty())
220 memcpy(masterKey.m8, &aMasterKey[0], sizeof(masterKey.m8));
224 RandomFill(masterKey.m8, sizeof(masterKey.m8));
229 memcpy(pskc.m8, &aPSKc[0], sizeof(pskc.m8));
233 RandomFill(pskc.m8, sizeof(pskc.m8));
236 if (!otIp6IsEnabled(mInstance))
238 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
241 SuccessOrExit(error = otThreadSetNetworkName(mInstance, aNetworkName.c_str()));
242 SuccessOrExit(error = otLinkSetPanId(mInstance, aPanId));
243 SuccessOrExit(error = otThreadSetExtendedPanId(mInstance, &extPanId));
244 SuccessOrExit(error = otThreadSetMasterKey(mInstance, &masterKey));
246 channelMask = otPlatRadioGetPreferredChannelMask(mInstance) & aChannelMask;
248 if (channelMask == 0)
250 channelMask = otLinkGetSupportedChannelMask(mInstance) & aChannelMask;
252 VerifyOrExit(channelMask != 0, otbrLog(OTBR_LOG_WARNING, "Invalid channel mask"), error = OT_ERROR_INVALID_ARGS);
254 channel = RandomChannelFromChannelMask(channelMask);
255 SuccessOrExit(otLinkSetChannel(mInstance, channel));
257 SuccessOrExit(error = otThreadSetPskc(mInstance, &pskc));
259 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
261 if (error != OT_ERROR_NONE)
267 mAttachHandler = nullptr;
271 void ThreadHelper::Attach(ResultHandler aHandler)
273 otError error = OT_ERROR_NONE;
275 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
276 mAttachHandler = aHandler;
278 if (!otIp6IsEnabled(mInstance))
280 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
282 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
285 if (error != OT_ERROR_NONE)
291 mAttachHandler = nullptr;
295 otError ThreadHelper::Reset(void)
297 mDeviceRoleHandlers.clear();
298 otInstanceReset(mInstance);
300 return OT_ERROR_NONE;
303 void ThreadHelper::JoinerStart(const std::string &aPskd,
304 const std::string &aProvisioningUrl,
305 const std::string &aVendorName,
306 const std::string &aVendorModel,
307 const std::string &aVendorSwVersion,
308 const std::string &aVendorData,
309 ResultHandler aHandler)
311 otError error = OT_ERROR_NONE;
313 VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS);
314 VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
315 mJoinerHandler = aHandler;
317 if (!otIp6IsEnabled(mInstance))
319 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
321 error = otJoinerStart(mInstance, aPskd.c_str(), aProvisioningUrl.c_str(), aVendorName.c_str(), aVendorModel.c_str(),
322 aVendorSwVersion.c_str(), aVendorData.c_str(), sJoinerCallback, this);
324 if (error != OT_ERROR_NONE)
330 mJoinerHandler = nullptr;
334 void ThreadHelper::sJoinerCallback(otError aError, void *aThreadHelper)
336 ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
338 helper->JoinerCallback(aError);
341 void ThreadHelper::JoinerCallback(otError aError)
343 if (aError != OT_ERROR_NONE)
345 otbrLog(OTBR_LOG_WARNING, "Failed to join Thread network: %s", otThreadErrorToString(aError));
346 mJoinerHandler(aError);
347 mJoinerHandler = nullptr;
351 LogOpenThreadResult("Start Thread network", otThreadSetEnabled(mInstance, true));
355 otError ThreadHelper::TryResumeNetwork(void)
357 otError error = OT_ERROR_NONE;
359 if (otLinkGetPanId(mInstance) != UINT16_MAX && otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED)
361 if (!otIp6IsEnabled(mInstance))
363 SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
364 SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
369 if (error != OT_ERROR_NONE)
371 (void)otIp6SetEnabled(mInstance, false);
377 #if OTBR_ENABLE_UNSECURE_JOIN
378 otError ThreadHelper::PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds)
380 otError error = OT_ERROR_NONE;
381 otExtAddress steeringData;
383 // 0xff to allow all devices to join
384 memset(&steeringData.m8, 0xff, sizeof(steeringData.m8));
385 SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, aPort));
386 otThreadSetSteeringData(mInstance, &steeringData);
390 auto triggerTime = std::chrono::steady_clock::now() + std::chrono::seconds(aSeconds);
392 if (mUnsecurePortCloseTime.find(aPort) == mUnsecurePortCloseTime.end() ||
393 mUnsecurePortCloseTime[aPort] < triggerTime)
395 mUnsecurePortCloseTime[aPort] = triggerTime;
398 mNcp->PostTimerTask(triggerTime, [this, aPort]() {
399 auto now = std::chrono::steady_clock::now();
400 otExtAddress noneAddress;
402 // 0 to clean steering data
403 memset(&noneAddress.m8, 0, sizeof(noneAddress.m8));
404 if (now >= mUnsecurePortCloseTime[aPort])
406 (void)otIp6RemoveUnsecurePort(mInstance, aPort);
407 otThreadSetSteeringData(mInstance, &noneAddress);
408 mUnsecurePortCloseTime.erase(aPort);
414 otExtAddress noneAddress;
416 memset(&noneAddress.m8, 0, sizeof(noneAddress.m8));
417 (void)otIp6RemoveUnsecurePort(mInstance, aPort);
418 otThreadSetSteeringData(mInstance, &noneAddress);