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