• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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