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