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/dtls.hpp"
54 #include "meshcop/energy_scan_client.hpp"
55 #include "meshcop/panid_query_client.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      * This enumeration 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      * This enumeration 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      * This type represents a Commissioning Dataset.
101      *
102      */
103     class Dataset : public otCommissioningDataset, public Clearable<Dataset>
104     {
105     public:
106         /**
107          * This method indicates whether or not the Border Router RLOC16 Locator is set in the Dataset.
108          *
109          * @returns TRUE if Border Router RLOC16 Locator is set, FALSE otherwise.
110          *
111          */
IsLocatorSet(void) const112         bool IsLocatorSet(void) const { return mIsLocatorSet; }
113 
114         /**
115          * This method gets the Border Router RLOC16 Locator in the Dataset.
116          *
117          * This method MUST be used when Locator is set in the Dataset, otherwise its behavior is undefined.
118          *
119          * @returns The Border Router RLOC16 Locator in the Dataset.
120          *
121          */
GetLocator(void) const122         uint16_t GetLocator(void) const { return mLocator; }
123 
124         /**
125          * This method sets the Border Router RLOCG16 Locator in the Dataset.
126          *
127          * @param[in] aLocator  A Locator.
128          *
129          */
SetLocator(uint16_t aLocator)130         void SetLocator(uint16_t aLocator)
131         {
132             mIsLocatorSet = true;
133             mLocator      = aLocator;
134         }
135 
136         /**
137          * This method indicates whether or not the Session ID is set in the Dataset.
138          *
139          * @returns TRUE if Session ID is set, FALSE otherwise.
140          *
141          */
IsSessionIdSet(void) const142         bool IsSessionIdSet(void) const { return mIsSessionIdSet; }
143 
144         /**
145          * This method gets the Session ID in the Dataset.
146          *
147          * This method MUST be used when Session ID is set in the Dataset, otherwise its behavior is undefined.
148          *
149          * @returns The Session ID in the Dataset.
150          *
151          */
GetSessionId(void) const152         uint16_t GetSessionId(void) const { return mSessionId; }
153 
154         /**
155          * This method sets the Session ID in the Dataset.
156          *
157          * @param[in] aSessionId  The Session ID.
158          *
159          */
SetSessionId(uint16_t aSessionId)160         void SetSessionId(uint16_t aSessionId)
161         {
162             mIsSessionIdSet = true;
163             mSessionId      = aSessionId;
164         }
165 
166         /**
167          * This method indicates whether or not the Steering Data is set in the Dataset.
168          *
169          * @returns TRUE if Steering Data is set, FALSE otherwise.
170          *
171          */
IsSteeringDataSet(void) const172         bool IsSteeringDataSet(void) const { return mIsSteeringDataSet; }
173 
174         /**
175          * This method gets the Steering Data in the Dataset.
176          *
177          * This method MUST be used when Steering Data is set in the Dataset, otherwise its behavior is undefined.
178          *
179          * @returns The Steering Data in the Dataset.
180          *
181          */
GetSteeringData(void) const182         const SteeringData &GetSteeringData(void) const { return AsCoreType(&mSteeringData); }
183 
184         /**
185          * This method returns a reference to the Steering Data in the Dataset to be updated by caller.
186          *
187          * @returns A reference to the Steering Data in the Dataset.
188          *
189          */
UpdateSteeringData(void)190         SteeringData &UpdateSteeringData(void)
191         {
192             mIsSteeringDataSet = true;
193             return AsCoreType(&mSteeringData);
194         }
195 
196         /**
197          * This method indicates whether or not the Joiner UDP port is set in the Dataset.
198          *
199          * @returns TRUE if Joiner UDP port is set, FALSE otherwise.
200          *
201          */
IsJoinerUdpPortSet(void) const202         bool IsJoinerUdpPortSet(void) const { return mIsJoinerUdpPortSet; }
203 
204         /**
205          * This method gets the Joiner UDP port in the Dataset.
206          *
207          * This method MUST be used when Joiner UDP port is set in the Dataset, otherwise its behavior is undefined.
208          *
209          * @returns The Joiner UDP port in the Dataset.
210          *
211          */
GetJoinerUdpPort(void) const212         uint16_t GetJoinerUdpPort(void) const { return mJoinerUdpPort; }
213 
214         /**
215          * This method sets the Joiner UDP Port in the Dataset.
216          *
217          * @param[in] aJoinerUdpPort  The Joiner UDP Port.
218          *
219          */
SetJoinerUdpPort(uint16_t aJoinerUdpPort)220         void SetJoinerUdpPort(uint16_t aJoinerUdpPort)
221         {
222             mIsJoinerUdpPortSet = true;
223             mJoinerUdpPort      = aJoinerUdpPort;
224         }
225     };
226 
227     /**
228      * This constructor initializes the Commissioner object.
229      *
230      * @param[in]  aInstance     A reference to the OpenThread instance.
231      *
232      */
233     explicit Commissioner(Instance &aInstance);
234 
235     /**
236      * This method starts the Commissioner service.
237      *
238      * @param[in]  aStateCallback    A pointer to a function that is called when the commissioner state changes.
239      * @param[in]  aJoinerCallback   A pointer to a function that is called when a joiner event occurs.
240      * @param[in]  aCallbackContext  A pointer to application-specific context.
241      *
242      * @retval kErrorNone           Successfully started the Commissioner service.
243      * @retval kErrorAlready        Commissioner is already started.
244      * @retval kErrorInvalidState   Device is not currently attached to a network.
245      *
246      */
247     Error Start(StateCallback aStateCallback, JoinerCallback aJoinerCallback, void *aCallbackContext);
248 
249     /**
250      * This method stops the Commissioner service.
251      *
252      * @retval kErrorNone     Successfully stopped the Commissioner service.
253      * @retval kErrorAlready  Commissioner is already stopped.
254      *
255      */
Stop(void)256     Error Stop(void) { return Stop(kSendKeepAliveToResign); }
257 
258     /**
259      * This method returns the Commissioner Id.
260      *
261      * @returns The Commissioner Id.
262      *
263      */
GetId(void) const264     const char *GetId(void) const { return mCommissionerId; }
265 
266     /**
267      * This method sets the Commissioner Id.
268      *
269      * @param[in]  aId   A pointer to a string character array. Must be null terminated.
270      *
271      * @retval kErrorNone           Successfully set the Commissioner Id.
272      * @retval kErrorInvalidArgs    Given name is too long.
273      * @retval kErrorInvalidState   The commissioner is active and id cannot be changed.
274      *
275      */
276     Error SetId(const char *aId);
277 
278     /**
279      * This method clears all Joiner entries.
280      *
281      */
282     void ClearJoiners(void);
283 
284     /**
285      * This method adds a Joiner entry accepting any Joiner.
286      *
287      * @param[in]  aPskd         A pointer to the PSKd.
288      * @param[in]  aTimeout      A time after which a Joiner is automatically removed, in seconds.
289      *
290      * @retval kErrorNone          Successfully added the Joiner.
291      * @retval kErrorNoBufs        No buffers available to add the Joiner.
292      * @retval kErrorInvalidState  Commissioner service is not started.
293      *
294      */
AddJoinerAny(const char * aPskd,uint32_t aTimeout)295     Error AddJoinerAny(const char *aPskd, uint32_t aTimeout) { return AddJoiner(nullptr, nullptr, aPskd, aTimeout); }
296 
297     /**
298      * This method adds a Joiner entry.
299      *
300      * @param[in]  aEui64        The Joiner's IEEE EUI-64.
301      * @param[in]  aPskd         A pointer to the PSKd.
302      * @param[in]  aTimeout      A time after which a Joiner is automatically removed, in seconds.
303      *
304      * @retval kErrorNone          Successfully added the Joiner.
305      * @retval kErrorNoBufs        No buffers available to add the Joiner.
306      * @retval kErrorInvalidState  Commissioner service is not started.
307      *
308      */
AddJoiner(const Mac::ExtAddress & aEui64,const char * aPskd,uint32_t aTimeout)309     Error AddJoiner(const Mac::ExtAddress &aEui64, const char *aPskd, uint32_t aTimeout)
310     {
311         return AddJoiner(&aEui64, nullptr, aPskd, aTimeout);
312     }
313 
314     /**
315      * This method adds a Joiner entry with a Joiner Discerner.
316      *
317      * @param[in]  aDiscerner  A Joiner Discerner.
318      * @param[in]  aPskd       A pointer to the PSKd.
319      * @param[in]  aTimeout    A time after which a Joiner is automatically removed, in seconds.
320      *
321      * @retval kErrorNone          Successfully added the Joiner.
322      * @retval kErrorNoBufs        No buffers available to add the Joiner.
323      * @retval kErrorInvalidState  Commissioner service is not started.
324      *
325      */
AddJoiner(const JoinerDiscerner & aDiscerner,const char * aPskd,uint32_t aTimeout)326     Error AddJoiner(const JoinerDiscerner &aDiscerner, const char *aPskd, uint32_t aTimeout)
327     {
328         return AddJoiner(nullptr, &aDiscerner, aPskd, aTimeout);
329     }
330 
331     /**
332      * This method get joiner info at aIterator position.
333      *
334      * @param[in,out]   aIterator   A iterator to the index of the joiner.
335      * @param[out]      aJoiner     A reference to Joiner info.
336      *
337      * @retval kErrorNone       Successfully get the Joiner info.
338      * @retval kErrorNotFound   Not found next Joiner.
339      *
340      */
341     Error GetNextJoinerInfo(uint16_t &aIterator, otJoinerInfo &aJoiner) const;
342 
343     /**
344      * This method removes a Joiner entry accepting any Joiner.
345      *
346      * @param[in]  aDelay         The delay to remove Joiner (in seconds).
347      *
348      * @retval kErrorNone          Successfully added the Joiner.
349      * @retval kErrorNotFound      The Joiner entry accepting any Joiner was not found.
350      * @retval kErrorInvalidState  Commissioner service is not started.
351      *
352      */
RemoveJoinerAny(uint32_t aDelay)353     Error RemoveJoinerAny(uint32_t aDelay) { return RemoveJoiner(nullptr, nullptr, aDelay); }
354 
355     /**
356      * This method removes a Joiner entry.
357      *
358      * @param[in]  aEui64         The Joiner's IEEE EUI-64.
359      * @param[in]  aDelay         The delay to remove Joiner (in seconds).
360      *
361      * @retval kErrorNone          Successfully added the Joiner.
362      * @retval kErrorNotFound      The Joiner specified by @p aEui64 was not found.
363      * @retval kErrorInvalidState  Commissioner service is not started.
364      *
365      */
RemoveJoiner(const Mac::ExtAddress & aEui64,uint32_t aDelay)366     Error RemoveJoiner(const Mac::ExtAddress &aEui64, uint32_t aDelay)
367     {
368         return RemoveJoiner(&aEui64, nullptr, aDelay);
369     }
370 
371     /**
372      * This method removes a Joiner entry.
373      *
374      * @param[in]  aDiscerner     A Joiner Discerner.
375      * @param[in]  aDelay         The delay to remove Joiner (in seconds).
376      *
377      * @retval kErrorNone          Successfully added the Joiner.
378      * @retval kErrorNotFound      The Joiner specified by @p aEui64 was not found.
379      * @retval kErrorInvalidState  Commissioner service is not started.
380      *
381      */
RemoveJoiner(const JoinerDiscerner & aDiscerner,uint32_t aDelay)382     Error RemoveJoiner(const JoinerDiscerner &aDiscerner, uint32_t aDelay)
383     {
384         return RemoveJoiner(nullptr, &aDiscerner, aDelay);
385     }
386 
387     /**
388      * This method gets the Provisioning URL.
389      *
390      * @returns A pointer to char buffer containing the URL string.
391      *
392      */
GetProvisioningUrl(void) const393     const char *GetProvisioningUrl(void) const { return mProvisioningUrl; }
394 
395     /**
396      * This method sets the Provisioning URL.
397      *
398      * @param[in]  aProvisioningUrl  A pointer to the Provisioning URL (may be `nullptr` to set URL to empty string).
399      *
400      * @retval kErrorNone         Successfully set the Provisioning URL.
401      * @retval kErrorInvalidArgs  @p aProvisioningUrl is invalid (too long).
402      *
403      */
404     Error SetProvisioningUrl(const char *aProvisioningUrl);
405 
406     /**
407      * This method returns the Commissioner Session ID.
408      *
409      * @returns The Commissioner Session ID.
410      *
411      */
GetSessionId(void) const412     uint16_t GetSessionId(void) const { return mSessionId; }
413 
414     /**
415      * This method indicates whether or not the Commissioner role is active.
416      *
417      * @returns TRUE if the Commissioner role is active, FALSE otherwise.
418      *
419      */
IsActive(void) const420     bool IsActive(void) const { return mState == kStateActive; }
421 
422     /**
423      * This method indicates whether or not the Commissioner role is disabled.
424      *
425      * @returns TRUE if the Commissioner role is disabled, FALSE otherwise.
426      *
427      */
IsDisabled(void) const428     bool IsDisabled(void) const { return mState == kStateDisabled; }
429 
430     /**
431      * This method gets the Commissioner State.
432      *
433      * @returns The Commissioner State.
434      *
435      */
GetState(void) const436     State GetState(void) const { return mState; }
437 
438     /**
439      * This method sends MGMT_COMMISSIONER_GET.
440      *
441      * @param[in]  aTlvs        A pointer to Commissioning Data TLVs.
442      * @param[in]  aLength      The length of requested TLVs in bytes.
443      *
444      * @retval kErrorNone          Send MGMT_COMMISSIONER_GET successfully.
445      * @retval kErrorNoBufs        Insufficient buffer space to send.
446      * @retval kErrorInvalidState  Commissioner service is not started.
447      *
448      */
449     Error SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, uint8_t aLength);
450 
451     /**
452      * This method sends MGMT_COMMISSIONER_SET.
453      *
454      * @param[in]  aDataset     A reference to Commissioning Data.
455      * @param[in]  aTlvs        A pointer to user specific Commissioning Data TLVs.
456      * @param[in]  aLength      The length of user specific TLVs in bytes.
457      *
458      * @retval kErrorNone          Send MGMT_COMMISSIONER_SET successfully.
459      * @retval kErrorNoBufs        Insufficient buffer space to send.
460      * @retval kErrorInvalidState  Commissioner service is not started.
461      *
462      */
463     Error SendMgmtCommissionerSetRequest(const Dataset &aDataset, const uint8_t *aTlvs, uint8_t aLength);
464 
465     /**
466      * This method returns a reference to the AnnounceBeginClient instance.
467      *
468      * @returns A reference to the AnnounceBeginClient instance.
469      *
470      */
GetAnnounceBeginClient(void)471     AnnounceBeginClient &GetAnnounceBeginClient(void) { return mAnnounceBegin; }
472 
473     /**
474      * This method returns a reference to the EnergyScanClient instance.
475      *
476      * @returns A reference to the EnergyScanClient instance.
477      *
478      */
GetEnergyScanClient(void)479     EnergyScanClient &GetEnergyScanClient(void) { return mEnergyScan; }
480 
481     /**
482      * This method returns a reference to the PanIdQueryClient instance.
483      *
484      * @returns A reference to the PanIdQueryClient instance.
485      *
486      */
GetPanIdQueryClient(void)487     PanIdQueryClient &GetPanIdQueryClient(void) { return mPanIdQuery; }
488 
489     /**
490      * This method applies the Mesh Local Prefix.
491      *
492      */
493     void ApplyMeshLocalPrefix(void);
494 
495 private:
496     static constexpr uint32_t kPetitionAttemptDelay = 5;  // COMM_PET_ATTEMPT_DELAY (seconds)
497     static constexpr uint8_t  kPetitionRetryCount   = 2;  // COMM_PET_RETRY_COUNT
498     static constexpr uint32_t kPetitionRetryDelay   = 1;  // COMM_PET_RETRY_DELAY (seconds)
499     static constexpr uint32_t kKeepAliveTimeout     = 50; // TIMEOUT_COMM_PET (seconds)
500     static constexpr uint32_t kRemoveJoinerDelay    = 20; // Delay to remove successfully joined joiner
501 
502     static constexpr uint32_t kJoinerSessionTimeoutMillis =
503         1000 * OPENTHREAD_CONFIG_COMMISSIONER_JOINER_SESSION_TIMEOUT; // Expiration time for active Joiner session
504 
505     enum ResignMode : uint8_t
506     {
507         kSendKeepAliveToResign,
508         kDoNotSendKeepAlive,
509     };
510 
511     struct Joiner
512     {
513         enum Type : uint8_t
514         {
515             kTypeUnused = 0, // Need to be 0 to ensure `memset()` clears all `Joiners`
516             kTypeAny,
517             kTypeEui64,
518             kTypeDiscerner,
519         };
520 
521         TimeMilli mExpirationTime;
522 
523         union
524         {
525             Mac::ExtAddress mEui64;
526             JoinerDiscerner mDiscerner;
527         } mSharedId;
528 
529         JoinerPskd mPskd;
530         Type       mType;
531 
532         void CopyToJoinerInfo(otJoinerInfo &aJoiner) const;
533     };
534 
535     Error   Stop(ResignMode aResignMode);
536     Joiner *GetUnusedJoinerEntry(void);
537     Joiner *FindJoinerEntry(const Mac::ExtAddress *aEui64);
538     Joiner *FindJoinerEntry(const JoinerDiscerner &aDiscerner);
539     Joiner *FindBestMatchingJoinerEntry(const Mac::ExtAddress &aReceivedJoinerId);
540     void    RemoveJoinerEntry(Joiner &aJoiner);
541 
542     Error AddJoiner(const Mac::ExtAddress *aEui64,
543                     const JoinerDiscerner *aDiscerner,
544                     const char            *aPskd,
545                     uint32_t               aTimeout);
546     Error RemoveJoiner(const Mac::ExtAddress *aEui64, const JoinerDiscerner *aDiscerner, uint32_t aDelay);
547     void  RemoveJoiner(Joiner &aJoiner, uint32_t aDelay);
548 
549     void HandleTimer(void);
550     void HandleJoinerExpirationTimer(void);
551 
552     void UpdateJoinerExpirationTimer(void);
553 
554     static void HandleMgmtCommissionerSetResponse(void                *aContext,
555                                                   otMessage           *aMessage,
556                                                   const otMessageInfo *aMessageInfo,
557                                                   Error                aResult);
558     void        HandleMgmtCommissionerSetResponse(Coap::Message          *aMessage,
559                                                   const Ip6::MessageInfo *aMessageInfo,
560                                                   Error                   aResult);
561     static void HandleMgmtCommissionerGetResponse(void                *aContext,
562                                                   otMessage           *aMessage,
563                                                   const otMessageInfo *aMessageInfo,
564                                                   Error                aResult);
565     void        HandleMgmtCommissionerGetResponse(Coap::Message          *aMessage,
566                                                   const Ip6::MessageInfo *aMessageInfo,
567                                                   Error                   aResult);
568     static void HandleLeaderPetitionResponse(void                *aContext,
569                                              otMessage           *aMessage,
570                                              const otMessageInfo *aMessageInfo,
571                                              Error                aResult);
572     void HandleLeaderPetitionResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
573     static void HandleLeaderKeepAliveResponse(void                *aContext,
574                                               otMessage           *aMessage,
575                                               const otMessageInfo *aMessageInfo,
576                                               Error                aResult);
577     void HandleLeaderKeepAliveResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
578 
579     static void HandleSecureAgentConnected(bool aConnected, void *aContext);
580     void        HandleSecureAgentConnected(bool aConnected);
581 
582     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
583 
584     void HandleRelayReceive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
585 
586     void HandleJoinerSessionTimer(void);
587 
588     void SendJoinFinalizeResponse(const Coap::Message &aRequest, StateTlv::State aState);
589 
590     static Error SendRelayTransmit(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
591     Error        SendRelayTransmit(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
592 
593     void  ComputeBloomFilter(SteeringData &aSteeringData) const;
594     void  SendCommissionerSet(void);
595     Error SendPetition(void);
596     void  SendKeepAlive(void);
597     void  SendKeepAlive(uint16_t aSessionId);
598 
599     void SetState(State aState);
600     void SignalJoinerEvent(JoinerEvent aEvent, const Joiner *aJoiner) const;
601     void LogJoinerEntry(const char *aAction, const Joiner &aJoiner) const;
602 
603     static const char *StateToString(State aState);
604 
605     using JoinerExpirationTimer = TimerMilliIn<Commissioner, &Commissioner::HandleJoinerExpirationTimer>;
606     using CommissionerTimer     = TimerMilliIn<Commissioner, &Commissioner::HandleTimer>;
607     using JoinerSessionTimer    = TimerMilliIn<Commissioner, &Commissioner::HandleJoinerSessionTimer>;
608 
609     Joiner mJoiners[OPENTHREAD_CONFIG_COMMISSIONER_MAX_JOINER_ENTRIES];
610 
611     Joiner                  *mActiveJoiner;
612     Ip6::InterfaceIdentifier mJoinerIid;
613     uint16_t                 mJoinerPort;
614     uint16_t                 mJoinerRloc;
615     uint16_t                 mSessionId;
616     uint8_t                  mTransmitAttempts;
617     JoinerExpirationTimer    mJoinerExpirationTimer;
618     CommissionerTimer        mTimer;
619     JoinerSessionTimer       mJoinerSessionTimer;
620 
621     AnnounceBeginClient mAnnounceBegin;
622     EnergyScanClient    mEnergyScan;
623     PanIdQueryClient    mPanIdQuery;
624 
625     Ip6::Netif::UnicastAddress mCommissionerAloc;
626 
627     char mProvisioningUrl[OT_PROVISIONING_URL_MAX_SIZE + 1]; // + 1 is for null char at end of string.
628     char mCommissionerId[CommissionerIdTlv::kMaxLength + 1];
629 
630     State mState;
631 
632     Callback<StateCallback>  mStateCallback;
633     Callback<JoinerCallback> mJoinerCallback;
634 };
635 
636 DeclareTmfHandler(Commissioner, kUriDatasetChanged);
637 DeclareTmfHandler(Commissioner, kUriRelayRx);
638 DeclareTmfHandler(Commissioner, kUriJoinerFinalize);
639 
640 } // namespace MeshCoP
641 
642 DefineMapEnum(otCommissionerState, MeshCoP::Commissioner::State);
643 DefineMapEnum(otCommissionerJoinerEvent, MeshCoP::Commissioner::JoinerEvent);
644 DefineCoreType(otCommissioningDataset, MeshCoP::Commissioner::Dataset);
645 
646 } // namespace ot
647 
648 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
649 
650 #endif // COMMISSIONER_HPP_
651