Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / agent / thread_helper.cpp
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 #include "agent/thread_helper.hpp"
30
31 #include <assert.h>
32 #include <limits.h>
33 #include <string.h>
34
35 #include <string>
36
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>
43
44 #include "agent/ncp_openthread.hpp"
45 #include "common/byteswap.hpp"
46 #include "common/code_utils.hpp"
47 #include "common/logging.hpp"
48
49 namespace otbr {
50 namespace agent {
51
52 ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp)
53     : mInstance(aInstance)
54     , mNcp(aNcp)
55 {
56 }
57
58 void ThreadHelper::StateChangedCallback(otChangedFlags aFlags)
59 {
60     if (aFlags & OT_CHANGED_THREAD_ROLE)
61     {
62         otDeviceRole role = otThreadGetDeviceRole(mInstance);
63
64         for (const auto &handler : mDeviceRoleHandlers)
65         {
66             handler(role);
67         }
68
69         if (role != OT_DEVICE_ROLE_DISABLED && role != OT_DEVICE_ROLE_DETACHED)
70         {
71             if (mAttachHandler != nullptr)
72             {
73                 mAttachHandler(OT_ERROR_NONE);
74                 mAttachHandler = nullptr;
75             }
76             else if (mJoinerHandler != nullptr)
77             {
78                 mJoinerHandler(OT_ERROR_NONE);
79                 mJoinerHandler = nullptr;
80             }
81         }
82     }
83 }
84
85 void ThreadHelper::AddDeviceRoleHandler(DeviceRoleHandler aHandler)
86 {
87     mDeviceRoleHandlers.emplace_back(aHandler);
88 }
89
90 void ThreadHelper::Scan(ScanHandler aHandler)
91 {
92     otError error = OT_ERROR_NONE;
93
94     VerifyOrExit(aHandler != nullptr);
95     mScanHandler = aHandler;
96     mScanResults.clear();
97
98     error =
99         otLinkActiveScan(mInstance, /*scanChannels =*/0, /*scanDuration=*/0, &ThreadHelper::sActiveScanHandler, this);
100
101 exit:
102     if (error != OT_ERROR_NONE)
103     {
104         if (aHandler)
105         {
106             mScanHandler(error, {});
107         }
108         mScanHandler = nullptr;
109     }
110 }
111
112 void ThreadHelper::RandomFill(void *aBuf, size_t size)
113 {
114     std::uniform_int_distribution<> dist(0, UINT8_MAX);
115     uint8_t *                       buf = static_cast<uint8_t *>(aBuf);
116
117     for (size_t i = 0; i < size; i++)
118     {
119         buf[i] = static_cast<uint8_t>(dist(mRandomDevice));
120     }
121 }
122
123 void ThreadHelper::sActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper)
124 {
125     ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
126
127     helper->ActiveScanHandler(aResult);
128 }
129
130 void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult)
131 {
132     if (aResult == nullptr)
133     {
134         if (mScanHandler != nullptr)
135         {
136             mScanHandler(OT_ERROR_NONE, mScanResults);
137         }
138     }
139     else
140     {
141         mScanResults.push_back(*aResult);
142     }
143 }
144
145 uint8_t ThreadHelper::RandomChannelFromChannelMask(uint32_t aChannelMask)
146 {
147     // 8 bit per byte
148     constexpr uint8_t kNumChannels = sizeof(aChannelMask) * 8;
149     uint8_t           channels[kNumChannels];
150     uint8_t           numValidChannels = 0;
151
152     for (uint8_t i = 0; i < kNumChannels; i++)
153     {
154         if (aChannelMask & (1 << i))
155         {
156             channels[numValidChannels++] = i;
157         }
158     }
159
160     return channels[std::uniform_int_distribution<unsigned int>(0, numValidChannels - 1)(mRandomDevice)];
161 }
162
163 static otExtendedPanId ToOtExtendedPanId(uint64_t aExtPanId)
164 {
165     otExtendedPanId extPanId;
166     uint64_t        mask = UINT8_MAX;
167
168     for (size_t i = 0; i < sizeof(uint64_t); i++)
169     {
170         extPanId.m8[i] = static_cast<uint8_t>((aExtPanId >> ((sizeof(uint64_t) - i - 1) * 8)) & mask);
171     }
172
173     return extPanId;
174 }
175
176 void ThreadHelper::Attach(const std::string &         aNetworkName,
177                           uint16_t                    aPanId,
178                           uint64_t                    aExtPanId,
179                           const std::vector<uint8_t> &aMasterKey,
180                           const std::vector<uint8_t> &aPSKc,
181                           uint32_t                    aChannelMask,
182                           ResultHandler               aHandler)
183
184 {
185     otError         error = OT_ERROR_NONE;
186     otExtendedPanId extPanId;
187     otMasterKey     masterKey;
188     otPskc          pskc;
189     uint32_t        channelMask;
190     uint8_t         channel;
191
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);
198
199     while (aPanId == UINT16_MAX)
200     {
201         RandomFill(&aPanId, sizeof(aPanId));
202     }
203
204     if (aExtPanId != UINT64_MAX)
205     {
206         extPanId = ToOtExtendedPanId(aExtPanId);
207     }
208     else
209     {
210         *reinterpret_cast<uint64_t *>(&extPanId) = UINT64_MAX;
211
212         while (*reinterpret_cast<uint64_t *>(&extPanId) == UINT64_MAX)
213         {
214             RandomFill(extPanId.m8, sizeof(extPanId.m8));
215         }
216     }
217
218     if (!aMasterKey.empty())
219     {
220         memcpy(masterKey.m8, &aMasterKey[0], sizeof(masterKey.m8));
221     }
222     else
223     {
224         RandomFill(masterKey.m8, sizeof(masterKey.m8));
225     }
226
227     if (!aPSKc.empty())
228     {
229         memcpy(pskc.m8, &aPSKc[0], sizeof(pskc.m8));
230     }
231     else
232     {
233         RandomFill(pskc.m8, sizeof(pskc.m8));
234     }
235
236     if (!otIp6IsEnabled(mInstance))
237     {
238         SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
239     }
240
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));
245
246     channelMask = otPlatRadioGetPreferredChannelMask(mInstance) & aChannelMask;
247
248     if (channelMask == 0)
249     {
250         channelMask = otLinkGetSupportedChannelMask(mInstance) & aChannelMask;
251     }
252     VerifyOrExit(channelMask != 0, otbrLog(OTBR_LOG_WARNING, "Invalid channel mask"), error = OT_ERROR_INVALID_ARGS);
253
254     channel = RandomChannelFromChannelMask(channelMask);
255     SuccessOrExit(otLinkSetChannel(mInstance, channel));
256
257     SuccessOrExit(error = otThreadSetPskc(mInstance, &pskc));
258
259     SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
260 exit:
261     if (error != OT_ERROR_NONE)
262     {
263         if (aHandler)
264         {
265             aHandler(error);
266         }
267         mAttachHandler = nullptr;
268     }
269 }
270
271 void ThreadHelper::Attach(ResultHandler aHandler)
272 {
273     otError error = OT_ERROR_NONE;
274
275     VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
276     mAttachHandler = aHandler;
277
278     if (!otIp6IsEnabled(mInstance))
279     {
280         SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
281     }
282     SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
283
284 exit:
285     if (error != OT_ERROR_NONE)
286     {
287         if (aHandler)
288         {
289             aHandler(error);
290         }
291         mAttachHandler = nullptr;
292     }
293 }
294
295 otError ThreadHelper::Reset(void)
296 {
297     mDeviceRoleHandlers.clear();
298     otInstanceReset(mInstance);
299
300     return OT_ERROR_NONE;
301 }
302
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)
310 {
311     otError error = OT_ERROR_NONE;
312
313     VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS);
314     VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE);
315     mJoinerHandler = aHandler;
316
317     if (!otIp6IsEnabled(mInstance))
318     {
319         SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
320     }
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);
323 exit:
324     if (error != OT_ERROR_NONE)
325     {
326         if (aHandler)
327         {
328             aHandler(error);
329         }
330         mJoinerHandler = nullptr;
331     }
332 }
333
334 void ThreadHelper::sJoinerCallback(otError aError, void *aThreadHelper)
335 {
336     ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
337
338     helper->JoinerCallback(aError);
339 }
340
341 void ThreadHelper::JoinerCallback(otError aError)
342 {
343     if (aError != OT_ERROR_NONE)
344     {
345         otbrLog(OTBR_LOG_WARNING, "Failed to join Thread network: %s", otThreadErrorToString(aError));
346         mJoinerHandler(aError);
347         mJoinerHandler = nullptr;
348     }
349     else
350     {
351         LogOpenThreadResult("Start Thread network", otThreadSetEnabled(mInstance, true));
352     }
353 }
354
355 otError ThreadHelper::TryResumeNetwork(void)
356 {
357     otError error = OT_ERROR_NONE;
358
359     if (otLinkGetPanId(mInstance) != UINT16_MAX && otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED)
360     {
361         if (!otIp6IsEnabled(mInstance))
362         {
363             SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
364             SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
365         }
366     }
367
368 exit:
369     if (error != OT_ERROR_NONE)
370     {
371         (void)otIp6SetEnabled(mInstance, false);
372     }
373
374     return error;
375 }
376
377 #if OTBR_ENABLE_UNSECURE_JOIN
378 otError ThreadHelper::PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds)
379 {
380     otError      error = OT_ERROR_NONE;
381     otExtAddress steeringData;
382
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);
387
388     if (aSeconds > 0)
389     {
390         auto triggerTime = std::chrono::steady_clock::now() + std::chrono::seconds(aSeconds);
391
392         if (mUnsecurePortCloseTime.find(aPort) == mUnsecurePortCloseTime.end() ||
393             mUnsecurePortCloseTime[aPort] < triggerTime)
394         {
395             mUnsecurePortCloseTime[aPort] = triggerTime;
396         }
397
398         mNcp->PostTimerTask(triggerTime, [this, aPort]() {
399             auto         now = std::chrono::steady_clock::now();
400             otExtAddress noneAddress;
401
402             // 0 to clean steering data
403             memset(&noneAddress.m8, 0, sizeof(noneAddress.m8));
404             if (now >= mUnsecurePortCloseTime[aPort])
405             {
406                 (void)otIp6RemoveUnsecurePort(mInstance, aPort);
407                 otThreadSetSteeringData(mInstance, &noneAddress);
408                 mUnsecurePortCloseTime.erase(aPort);
409             }
410         });
411     }
412     else
413     {
414         otExtAddress noneAddress;
415
416         memset(&noneAddress.m8, 0, sizeof(noneAddress.m8));
417         (void)otIp6RemoveUnsecurePort(mInstance, aPort);
418         otThreadSetSteeringData(mInstance, &noneAddress);
419     }
420
421 exit:
422     return error;
423 }
424 #endif
425
426 } // namespace agent
427 } // namespace otbr