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 /** 30 * @file 31 * This file includes definitions for Thread helper. 32 */ 33 34 #ifndef OTBR_THREAD_HELPER_HPP_ 35 #define OTBR_THREAD_HELPER_HPP_ 36 37 #include "openthread-br/config.h" 38 39 #include <chrono> 40 #include <functional> 41 #include <map> 42 #include <random> 43 #include <string> 44 #include <vector> 45 46 #include <openthread/border_routing.h> 47 #include <openthread/instance.h> 48 #include <openthread/ip6.h> 49 #include <openthread/jam_detection.h> 50 #include <openthread/joiner.h> 51 #include <openthread/netdata.h> 52 #include <openthread/thread.h> 53 #include "mdns/mdns.hpp" 54 #if OTBR_ENABLE_TELEMETRY_DATA_API 55 #include "proto/thread_telemetry.pb.h" 56 #endif 57 58 namespace otbr { 59 namespace Ncp { 60 class RcpHost; 61 } 62 } // namespace otbr 63 64 namespace otbr { 65 namespace agent { 66 67 /** 68 * This class implements Thread helper. 69 */ 70 class ThreadHelper 71 { 72 public: 73 using DeviceRoleHandler = std::function<void(otDeviceRole)>; 74 using ScanHandler = std::function<void(otError, const std::vector<otActiveScanResult> &)>; 75 using EnergyScanHandler = std::function<void(otError, const std::vector<otEnergyScanResult> &)>; 76 using ResultHandler = std::function<void(otError)>; 77 using AttachHandler = std::function<void(otError, int64_t)>; 78 using UpdateMeshCopTxtHandler = std::function<void(std::map<std::string, std::vector<uint8_t>>)>; 79 using DatasetChangeHandler = std::function<void(const otOperationalDatasetTlvs &)>; 80 #if OTBR_ENABLE_DHCP6_PD 81 using Dhcp6PdStateCallback = std::function<void(otBorderRoutingDhcp6PdState)>; 82 #endif 83 84 /** 85 * The constructor of a Thread helper. 86 * 87 * @param[in] aInstance The Thread instance. 88 * @param[in] aHost The Thread controller. 89 */ 90 ThreadHelper(otInstance *aInstance, otbr::Ncp::RcpHost *aHost); 91 92 /** 93 * This method adds a callback for device role change. 94 * 95 * @param[in] aHandler The device role handler. 96 */ 97 void AddDeviceRoleHandler(DeviceRoleHandler aHandler); 98 99 #if OTBR_ENABLE_DHCP6_PD 100 /** 101 * This method adds a callback for DHCPv6 PD state change. 102 * 103 * @param[in] aCallback The DHCPv6 PD state change callback. 104 */ 105 void SetDhcp6PdStateCallback(Dhcp6PdStateCallback aCallback); 106 #endif 107 108 /** 109 * This method adds a callback for active dataset change. 110 * 111 * @param[in] aHandler The active dataset change handler. 112 */ 113 void AddActiveDatasetChangeHandler(DatasetChangeHandler aHandler); 114 115 /** 116 * This method permits unsecure join on port. 117 * 118 * @param[in] aPort The port number. 119 * @param[in] aSeconds The timeout to close the port, 0 for never close. 120 * 121 * @returns The error value of underlying OpenThread api calls. 122 */ 123 otError PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds); 124 125 /** 126 * This method performs a Thread network scan. 127 * 128 * @param[in] aHandler The scan result handler. 129 */ 130 void Scan(ScanHandler aHandler); 131 132 /** 133 * This method performs an IEEE 802.15.4 Energy Scan. 134 * 135 * @param[in] aScanDuration The duration for the scan, in milliseconds. 136 * @param[in] aHandler The scan result handler. 137 */ 138 void EnergyScan(uint32_t aScanDuration, EnergyScanHandler aHandler); 139 140 /** 141 * This method attaches the device to the Thread network. 142 * 143 * @note The joiner start and the attach proccesses are exclusive 144 * 145 * @param[in] aNetworkName The network name. 146 * @param[in] aPanId The pan id, UINT16_MAX for random. 147 * @param[in] aExtPanId The extended pan id, UINT64_MAX for random. 148 * @param[in] aNetworkKey The network key, empty for random. 149 * @param[in] aPSKc The pre-shared commissioner key, empty for random. 150 * @param[in] aChannelMask A bitmask for valid channels, will random select one. 151 * @param[in] aHandler The attach result handler. 152 */ 153 void Attach(const std::string &aNetworkName, 154 uint16_t aPanId, 155 uint64_t aExtPanId, 156 const std::vector<uint8_t> &aNetworkKey, 157 const std::vector<uint8_t> &aPSKc, 158 uint32_t aChannelMask, 159 AttachHandler aHandler); 160 161 /** 162 * This method detaches the device from the Thread network. 163 * 164 * @returns The error value of underlying OpenThread API calls. 165 */ 166 otError Detach(void); 167 168 /** 169 * This method attaches the device to the Thread network. 170 * 171 * @note The joiner start and the attach proccesses are exclusive, and the 172 * network parameter will be set through the active dataset. 173 * 174 * @param[in] aHandler The attach result handler. 175 */ 176 void Attach(AttachHandler aHandler); 177 178 /** 179 * This method makes all nodes in the current network attach to the network specified by the dataset TLVs. 180 * 181 * @param[in] aDatasetTlvs The dataset TLVs. 182 * @param[in] aHandler The result handler. 183 */ 184 void AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, AttachHandler aHandler); 185 186 /** 187 * This method resets the OpenThread stack. 188 * 189 * @returns The error value of underlying OpenThread api calls. 190 */ 191 otError Reset(void); 192 193 /** 194 * This method triggers a thread join process. 195 * 196 * @note The joiner start and the attach proccesses are exclusive 197 * 198 * @param[in] aPskd The pre-shared key for device. 199 * @param[in] aProvisioningUrl The provision url. 200 * @param[in] aVendorName The vendor name. 201 * @param[in] aVendorModel The vendor model. 202 * @param[in] aVendorSwVersion The vendor software version. 203 * @param[in] aVendorData The vendor custom data. 204 * @param[in] aHandler The join result handler. 205 */ 206 void JoinerStart(const std::string &aPskd, 207 const std::string &aProvisioningUrl, 208 const std::string &aVendorName, 209 const std::string &aVendorModel, 210 const std::string &aVendorSwVersion, 211 const std::string &aVendorData, 212 ResultHandler aHandler); 213 214 /** 215 * This method tries to restore the network after reboot 216 * 217 * @returns The error value of underlying OpenThread api calls. 218 */ 219 otError TryResumeNetwork(void); 220 221 /** 222 * This method returns the underlying OpenThread instance. 223 * 224 * @returns The underlying instance. 225 */ GetInstance(void)226 otInstance *GetInstance(void) 227 { 228 return mInstance; 229 } 230 231 /** 232 * This method handles OpenThread state changed notification. 233 * 234 * @param[in] aFlags A bit-field indicating specific state that has changed. See `OT_CHANGED_*` definitions. 235 */ 236 void StateChangedCallback(otChangedFlags aFlags); 237 238 #if OTBR_ENABLE_DBUS_SERVER 239 /** 240 * This method sets a callback for calls of UpdateVendorMeshCopTxtEntries D-Bus API. 241 * 242 * @param[in] aHandler The handler on MeshCoP TXT changes. 243 */ SetUpdateMeshCopTxtHandler(UpdateMeshCopTxtHandler aHandler)244 void SetUpdateMeshCopTxtHandler(UpdateMeshCopTxtHandler aHandler) 245 { 246 mUpdateMeshCopTxtHandler = std::move(aHandler); 247 } 248 249 /** 250 * This method handles MeshCoP TXT updates done by UpdateVendorMeshCopTxtEntries D-Bus API. 251 * 252 * @param[in] aUpdate The key-value pairs to be updated in the TXT record. 253 */ 254 void OnUpdateMeshCopTxt(std::map<std::string, std::vector<uint8_t>> aUpdate); 255 #endif 256 257 void DetachGracefully(ResultHandler aHandler); 258 259 #if OTBR_ENABLE_TELEMETRY_DATA_API 260 /** 261 * This method populates the telemetry data with best effort. The best effort means, for a given 262 * telemetry, if its retrieval has error, it is left unpopulated and the process continues to 263 * retrieve the remaining telemetries instead of the immediately return. The error code 264 * OT_ERRROR_FAILED will be returned if there is one or more error(s) happened in the process. 265 * 266 * @param[in] aPublisher The Mdns::Publisher to provide MDNS telemetry if it is not `nullptr`. 267 * @param[in] telemetryData The telemetry data to be populated. 268 * 269 * @retval OTBR_ERROR_NONE There is no error happened in the process. 270 * @retval OT_ERRROR_FAILED There is one or more error(s) happened in the process. 271 */ 272 otError RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadnetwork::TelemetryData &telemetryData); 273 #endif // OTBR_ENABLE_TELEMETRY_DATA_API 274 275 /** 276 * This method logs OpenThread action result. 277 * 278 * @param[in] aAction The action OpenThread performs. 279 * @param[in] aError The action result. 280 */ 281 static void LogOpenThreadResult(const char *aAction, otError aError); 282 283 /** 284 * This method validates and updates a pending dataset do Thread network migration. 285 * 286 * This method validates that: 287 * 1. the given dataset doesn't contain a meshcop Pending Timestamp TLV or a meshcop Delay Timer TLV. 288 * 2. the given dataset has sufficient space to append a Pending Timestamp TLV and a Delay Timer TLV. 289 * 290 * If it's valid, the method will append a meshcop Pending Timestamp TLV with value being the current unix 291 * timestamp and a meshcop Delay Timer TLV with value being @p aDelayMilli. 292 * 293 * @param[in/out] aDatasetTlvs The dataset to validate and process in TLVs format. 294 * @param[in] aDelayMilli The delay time for migration in milliseconds. 295 * 296 * @retval OT_ERROR_NONE Dataset is valid to do Thread network migration. 297 * @retval OT_ERROR_INVALID_ARGS Dataset is invalid to do Thread network migration. 298 */ 299 static otError ProcessDatasetForMigration(otOperationalDatasetTlvs &aDatasetTlvs, uint32_t aDelayMilli); 300 301 private: 302 static void ActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper); 303 void ActiveScanHandler(otActiveScanResult *aResult); 304 305 static void EnergyScanCallback(otEnergyScanResult *aResult, void *aThreadHelper); 306 void EnergyScanCallback(otEnergyScanResult *aResult); 307 308 static void JoinerCallback(otError aError, void *aThreadHelper); 309 void JoinerCallback(otError aResult); 310 311 static void MgmtSetResponseHandler(otError aResult, void *aContext); 312 void MgmtSetResponseHandler(otError aResult); 313 314 static void DetachGracefullyCallback(void *aContext); 315 void DetachGracefullyCallback(void); 316 317 void RandomFill(void *aBuf, size_t size); 318 uint8_t RandomChannelFromChannelMask(uint32_t aChannelMask); 319 320 void ActiveDatasetChangedCallback(void); 321 322 #if OTBR_ENABLE_DHCP6_PD 323 static void BorderRoutingDhcp6PdCallback(otBorderRoutingDhcp6PdState aState, void *aThreadHelper); 324 void BorderRoutingDhcp6PdCallback(otBorderRoutingDhcp6PdState aState); 325 #endif 326 #if OTBR_ENABLE_TELEMETRY_DATA_API 327 #if OTBR_ENABLE_BORDER_ROUTING 328 void RetrieveInfraLinkInfo(threadnetwork::TelemetryData::InfraLinkInfo &aInfraLinkInfo); 329 void RetrieveExternalRouteInfo(threadnetwork::TelemetryData::ExternalRoutes &aExternalRouteInfo); 330 #endif 331 #if OTBR_ENABLE_DHCP6_PD 332 void RetrievePdInfo(threadnetwork::TelemetryData::WpanBorderRouter *aWpanBorderRouter); 333 void RetrieveHashedPdPrefix(std::string *aHashedPdPrefix); 334 void RetrievePdProcessedRaInfo(threadnetwork::TelemetryData::PdProcessedRaInfo *aPdProcessedRaInfo); 335 #endif 336 #if OTBR_ENABLE_BORDER_AGENT 337 void RetrieveBorderAgentInfo(threadnetwork::TelemetryData::BorderAgentInfo *aBorderAgentInfo); 338 #endif 339 #endif // OTBR_ENABLE_TELEMETRY_DATA_API 340 341 otInstance *mInstance; 342 343 otbr::Ncp::RcpHost *mHost; 344 345 ScanHandler mScanHandler; 346 std::vector<otActiveScanResult> mScanResults; 347 EnergyScanHandler mEnergyScanHandler; 348 std::vector<otEnergyScanResult> mEnergyScanResults; 349 350 std::vector<DeviceRoleHandler> mDeviceRoleHandlers; 351 std::vector<DatasetChangeHandler> mActiveDatasetChangeHandlers; 352 353 std::map<uint16_t, size_t> mUnsecurePortRefCounter; 354 355 bool mWaitingMgmtSetResponse = 356 false; // During waiting for mgmt set response, calls to AttachHandler by StateChangedCallback will be ignored 357 int64_t mAttachDelayMs = 0; 358 AttachHandler mAttachHandler; 359 ResultHandler mJoinerHandler; 360 361 ResultHandler mDetachGracefullyHandler = nullptr; 362 363 otOperationalDatasetTlvs mAttachPendingDatasetTlvs = {}; 364 365 std::random_device mRandomDevice; 366 367 #if OTBR_ENABLE_DHCP6_PD 368 Dhcp6PdStateCallback mDhcp6PdCallback; 369 #endif 370 371 #if OTBR_ENABLE_DBUS_SERVER 372 UpdateMeshCopTxtHandler mUpdateMeshCopTxtHandler; 373 #endif 374 375 #if OTBR_ENABLE_TELEMETRY_DATA_API && (OTBR_ENABLE_NAT64 || OTBR_ENABLE_DHCP6_PD) 376 static constexpr uint8_t kNat64PdCommonHashSaltLength = 16; 377 uint8_t mNat64PdCommonSalt[kNat64PdCommonHashSaltLength]; 378 #endif 379 }; 380 381 } // namespace agent 382 } // namespace otbr 383 384 #endif // OTBR_THREAD_HELPER_HPP_ 385