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