1 /* 2 * Copyright (c) 2016, 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 the Joiner role. 32 */ 33 34 #ifndef JOINER_HPP_ 35 #define JOINER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_JOINER_ENABLE 40 41 #include <openthread/joiner.h> 42 43 #include "coap/coap_message.hpp" 44 #include "coap/coap_secure.hpp" 45 #include "common/as_core_type.hpp" 46 #include "common/callback.hpp" 47 #include "common/locator.hpp" 48 #include "common/log.hpp" 49 #include "common/message.hpp" 50 #include "common/non_copyable.hpp" 51 #include "mac/mac_types.hpp" 52 #include "meshcop/meshcop.hpp" 53 #include "meshcop/meshcop_tlvs.hpp" 54 #include "meshcop/secure_transport.hpp" 55 #include "thread/discover_scanner.hpp" 56 #include "thread/tmf.hpp" 57 58 namespace ot { 59 60 namespace MeshCoP { 61 62 class Joiner : public InstanceLocator, private NonCopyable 63 { 64 friend class Tmf::Agent; 65 66 public: 67 /** 68 * Type defines the Joiner State. 69 * 70 */ 71 enum State : uint8_t 72 { 73 kStateIdle = OT_JOINER_STATE_IDLE, 74 kStateDiscover = OT_JOINER_STATE_DISCOVER, 75 kStateConnect = OT_JOINER_STATE_CONNECT, 76 kStateConnected = OT_JOINER_STATE_CONNECTED, 77 kStateEntrust = OT_JOINER_STATE_ENTRUST, 78 kStateJoined = OT_JOINER_STATE_JOINED, 79 }; 80 81 /** 82 * Initializes the Joiner object. 83 * 84 * @param[in] aInstance A reference to the OpenThread instance. 85 * 86 */ 87 explicit Joiner(Instance &aInstance); 88 89 /** 90 * Starts the Joiner service. 91 * 92 * @param[in] aPskd A pointer to the PSKd. 93 * @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be `nullptr`). 94 * @param[in] aVendorName A pointer to the Vendor Name (may be `nullptr`). 95 * @param[in] aVendorModel A pointer to the Vendor Model (may be `nullptr`). 96 * @param[in] aVendorSwVersion A pointer to the Vendor SW Version (may be `nullptr`). 97 * @param[in] aVendorData A pointer to the Vendor Data (may be `nullptr`). 98 * @param[in] aCallback A pointer to a function that is called when the join operation completes. 99 * @param[in] aContext A pointer to application-specific context. 100 * 101 * @retval kErrorNone Successfully started the Joiner service. 102 * @retval kErrorBusy The previous attempt is still on-going. 103 * @retval kErrorInvalidState The IPv6 stack is not enabled or Thread stack is fully enabled. 104 * 105 */ 106 Error Start(const char *aPskd, 107 const char *aProvisioningUrl, 108 const char *aVendorName, 109 const char *aVendorModel, 110 const char *aVendorSwVersion, 111 const char *aVendorData, 112 otJoinerCallback aCallback, 113 void *aContext); 114 115 /** 116 * Stops the Joiner service. 117 * 118 */ 119 void Stop(void); 120 121 /** 122 * Gets the Joiner State. 123 * 124 * @returns The Joiner state (see `State`). 125 * 126 */ GetState(void) const127 State GetState(void) const { return mState; } 128 129 /** 130 * Retrieves the Joiner ID. 131 * 132 * @returns The Joiner ID. 133 * 134 */ GetId(void) const135 const Mac::ExtAddress &GetId(void) const { return mId; } 136 137 /** 138 * Gets the Jointer Discerner. 139 * 140 * @returns A pointer to the current Joiner Discerner or `nullptr` if none is set. 141 * 142 */ 143 const JoinerDiscerner *GetDiscerner(void) const; 144 145 /** 146 * Sets the Joiner Discerner. 147 * 148 * The Joiner Discerner is used to calculate the Joiner ID used during commissioning/joining process. 149 * 150 * By default (when a discerner is not provided or cleared), Joiner ID is derived as first 64 bits of the 151 * result of computing SHA-256 over factory-assigned IEEE EUI-64. Note that this is the main behavior expected by 152 * Thread specification. 153 * 154 * @param[in] aDiscerner A Joiner Discerner 155 * 156 * @retval kErrorNone The Joiner Discerner updated successfully. 157 * @retval kErrorInvalidArgs @p aDiscerner is not valid (specified length is not within valid range). 158 * @retval kErrorInvalidState There is an ongoing Joining process so Joiner Discerner could not be changed. 159 * 160 */ 161 Error SetDiscerner(const JoinerDiscerner &aDiscerner); 162 163 /** 164 * Clears any previously set Joiner Discerner. 165 * 166 * When cleared, Joiner ID is derived as first 64 bits of SHA-256 of factory-assigned IEEE EUI-64. 167 * 168 * @retval kErrorNone The Joiner Discerner cleared and Joiner ID updated. 169 * @retval kErrorInvalidState There is an ongoing Joining process so Joiner Discerner could not be changed. 170 * 171 */ 172 Error ClearDiscerner(void); 173 174 /** 175 * Converts a given Joiner state to its human-readable string representation. 176 * 177 * @param[in] aState The Joiner state to convert. 178 * 179 * @returns A human-readable string representation of @p aState. 180 * 181 */ 182 static const char *StateToString(State aState); 183 184 private: 185 static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; 186 187 static constexpr uint32_t kConfigExtAddressDelay = 100; // in msec. 188 static constexpr uint32_t kResponseTimeout = 4000; ///< Max wait time to receive response (in msec). 189 190 struct JoinerRouter 191 { 192 Mac::ExtAddress mExtAddr; 193 Mac::PanId mPanId; 194 uint16_t mJoinerUdpPort; 195 uint8_t mChannel; 196 uint8_t mPriority; 197 }; 198 199 static void HandleDiscoverResult(Mle::DiscoverScanner::ScanResult *aResult, void *aContext); 200 void HandleDiscoverResult(Mle::DiscoverScanner::ScanResult *aResult); 201 202 static void HandleSecureCoapClientConnect(bool aConnected, void *aContext); 203 void HandleSecureCoapClientConnect(bool aConnected); 204 205 static void HandleJoinerFinalizeResponse(void *aContext, 206 otMessage *aMessage, 207 const otMessageInfo *aMessageInfo, 208 Error aResult); 209 void HandleJoinerFinalizeResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult); 210 211 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 212 213 void HandleTimer(void); 214 215 void SetState(State aState); 216 void SetIdFromIeeeEui64(void); 217 void SaveDiscoveredJoinerRouter(const Mle::DiscoverScanner::ScanResult &aResult); 218 void TryNextJoinerRouter(Error aPrevError); 219 Error Connect(JoinerRouter &aRouter); 220 void Finish(Error aError); 221 uint8_t CalculatePriority(int8_t aRssi, bool aSteeringDataAllowsAny); 222 223 Error PrepareJoinerFinalizeMessage(const char *aProvisioningUrl, 224 const char *aVendorName, 225 const char *aVendorModel, 226 const char *aVendorSwVersion, 227 const char *aVendorData); 228 void FreeJoinerFinalizeMessage(void); 229 void SendJoinerFinalize(void); 230 void SendJoinerEntrustResponse(const Coap::Message &aRequest, const Ip6::MessageInfo &aRequestInfo); 231 232 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE 233 void LogCertMessage(const char *aText, const Coap::Message &aMessage) const; 234 #endif 235 236 using JoinerTimer = TimerMilliIn<Joiner, &Joiner::HandleTimer>; 237 238 Mac::ExtAddress mId; 239 JoinerDiscerner mDiscerner; 240 241 State mState; 242 243 Callback<otJoinerCallback> mCallback; 244 245 JoinerRouter mJoinerRouters[OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES]; 246 uint16_t mJoinerRouterIndex; 247 248 Coap::Message *mFinalizeMessage; 249 250 JoinerTimer mTimer; 251 }; 252 253 DeclareTmfHandler(Joiner, kUriJoinerEntrust); 254 255 } // namespace MeshCoP 256 257 DefineMapEnum(otJoinerState, MeshCoP::Joiner::State); 258 259 } // namespace ot 260 261 #endif // OPENTHREAD_CONFIG_JOINER_ENABLE 262 263 #endif // JOINER_HPP_ 264