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 Commissioner role. 32 */ 33 34 #ifndef COMMISSIONER_HPP_ 35 #define COMMISSIONER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 40 41 #include <openthread/commissioner.h> 42 43 #include "coap/coap_secure.hpp" 44 #include "common/as_core_type.hpp" 45 #include "common/callback.hpp" 46 #include "common/clearable.hpp" 47 #include "common/locator.hpp" 48 #include "common/log.hpp" 49 #include "common/non_copyable.hpp" 50 #include "common/timer.hpp" 51 #include "mac/mac_types.hpp" 52 #include "meshcop/announce_begin_client.hpp" 53 #include "meshcop/energy_scan_client.hpp" 54 #include "meshcop/panid_query_client.hpp" 55 #include "meshcop/secure_transport.hpp" 56 #include "net/ip6_address.hpp" 57 #include "net/udp6.hpp" 58 #include "thread/key_manager.hpp" 59 #include "thread/mle.hpp" 60 #include "thread/tmf.hpp" 61 62 namespace ot { 63 64 namespace MeshCoP { 65 66 #if !OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE 67 #error "Commissioner feature requires `OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE`" 68 #endif 69 70 class Commissioner : public InstanceLocator, private NonCopyable 71 { 72 friend class Tmf::Agent; 73 friend class Tmf::SecureAgent; 74 75 public: 76 /** 77 * Type represents the Commissioner State. 78 */ 79 enum State : uint8_t 80 { 81 kStateDisabled = OT_COMMISSIONER_STATE_DISABLED, ///< Disabled. 82 kStatePetition = OT_COMMISSIONER_STATE_PETITION, ///< Petitioning to become a Commissioner. 83 kStateActive = OT_COMMISSIONER_STATE_ACTIVE, ///< Active Commissioner. 84 }; 85 86 /** 87 * Type represents Joiner Event. 88 */ 89 enum JoinerEvent : uint8_t 90 { 91 kJoinerEventStart = OT_COMMISSIONER_JOINER_START, 92 kJoinerEventConnected = OT_COMMISSIONER_JOINER_CONNECTED, 93 kJoinerEventFinalize = OT_COMMISSIONER_JOINER_FINALIZE, 94 kJoinerEventEnd = OT_COMMISSIONER_JOINER_END, 95 kJoinerEventRemoved = OT_COMMISSIONER_JOINER_REMOVED, 96 }; 97 98 typedef otCommissionerStateCallback StateCallback; ///< State change callback function pointer type. 99 typedef otCommissionerJoinerCallback JoinerCallback; ///< Joiner state change callback function pointer type. 100 101 /** 102 * Initializes the Commissioner object. 103 * 104 * @param[in] aInstance A reference to the OpenThread instance. 105 */ 106 explicit Commissioner(Instance &aInstance); 107 108 /** 109 * Starts the Commissioner service. 110 * 111 * @param[in] aStateCallback A pointer to a function that is called when the commissioner state changes. 112 * @param[in] aJoinerCallback A pointer to a function that is called when a joiner event occurs. 113 * @param[in] aCallbackContext A pointer to application-specific context. 114 * 115 * @retval kErrorNone Successfully started the Commissioner service. 116 * @retval kErrorAlready Commissioner is already started. 117 * @retval kErrorInvalidState Device is not currently attached to a network. 118 */ 119 Error Start(StateCallback aStateCallback, JoinerCallback aJoinerCallback, void *aCallbackContext); 120 121 /** 122 * Stops the Commissioner service. 123 * 124 * @retval kErrorNone Successfully stopped the Commissioner service. 125 * @retval kErrorAlready Commissioner is already stopped. 126 */ Stop(void)127 Error Stop(void) { return Stop(kSendKeepAliveToResign); } 128 129 /** 130 * Returns the Commissioner Id. 131 * 132 * @returns The Commissioner Id. 133 */ GetId(void) const134 const char *GetId(void) const { return mCommissionerId; } 135 136 /** 137 * Sets the Commissioner Id. 138 * 139 * @param[in] aId A pointer to a string character array. Must be null terminated. 140 * 141 * @retval kErrorNone Successfully set the Commissioner Id. 142 * @retval kErrorInvalidArgs Given name is too long. 143 * @retval kErrorInvalidState The commissioner is active and id cannot be changed. 144 */ 145 Error SetId(const char *aId); 146 147 /** 148 * Clears all Joiner entries. 149 */ 150 void ClearJoiners(void); 151 152 /** 153 * Adds a Joiner entry accepting any Joiner. 154 * 155 * @param[in] aPskd A pointer to the PSKd. 156 * @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds. 157 * 158 * @retval kErrorNone Successfully added the Joiner. 159 * @retval kErrorNoBufs No buffers available to add the Joiner. 160 * @retval kErrorInvalidState Commissioner service is not started. 161 */ AddJoinerAny(const char * aPskd,uint32_t aTimeout)162 Error AddJoinerAny(const char *aPskd, uint32_t aTimeout) { return AddJoiner(nullptr, nullptr, aPskd, aTimeout); } 163 164 /** 165 * Adds a Joiner entry. 166 * 167 * @param[in] aEui64 The Joiner's IEEE EUI-64. 168 * @param[in] aPskd A pointer to the PSKd. 169 * @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds. 170 * 171 * @retval kErrorNone Successfully added the Joiner. 172 * @retval kErrorNoBufs No buffers available to add the Joiner. 173 * @retval kErrorInvalidState Commissioner service is not started. 174 */ AddJoiner(const Mac::ExtAddress & aEui64,const char * aPskd,uint32_t aTimeout)175 Error AddJoiner(const Mac::ExtAddress &aEui64, const char *aPskd, uint32_t aTimeout) 176 { 177 return AddJoiner(&aEui64, nullptr, aPskd, aTimeout); 178 } 179 180 /** 181 * Adds a Joiner entry with a Joiner Discerner. 182 * 183 * @param[in] aDiscerner A Joiner Discerner. 184 * @param[in] aPskd A pointer to the PSKd. 185 * @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds. 186 * 187 * @retval kErrorNone Successfully added the Joiner. 188 * @retval kErrorNoBufs No buffers available to add the Joiner. 189 * @retval kErrorInvalidState Commissioner service is not started. 190 */ AddJoiner(const JoinerDiscerner & aDiscerner,const char * aPskd,uint32_t aTimeout)191 Error AddJoiner(const JoinerDiscerner &aDiscerner, const char *aPskd, uint32_t aTimeout) 192 { 193 return AddJoiner(nullptr, &aDiscerner, aPskd, aTimeout); 194 } 195 196 /** 197 * Get joiner info at aIterator position. 198 * 199 * @param[in,out] aIterator A iterator to the index of the joiner. 200 * @param[out] aJoiner A reference to Joiner info. 201 * 202 * @retval kErrorNone Successfully get the Joiner info. 203 * @retval kErrorNotFound Not found next Joiner. 204 */ 205 Error GetNextJoinerInfo(uint16_t &aIterator, otJoinerInfo &aJoiner) const; 206 207 /** 208 * Removes a Joiner entry accepting any Joiner. 209 * 210 * @param[in] aDelay The delay to remove Joiner (in seconds). 211 * 212 * @retval kErrorNone Successfully added the Joiner. 213 * @retval kErrorNotFound The Joiner entry accepting any Joiner was not found. 214 * @retval kErrorInvalidState Commissioner service is not started. 215 */ RemoveJoinerAny(uint32_t aDelay)216 Error RemoveJoinerAny(uint32_t aDelay) { return RemoveJoiner(nullptr, nullptr, aDelay); } 217 218 /** 219 * Removes a Joiner entry. 220 * 221 * @param[in] aEui64 The Joiner's IEEE EUI-64. 222 * @param[in] aDelay The delay to remove Joiner (in seconds). 223 * 224 * @retval kErrorNone Successfully added the Joiner. 225 * @retval kErrorNotFound The Joiner specified by @p aEui64 was not found. 226 * @retval kErrorInvalidState Commissioner service is not started. 227 */ RemoveJoiner(const Mac::ExtAddress & aEui64,uint32_t aDelay)228 Error RemoveJoiner(const Mac::ExtAddress &aEui64, uint32_t aDelay) 229 { 230 return RemoveJoiner(&aEui64, nullptr, aDelay); 231 } 232 233 /** 234 * Removes a Joiner entry. 235 * 236 * @param[in] aDiscerner A Joiner Discerner. 237 * @param[in] aDelay The delay to remove Joiner (in seconds). 238 * 239 * @retval kErrorNone Successfully added the Joiner. 240 * @retval kErrorNotFound The Joiner specified by @p aEui64 was not found. 241 * @retval kErrorInvalidState Commissioner service is not started. 242 */ RemoveJoiner(const JoinerDiscerner & aDiscerner,uint32_t aDelay)243 Error RemoveJoiner(const JoinerDiscerner &aDiscerner, uint32_t aDelay) 244 { 245 return RemoveJoiner(nullptr, &aDiscerner, aDelay); 246 } 247 248 /** 249 * Gets the Provisioning URL. 250 * 251 * @returns A pointer to char buffer containing the URL string. 252 */ GetProvisioningUrl(void) const253 const char *GetProvisioningUrl(void) const { return mProvisioningUrl; } 254 255 /** 256 * Sets the Provisioning URL. 257 * 258 * @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be `nullptr` to set URL to empty string). 259 * 260 * @retval kErrorNone Successfully set the Provisioning URL. 261 * @retval kErrorInvalidArgs @p aProvisioningUrl is invalid (too long). 262 */ 263 Error SetProvisioningUrl(const char *aProvisioningUrl); 264 265 /** 266 * Returns the Commissioner Session ID. 267 * 268 * @returns The Commissioner Session ID. 269 */ GetSessionId(void) const270 uint16_t GetSessionId(void) const { return mSessionId; } 271 272 /** 273 * Indicates whether or not the Commissioner role is active. 274 * 275 * @returns TRUE if the Commissioner role is active, FALSE otherwise. 276 */ IsActive(void) const277 bool IsActive(void) const { return mState == kStateActive; } 278 279 /** 280 * Indicates whether or not the Commissioner role is disabled. 281 * 282 * @returns TRUE if the Commissioner role is disabled, FALSE otherwise. 283 */ IsDisabled(void) const284 bool IsDisabled(void) const { return mState == kStateDisabled; } 285 286 /** 287 * Gets the Commissioner State. 288 * 289 * @returns The Commissioner State. 290 */ GetState(void) const291 State GetState(void) const { return mState; } 292 293 /** 294 * Sends MGMT_COMMISSIONER_GET. 295 * 296 * @param[in] aTlvs A pointer to Commissioning Data TLVs. 297 * @param[in] aLength The length of requested TLVs in bytes. 298 * 299 * @retval kErrorNone Send MGMT_COMMISSIONER_GET successfully. 300 * @retval kErrorNoBufs Insufficient buffer space to send. 301 * @retval kErrorInvalidState Commissioner service is not started. 302 */ 303 Error SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, uint8_t aLength); 304 305 /** 306 * Sends MGMT_COMMISSIONER_SET. 307 * 308 * @param[in] aDataset A reference to Commissioning Data. 309 * @param[in] aTlvs A pointer to user specific Commissioning Data TLVs. 310 * @param[in] aLength The length of user specific TLVs in bytes. 311 * 312 * @retval kErrorNone Send MGMT_COMMISSIONER_SET successfully. 313 * @retval kErrorNoBufs Insufficient buffer space to send. 314 * @retval kErrorInvalidState Commissioner service is not started. 315 */ 316 Error SendMgmtCommissionerSetRequest(const CommissioningDataset &aDataset, const uint8_t *aTlvs, uint8_t aLength); 317 318 /** 319 * Returns a reference to the AnnounceBeginClient instance. 320 * 321 * @returns A reference to the AnnounceBeginClient instance. 322 */ GetAnnounceBeginClient(void)323 AnnounceBeginClient &GetAnnounceBeginClient(void) { return mAnnounceBegin; } 324 325 /** 326 * Returns a reference to the EnergyScanClient instance. 327 * 328 * @returns A reference to the EnergyScanClient instance. 329 */ GetEnergyScanClient(void)330 EnergyScanClient &GetEnergyScanClient(void) { return mEnergyScan; } 331 332 /** 333 * Returns a reference to the PanIdQueryClient instance. 334 * 335 * @returns A reference to the PanIdQueryClient instance. 336 */ GetPanIdQueryClient(void)337 PanIdQueryClient &GetPanIdQueryClient(void) { return mPanIdQuery; } 338 339 private: 340 static constexpr uint32_t kPetitionAttemptDelay = 5; // COMM_PET_ATTEMPT_DELAY (seconds) 341 static constexpr uint8_t kPetitionRetryCount = 2; // COMM_PET_RETRY_COUNT 342 static constexpr uint32_t kPetitionRetryDelay = 1; // COMM_PET_RETRY_DELAY (seconds) 343 static constexpr uint32_t kKeepAliveTimeout = 50; // TIMEOUT_COMM_PET (seconds) 344 static constexpr uint32_t kRemoveJoinerDelay = 20; // Delay to remove successfully joined joiner 345 346 static constexpr uint32_t kJoinerSessionTimeoutMillis = 347 1000 * OPENTHREAD_CONFIG_COMMISSIONER_JOINER_SESSION_TIMEOUT; // Expiration time for active Joiner session 348 349 enum ResignMode : uint8_t 350 { 351 kSendKeepAliveToResign, 352 kDoNotSendKeepAlive, 353 }; 354 355 struct Joiner 356 { 357 enum Type : uint8_t 358 { 359 kTypeUnused = 0, // Need to be 0 to ensure `memset()` clears all `Joiners` 360 kTypeAny, 361 kTypeEui64, 362 kTypeDiscerner, 363 }; 364 365 TimeMilli mExpirationTime; 366 367 union 368 { 369 Mac::ExtAddress mEui64; 370 JoinerDiscerner mDiscerner; 371 } mSharedId; 372 373 JoinerPskd mPskd; 374 Type mType; 375 376 void CopyToJoinerInfo(otJoinerInfo &aJoiner) const; 377 }; 378 379 Error Stop(ResignMode aResignMode); 380 Joiner *GetUnusedJoinerEntry(void); 381 Joiner *FindJoinerEntry(const Mac::ExtAddress *aEui64); 382 Joiner *FindJoinerEntry(const JoinerDiscerner &aDiscerner); 383 Joiner *FindBestMatchingJoinerEntry(const Mac::ExtAddress &aReceivedJoinerId); 384 void RemoveJoinerEntry(Joiner &aJoiner); 385 386 Error AddJoiner(const Mac::ExtAddress *aEui64, 387 const JoinerDiscerner *aDiscerner, 388 const char *aPskd, 389 uint32_t aTimeout); 390 Error RemoveJoiner(const Mac::ExtAddress *aEui64, const JoinerDiscerner *aDiscerner, uint32_t aDelay); 391 void RemoveJoiner(Joiner &aJoiner, uint32_t aDelay); 392 393 void HandleTimer(void); 394 void HandleJoinerExpirationTimer(void); 395 396 static void HandleMgmtCommissionerSetResponse(void *aContext, 397 otMessage *aMessage, 398 const otMessageInfo *aMessageInfo, 399 otError aResult); 400 void HandleMgmtCommissionerSetResponse(Coap::Message *aMessage, 401 const Ip6::MessageInfo *aMessageInfo, 402 Error aResult); 403 static void HandleMgmtCommissionerGetResponse(void *aContext, 404 otMessage *aMessage, 405 const otMessageInfo *aMessageInfo, 406 otError aResult); 407 void HandleMgmtCommissionerGetResponse(Coap::Message *aMessage, 408 const Ip6::MessageInfo *aMessageInfo, 409 Error aResult); 410 static void HandleLeaderPetitionResponse(void *aContext, 411 otMessage *aMessage, 412 const otMessageInfo *aMessageInfo, 413 otError aResult); 414 void HandleLeaderPetitionResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, otError aResult); 415 static void HandleLeaderKeepAliveResponse(void *aContext, 416 otMessage *aMessage, 417 const otMessageInfo *aMessageInfo, 418 Error aResult); 419 void HandleLeaderKeepAliveResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult); 420 421 static void HandleSecureAgentConnectEvent(Dtls::Session::ConnectEvent aEvent, void *aContext); 422 void HandleSecureAgentConnectEvent(Dtls::Session::ConnectEvent aEvent); 423 424 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 425 426 void HandleRelayReceive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 427 428 void HandleJoinerSessionTimer(void); 429 430 void SendJoinFinalizeResponse(const Coap::Message &aRequest, StateTlv::State aState); 431 432 static Error SendRelayTransmit(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 433 Error SendRelayTransmit(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 434 435 void ComputeBloomFilter(SteeringData &aSteeringData) const; 436 void SendCommissionerSet(void); 437 Error SendPetition(void); 438 void SendKeepAlive(void); 439 void SendKeepAlive(uint16_t aSessionId); 440 441 void SetState(State aState); 442 void SignalJoinerEvent(JoinerEvent aEvent, const Joiner *aJoiner) const; 443 void LogJoinerEntry(const char *aAction, const Joiner &aJoiner) const; 444 445 static const char *StateToString(State aState); 446 447 using JoinerExpirationTimer = TimerMilliIn<Commissioner, &Commissioner::HandleJoinerExpirationTimer>; 448 using CommissionerTimer = TimerMilliIn<Commissioner, &Commissioner::HandleTimer>; 449 using JoinerSessionTimer = TimerMilliIn<Commissioner, &Commissioner::HandleJoinerSessionTimer>; 450 451 Joiner mJoiners[OPENTHREAD_CONFIG_COMMISSIONER_MAX_JOINER_ENTRIES]; 452 453 Joiner *mActiveJoiner; 454 Ip6::InterfaceIdentifier mJoinerIid; 455 uint16_t mJoinerPort; 456 uint16_t mJoinerRloc; 457 uint16_t mSessionId; 458 uint8_t mTransmitAttempts; 459 JoinerExpirationTimer mJoinerExpirationTimer; 460 CommissionerTimer mTimer; 461 JoinerSessionTimer mJoinerSessionTimer; 462 463 AnnounceBeginClient mAnnounceBegin; 464 EnergyScanClient mEnergyScan; 465 PanIdQueryClient mPanIdQuery; 466 467 Ip6::Netif::UnicastAddress mCommissionerAloc; 468 469 ProvisioningUrlTlv::StringType mProvisioningUrl; 470 CommissionerIdTlv::StringType mCommissionerId; 471 472 State mState; 473 474 Callback<StateCallback> mStateCallback; 475 Callback<JoinerCallback> mJoinerCallback; 476 }; 477 478 DeclareTmfHandler(Commissioner, kUriDatasetChanged); 479 DeclareTmfHandler(Commissioner, kUriRelayRx); 480 DeclareTmfHandler(Commissioner, kUriJoinerFinalize); 481 482 } // namespace MeshCoP 483 484 DefineMapEnum(otCommissionerState, MeshCoP::Commissioner::State); 485 DefineMapEnum(otCommissionerJoinerEvent, MeshCoP::Commissioner::JoinerEvent); 486 487 } // namespace ot 488 489 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 490 491 #endif // COMMISSIONER_HPP_ 492