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