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