• 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 implements a Commissioner role.
32  */
33 
34 #include "commissioner.hpp"
35 
36 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
37 
38 #include <stdio.h>
39 
40 #include "coap/coap_message.hpp"
41 #include "common/array.hpp"
42 #include "common/as_core_type.hpp"
43 #include "common/encoding.hpp"
44 #include "common/instance.hpp"
45 #include "common/locator_getters.hpp"
46 #include "common/string.hpp"
47 #include "meshcop/joiner.hpp"
48 #include "meshcop/joiner_router.hpp"
49 #include "meshcop/meshcop.hpp"
50 #include "meshcop/meshcop_tlvs.hpp"
51 #include "thread/thread_netif.hpp"
52 #include "thread/thread_tlvs.hpp"
53 #include "thread/uri_paths.hpp"
54 
55 namespace ot {
56 namespace MeshCoP {
57 
58 RegisterLogModule("Commissioner");
59 
Commissioner(Instance & aInstance)60 Commissioner::Commissioner(Instance &aInstance)
61     : InstanceLocator(aInstance)
62     , mActiveJoiner(nullptr)
63     , mJoinerPort(0)
64     , mJoinerRloc(0)
65     , mSessionId(0)
66     , mTransmitAttempts(0)
67     , mJoinerExpirationTimer(aInstance, HandleJoinerExpirationTimer)
68     , mTimer(aInstance, HandleTimer)
69     , mRelayReceive(UriPath::kRelayRx, &Commissioner::HandleRelayReceive, this)
70     , mDatasetChanged(UriPath::kDatasetChanged, &Commissioner::HandleDatasetChanged, this)
71     , mJoinerFinalize(UriPath::kJoinerFinalize, &Commissioner::HandleJoinerFinalize, this)
72     , mAnnounceBegin(aInstance)
73     , mEnergyScan(aInstance)
74     , mPanIdQuery(aInstance)
75     , mState(kStateDisabled)
76     , mStateCallback(nullptr)
77     , mJoinerCallback(nullptr)
78     , mCallbackContext(nullptr)
79 {
80     memset(reinterpret_cast<void *>(mJoiners), 0, sizeof(mJoiners));
81 
82     mCommissionerAloc.Clear();
83     mCommissionerAloc.mPrefixLength       = 64;
84     mCommissionerAloc.mPreferred          = true;
85     mCommissionerAloc.mValid              = true;
86     mCommissionerAloc.mScopeOverride      = Ip6::Address::kRealmLocalScope;
87     mCommissionerAloc.mScopeOverrideValid = true;
88 
89     IgnoreError(SetId("OpenThread Commissioner"));
90 
91     mProvisioningUrl[0] = '\0';
92 }
93 
SetState(State aState)94 void Commissioner::SetState(State aState)
95 {
96     State oldState = mState;
97 
98     OT_UNUSED_VARIABLE(oldState);
99 
100     SuccessOrExit(Get<Notifier>().Update(mState, aState, kEventCommissionerStateChanged));
101 
102     LogInfo("State: %s -> %s", StateToString(oldState), StateToString(aState));
103 
104     if (mStateCallback)
105     {
106         mStateCallback(MapEnum(mState), mCallbackContext);
107     }
108 
109 exit:
110     return;
111 }
112 
SignalJoinerEvent(JoinerEvent aEvent,const Joiner * aJoiner) const113 void Commissioner::SignalJoinerEvent(JoinerEvent aEvent, const Joiner *aJoiner) const
114 {
115     otJoinerInfo    joinerInfo;
116     Mac::ExtAddress joinerId;
117     bool            noJoinerId = false;
118 
119     VerifyOrExit((mJoinerCallback != nullptr) && (aJoiner != nullptr));
120 
121     aJoiner->CopyToJoinerInfo(joinerInfo);
122 
123     if (aJoiner->mType == Joiner::kTypeEui64)
124     {
125         ComputeJoinerId(aJoiner->mSharedId.mEui64, joinerId);
126     }
127     else if (aJoiner == mActiveJoiner)
128     {
129         mJoinerIid.ConvertToExtAddress(joinerId);
130     }
131     else
132     {
133         noJoinerId = true;
134     }
135 
136     mJoinerCallback(MapEnum(aEvent), &joinerInfo, noJoinerId ? nullptr : &joinerId, mCallbackContext);
137 
138 exit:
139     return;
140 }
141 
AddCoapResources(void)142 void Commissioner::AddCoapResources(void)
143 {
144     Get<Tmf::Agent>().AddResource(mRelayReceive);
145     Get<Tmf::Agent>().AddResource(mDatasetChanged);
146     Get<Coap::CoapSecure>().AddResource(mJoinerFinalize);
147 }
148 
RemoveCoapResources(void)149 void Commissioner::RemoveCoapResources(void)
150 {
151     Get<Tmf::Agent>().RemoveResource(mRelayReceive);
152     Get<Tmf::Agent>().RemoveResource(mDatasetChanged);
153     Get<Coap::CoapSecure>().RemoveResource(mJoinerFinalize);
154 }
155 
HandleCoapsConnected(bool aConnected,void * aContext)156 void Commissioner::HandleCoapsConnected(bool aConnected, void *aContext)
157 {
158     static_cast<Commissioner *>(aContext)->HandleCoapsConnected(aConnected);
159 }
160 
HandleCoapsConnected(bool aConnected)161 void Commissioner::HandleCoapsConnected(bool aConnected)
162 {
163     SignalJoinerEvent(aConnected ? kJoinerEventConnected : kJoinerEventEnd, mActiveJoiner);
164 }
165 
GetUnusedJoinerEntry(void)166 Commissioner::Joiner *Commissioner::GetUnusedJoinerEntry(void)
167 {
168     Joiner *rval = nullptr;
169 
170     for (Joiner &joiner : mJoiners)
171     {
172         if (joiner.mType == Joiner::kTypeUnused)
173         {
174             rval = &joiner;
175             break;
176         }
177     }
178 
179     return rval;
180 }
181 
FindJoinerEntry(const Mac::ExtAddress * aEui64)182 Commissioner::Joiner *Commissioner::FindJoinerEntry(const Mac::ExtAddress *aEui64)
183 {
184     Joiner *rval = nullptr;
185 
186     for (Joiner &joiner : mJoiners)
187     {
188         switch (joiner.mType)
189         {
190         case Joiner::kTypeUnused:
191         case Joiner::kTypeDiscerner:
192             break;
193 
194         case Joiner::kTypeAny:
195             if (aEui64 == nullptr)
196             {
197                 ExitNow(rval = &joiner);
198             }
199             break;
200 
201         case Joiner::kTypeEui64:
202             if ((aEui64 != nullptr) && (joiner.mSharedId.mEui64 == *aEui64))
203             {
204                 ExitNow(rval = &joiner);
205             }
206             break;
207         }
208     }
209 
210 exit:
211     return rval;
212 }
213 
FindJoinerEntry(const JoinerDiscerner & aDiscerner)214 Commissioner::Joiner *Commissioner::FindJoinerEntry(const JoinerDiscerner &aDiscerner)
215 {
216     Joiner *rval = nullptr;
217 
218     for (Joiner &joiner : mJoiners)
219     {
220         if ((joiner.mType == Joiner::kTypeDiscerner) && (aDiscerner == joiner.mSharedId.mDiscerner))
221         {
222             rval = &joiner;
223             break;
224         }
225     }
226 
227     return rval;
228 }
229 
FindBestMatchingJoinerEntry(const Mac::ExtAddress & aReceivedJoinerId)230 Commissioner::Joiner *Commissioner::FindBestMatchingJoinerEntry(const Mac::ExtAddress &aReceivedJoinerId)
231 {
232     Joiner *        best = nullptr;
233     Mac::ExtAddress joinerId;
234 
235     // Prefer a full Joiner ID match, if not found use the entry
236     // accepting any joiner.
237 
238     for (Joiner &joiner : mJoiners)
239     {
240         switch (joiner.mType)
241         {
242         case Joiner::kTypeUnused:
243             break;
244 
245         case Joiner::kTypeAny:
246             if (best == nullptr)
247             {
248                 best = &joiner;
249             }
250             break;
251 
252         case Joiner::kTypeEui64:
253             ComputeJoinerId(joiner.mSharedId.mEui64, joinerId);
254             if (joinerId == aReceivedJoinerId)
255             {
256                 ExitNow(best = &joiner);
257             }
258             break;
259 
260         case Joiner::kTypeDiscerner:
261             if (joiner.mSharedId.mDiscerner.Matches(aReceivedJoinerId))
262             {
263                 if ((best == nullptr) ||
264                     ((best->mType == Joiner::kTypeDiscerner) &&
265                      (best->mSharedId.mDiscerner.GetLength() < joiner.mSharedId.mDiscerner.GetLength())))
266                 {
267                     best = &joiner;
268                 }
269             }
270             break;
271         }
272     }
273 
274 exit:
275     return best;
276 }
277 
RemoveJoinerEntry(Commissioner::Joiner & aJoiner)278 void Commissioner::RemoveJoinerEntry(Commissioner::Joiner &aJoiner)
279 {
280     // Create a copy of `aJoiner` to use for signaling joiner event
281     // and logging after the entry is removed. This ensures the joiner
282     // event callback is invoked after all states are cleared.
283 
284     Joiner joinerCopy = aJoiner;
285 
286     aJoiner.mType = Joiner::kTypeUnused;
287 
288     if (&aJoiner == mActiveJoiner)
289     {
290         mActiveJoiner = nullptr;
291     }
292 
293     UpdateJoinerExpirationTimer();
294 
295     SendCommissionerSet();
296 
297     LogJoinerEntry("Removed", joinerCopy);
298     SignalJoinerEvent(kJoinerEventRemoved, &joinerCopy);
299 }
300 
Start(StateCallback aStateCallback,JoinerCallback aJoinerCallback,void * aCallbackContext)301 Error Commissioner::Start(StateCallback aStateCallback, JoinerCallback aJoinerCallback, void *aCallbackContext)
302 {
303     Error error = kErrorNone;
304 
305     VerifyOrExit(Get<Mle::MleRouter>().IsAttached(), error = kErrorInvalidState);
306     VerifyOrExit(mState == kStateDisabled, error = kErrorAlready);
307 
308 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
309     Get<BorderAgent>().Stop();
310 #endif
311 
312     SuccessOrExit(error = Get<Coap::CoapSecure>().Start(SendRelayTransmit, this));
313     Get<Coap::CoapSecure>().SetConnectedCallback(&Commissioner::HandleCoapsConnected, this);
314 
315     mStateCallback    = aStateCallback;
316     mJoinerCallback   = aJoinerCallback;
317     mCallbackContext  = aCallbackContext;
318     mTransmitAttempts = 0;
319 
320     SuccessOrExit(error = SendPetition());
321     SetState(kStatePetition);
322 
323     LogInfo("start commissioner %s", mCommissionerId);
324 
325 exit:
326     if ((error != kErrorNone) && (error != kErrorAlready))
327     {
328         Get<Coap::CoapSecure>().Stop();
329     }
330 
331     LogError("start commissioner", error);
332     return error;
333 }
334 
Stop(ResignMode aResignMode)335 Error Commissioner::Stop(ResignMode aResignMode)
336 {
337     Error error      = kErrorNone;
338     bool  needResign = false;
339 
340     VerifyOrExit(mState != kStateDisabled, error = kErrorAlready);
341 
342     Get<Coap::CoapSecure>().Stop();
343 
344     if (mState == kStateActive)
345     {
346         Get<ThreadNetif>().RemoveUnicastAddress(mCommissionerAloc);
347         RemoveCoapResources();
348         ClearJoiners();
349         needResign = true;
350     }
351     else if (mState == kStatePetition)
352     {
353         mTransmitAttempts = 0;
354     }
355 
356     mTimer.Stop();
357 
358     SetState(kStateDisabled);
359 
360     if (needResign && (aResignMode == kSendKeepAliveToResign))
361     {
362         SendKeepAlive();
363     }
364 
365 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
366     Get<BorderAgent>().Start();
367 #endif
368 
369 exit:
370     LogError("stop commissioner", error);
371     return error;
372 }
373 
SetId(const char * aId)374 Error Commissioner::SetId(const char *aId)
375 {
376     Error   error = kErrorNone;
377     uint8_t len;
378 
379     VerifyOrExit(IsDisabled(), error = kErrorInvalidState);
380     VerifyOrExit(aId != nullptr);
381     VerifyOrExit(IsValidUtf8String(aId), error = kErrorInvalidArgs);
382 
383     len = static_cast<uint8_t>(StringLength(aId, sizeof(mCommissionerId)));
384 
385     // CommissionerIdTlv::SetCommissionerId trims the string to the maximum array size.
386     // Prevent this from happening returning an error.
387     VerifyOrExit(len < CommissionerIdTlv::kMaxLength, error = kErrorInvalidArgs);
388 
389     memcpy(mCommissionerId, aId, len);
390     mCommissionerId[len] = '\0';
391 
392 exit:
393     return error;
394 }
395 
ComputeBloomFilter(SteeringData & aSteeringData) const396 void Commissioner::ComputeBloomFilter(SteeringData &aSteeringData) const
397 {
398     Mac::ExtAddress joinerId;
399 
400     aSteeringData.Init();
401 
402     for (const Joiner &joiner : mJoiners)
403     {
404         switch (joiner.mType)
405         {
406         case Joiner::kTypeUnused:
407             break;
408 
409         case Joiner::kTypeEui64:
410             ComputeJoinerId(joiner.mSharedId.mEui64, joinerId);
411             aSteeringData.UpdateBloomFilter(joinerId);
412             break;
413 
414         case Joiner::kTypeDiscerner:
415             aSteeringData.UpdateBloomFilter(joiner.mSharedId.mDiscerner);
416             break;
417 
418         case Joiner::kTypeAny:
419             aSteeringData.SetToPermitAllJoiners();
420             ExitNow();
421         }
422     }
423 
424 exit:
425     return;
426 }
427 
SendCommissionerSet(void)428 void Commissioner::SendCommissionerSet(void)
429 {
430     Error   error = kErrorNone;
431     Dataset dataset;
432 
433     VerifyOrExit(mState == kStateActive, error = kErrorInvalidState);
434 
435     dataset.Clear();
436 
437     dataset.SetSessionId(mSessionId);
438     ComputeBloomFilter(dataset.UpdateSteeringData());
439 
440     error = SendMgmtCommissionerSetRequest(dataset, nullptr, 0);
441 
442 exit:
443     LogError("send MGMT_COMMISSIONER_SET.req", error);
444 }
445 
ClearJoiners(void)446 void Commissioner::ClearJoiners(void)
447 {
448     for (Joiner &joiner : mJoiners)
449     {
450         joiner.mType = Joiner::kTypeUnused;
451     }
452 
453     SendCommissionerSet();
454 }
455 
AddJoiner(const Mac::ExtAddress * aEui64,const JoinerDiscerner * aDiscerner,const char * aPskd,uint32_t aTimeout)456 Error Commissioner::AddJoiner(const Mac::ExtAddress *aEui64,
457                               const JoinerDiscerner *aDiscerner,
458                               const char *           aPskd,
459                               uint32_t               aTimeout)
460 {
461     Error   error = kErrorNone;
462     Joiner *joiner;
463 
464     VerifyOrExit(mState == kStateActive, error = kErrorInvalidState);
465 
466     if (aDiscerner != nullptr)
467     {
468         VerifyOrExit(aDiscerner->IsValid(), error = kErrorInvalidArgs);
469         joiner = FindJoinerEntry(*aDiscerner);
470     }
471     else
472     {
473         joiner = FindJoinerEntry(aEui64);
474     }
475 
476     if (joiner == nullptr)
477     {
478         joiner = GetUnusedJoinerEntry();
479     }
480 
481     VerifyOrExit(joiner != nullptr, error = kErrorNoBufs);
482 
483     SuccessOrExit(error = joiner->mPskd.SetFrom(aPskd));
484 
485     if (aDiscerner != nullptr)
486     {
487         joiner->mType                = Joiner::kTypeDiscerner;
488         joiner->mSharedId.mDiscerner = *aDiscerner;
489     }
490     else if (aEui64 != nullptr)
491     {
492         joiner->mType            = Joiner::kTypeEui64;
493         joiner->mSharedId.mEui64 = *aEui64;
494     }
495     else
496     {
497         joiner->mType = Joiner::kTypeAny;
498     }
499 
500     joiner->mExpirationTime = TimerMilli::GetNow() + Time::SecToMsec(aTimeout);
501 
502     UpdateJoinerExpirationTimer();
503 
504     SendCommissionerSet();
505 
506     LogJoinerEntry("Added", *joiner);
507 
508 exit:
509     return error;
510 }
511 
CopyToJoinerInfo(otJoinerInfo & aJoiner) const512 void Commissioner::Joiner::CopyToJoinerInfo(otJoinerInfo &aJoiner) const
513 {
514     memset(&aJoiner, 0, sizeof(aJoiner));
515 
516     switch (mType)
517     {
518     case kTypeAny:
519         aJoiner.mType = OT_JOINER_INFO_TYPE_ANY;
520         break;
521 
522     case kTypeEui64:
523         aJoiner.mType            = OT_JOINER_INFO_TYPE_EUI64;
524         aJoiner.mSharedId.mEui64 = mSharedId.mEui64;
525         break;
526 
527     case kTypeDiscerner:
528         aJoiner.mType                = OT_JOINER_INFO_TYPE_DISCERNER;
529         aJoiner.mSharedId.mDiscerner = mSharedId.mDiscerner;
530         break;
531 
532     case kTypeUnused:
533         ExitNow();
534     }
535 
536     aJoiner.mPskd           = mPskd;
537     aJoiner.mExpirationTime = mExpirationTime - TimerMilli::GetNow();
538 
539 exit:
540     return;
541 }
542 
GetNextJoinerInfo(uint16_t & aIterator,otJoinerInfo & aJoinerInfo) const543 Error Commissioner::GetNextJoinerInfo(uint16_t &aIterator, otJoinerInfo &aJoinerInfo) const
544 {
545     Error error = kErrorNone;
546 
547     while (aIterator < GetArrayLength(mJoiners))
548     {
549         const Joiner &joiner = mJoiners[aIterator++];
550 
551         if (joiner.mType != Joiner::kTypeUnused)
552         {
553             joiner.CopyToJoinerInfo(aJoinerInfo);
554             ExitNow();
555         }
556     }
557 
558     error = kErrorNotFound;
559 
560 exit:
561     return error;
562 }
563 
RemoveJoiner(const Mac::ExtAddress * aEui64,const JoinerDiscerner * aDiscerner,uint32_t aDelay)564 Error Commissioner::RemoveJoiner(const Mac::ExtAddress *aEui64, const JoinerDiscerner *aDiscerner, uint32_t aDelay)
565 {
566     Error   error = kErrorNone;
567     Joiner *joiner;
568 
569     VerifyOrExit(mState == kStateActive, error = kErrorInvalidState);
570 
571     if (aDiscerner != nullptr)
572     {
573         VerifyOrExit(aDiscerner->IsValid(), error = kErrorInvalidArgs);
574         joiner = FindJoinerEntry(*aDiscerner);
575     }
576     else
577     {
578         joiner = FindJoinerEntry(aEui64);
579     }
580 
581     VerifyOrExit(joiner != nullptr, error = kErrorNotFound);
582 
583     RemoveJoiner(*joiner, aDelay);
584 
585 exit:
586     return error;
587 }
588 
RemoveJoiner(Joiner & aJoiner,uint32_t aDelay)589 void Commissioner::RemoveJoiner(Joiner &aJoiner, uint32_t aDelay)
590 {
591     if (aDelay > 0)
592     {
593         TimeMilli newExpirationTime = TimerMilli::GetNow() + Time::SecToMsec(aDelay);
594 
595         if (aJoiner.mExpirationTime > newExpirationTime)
596         {
597             aJoiner.mExpirationTime = newExpirationTime;
598             UpdateJoinerExpirationTimer();
599         }
600     }
601     else
602     {
603         RemoveJoinerEntry(aJoiner);
604     }
605 }
606 
SetProvisioningUrl(const char * aProvisioningUrl)607 Error Commissioner::SetProvisioningUrl(const char *aProvisioningUrl)
608 {
609     Error   error = kErrorNone;
610     uint8_t len;
611 
612     if (aProvisioningUrl == nullptr)
613     {
614         mProvisioningUrl[0] = '\0';
615         ExitNow();
616     }
617 
618     VerifyOrExit(IsValidUtf8String(aProvisioningUrl), error = kErrorInvalidArgs);
619 
620     len = static_cast<uint8_t>(StringLength(aProvisioningUrl, sizeof(mProvisioningUrl)));
621 
622     VerifyOrExit(len < sizeof(mProvisioningUrl), error = kErrorInvalidArgs);
623 
624     memcpy(mProvisioningUrl, aProvisioningUrl, len);
625     mProvisioningUrl[len] = '\0';
626 
627 exit:
628     return error;
629 }
630 
HandleTimer(Timer & aTimer)631 void Commissioner::HandleTimer(Timer &aTimer)
632 {
633     aTimer.Get<Commissioner>().HandleTimer();
634 }
635 
HandleTimer(void)636 void Commissioner::HandleTimer(void)
637 {
638     switch (mState)
639     {
640     case kStateDisabled:
641         break;
642 
643     case kStatePetition:
644         IgnoreError(SendPetition());
645         break;
646 
647     case kStateActive:
648         SendKeepAlive();
649         break;
650     }
651 }
652 
HandleJoinerExpirationTimer(Timer & aTimer)653 void Commissioner::HandleJoinerExpirationTimer(Timer &aTimer)
654 {
655     aTimer.Get<Commissioner>().HandleJoinerExpirationTimer();
656 }
657 
HandleJoinerExpirationTimer(void)658 void Commissioner::HandleJoinerExpirationTimer(void)
659 {
660     TimeMilli now = TimerMilli::GetNow();
661 
662     for (Joiner &joiner : mJoiners)
663     {
664         if (joiner.mType == Joiner::kTypeUnused)
665         {
666             continue;
667         }
668 
669         if (joiner.mExpirationTime <= now)
670         {
671             LogDebg("removing joiner due to timeout or successfully joined");
672             RemoveJoinerEntry(joiner);
673         }
674     }
675 
676     UpdateJoinerExpirationTimer();
677 }
678 
UpdateJoinerExpirationTimer(void)679 void Commissioner::UpdateJoinerExpirationTimer(void)
680 {
681     TimeMilli now  = TimerMilli::GetNow();
682     TimeMilli next = now.GetDistantFuture();
683 
684     for (Joiner &joiner : mJoiners)
685     {
686         if (joiner.mType == Joiner::kTypeUnused)
687         {
688             continue;
689         }
690 
691         if (joiner.mExpirationTime <= now)
692         {
693             next = now;
694         }
695         else if (joiner.mExpirationTime < next)
696         {
697             next = joiner.mExpirationTime;
698         }
699     }
700 
701     if (next < now.GetDistantFuture())
702     {
703         mJoinerExpirationTimer.FireAt(next);
704     }
705     else
706     {
707         mJoinerExpirationTimer.Stop();
708     }
709 }
710 
SendMgmtCommissionerGetRequest(const uint8_t * aTlvs,uint8_t aLength)711 Error Commissioner::SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, uint8_t aLength)
712 {
713     Error            error = kErrorNone;
714     Coap::Message *  message;
715     Tmf::MessageInfo messageInfo(GetInstance());
716     Tlv              tlv;
717 
718     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kCommissionerGet);
719     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
720 
721     if (aLength > 0)
722     {
723         tlv.SetType(Tlv::kGet);
724         tlv.SetLength(aLength);
725         SuccessOrExit(error = message->Append(tlv));
726         SuccessOrExit(error = message->AppendBytes(aTlvs, aLength));
727     }
728 
729     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
730     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo,
731                                                         Commissioner::HandleMgmtCommissionerGetResponse, this));
732 
733     LogInfo("sent MGMT_COMMISSIONER_GET.req to leader");
734 
735 exit:
736     FreeMessageOnError(message, error);
737     return error;
738 }
739 
HandleMgmtCommissionerGetResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)740 void Commissioner::HandleMgmtCommissionerGetResponse(void *               aContext,
741                                                      otMessage *          aMessage,
742                                                      const otMessageInfo *aMessageInfo,
743                                                      Error                aResult)
744 {
745     static_cast<Commissioner *>(aContext)->HandleMgmtCommissionerGetResponse(AsCoapMessagePtr(aMessage),
746                                                                              AsCoreTypePtr(aMessageInfo), aResult);
747 }
748 
HandleMgmtCommissionerGetResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)749 void Commissioner::HandleMgmtCommissionerGetResponse(Coap::Message *         aMessage,
750                                                      const Ip6::MessageInfo *aMessageInfo,
751                                                      Error                   aResult)
752 {
753     OT_UNUSED_VARIABLE(aMessageInfo);
754 
755     VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged);
756     LogInfo("received MGMT_COMMISSIONER_GET response");
757 
758 exit:
759     return;
760 }
761 
SendMgmtCommissionerSetRequest(const Dataset & aDataset,const uint8_t * aTlvs,uint8_t aLength)762 Error Commissioner::SendMgmtCommissionerSetRequest(const Dataset &aDataset, const uint8_t *aTlvs, uint8_t aLength)
763 {
764     Error            error = kErrorNone;
765     Coap::Message *  message;
766     Tmf::MessageInfo messageInfo(GetInstance());
767 
768     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kCommissionerSet);
769     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
770 
771     if (aDataset.IsLocatorSet())
772     {
773         SuccessOrExit(error = Tlv::Append<BorderAgentLocatorTlv>(*message, aDataset.GetLocator()));
774     }
775 
776     if (aDataset.IsSessionIdSet())
777     {
778         SuccessOrExit(error = Tlv::Append<CommissionerSessionIdTlv>(*message, aDataset.GetSessionId()));
779     }
780 
781     if (aDataset.IsSteeringDataSet())
782     {
783         const SteeringData &steeringData = aDataset.GetSteeringData();
784 
785         SuccessOrExit(error = Tlv::Append<SteeringDataTlv>(*message, steeringData.GetData(), steeringData.GetLength()));
786     }
787 
788     if (aDataset.IsJoinerUdpPortSet())
789     {
790         SuccessOrExit(error = Tlv::Append<JoinerUdpPortTlv>(*message, aDataset.GetJoinerUdpPort()));
791     }
792 
793     if (aLength > 0)
794     {
795         SuccessOrExit(error = message->AppendBytes(aTlvs, aLength));
796     }
797 
798     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
799     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo,
800                                                         Commissioner::HandleMgmtCommissionerSetResponse, this));
801 
802     LogInfo("sent MGMT_COMMISSIONER_SET.req to leader");
803 
804 exit:
805     FreeMessageOnError(message, error);
806     return error;
807 }
808 
HandleMgmtCommissionerSetResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)809 void Commissioner::HandleMgmtCommissionerSetResponse(void *               aContext,
810                                                      otMessage *          aMessage,
811                                                      const otMessageInfo *aMessageInfo,
812                                                      Error                aResult)
813 {
814     static_cast<Commissioner *>(aContext)->HandleMgmtCommissionerSetResponse(AsCoapMessagePtr(aMessage),
815                                                                              AsCoreTypePtr(aMessageInfo), aResult);
816 }
817 
HandleMgmtCommissionerSetResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)818 void Commissioner::HandleMgmtCommissionerSetResponse(Coap::Message *         aMessage,
819                                                      const Ip6::MessageInfo *aMessageInfo,
820                                                      Error                   aResult)
821 {
822     OT_UNUSED_VARIABLE(aMessageInfo);
823 
824     VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged);
825     LogInfo("received MGMT_COMMISSIONER_SET response");
826 
827 exit:
828     return;
829 }
830 
SendPetition(void)831 Error Commissioner::SendPetition(void)
832 {
833     Error             error   = kErrorNone;
834     Coap::Message *   message = nullptr;
835     Tmf::MessageInfo  messageInfo(GetInstance());
836     CommissionerIdTlv commissionerIdTlv;
837 
838     mTransmitAttempts++;
839 
840     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kLeaderPetition);
841     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
842 
843     commissionerIdTlv.Init();
844     commissionerIdTlv.SetCommissionerId(mCommissionerId);
845 
846     SuccessOrExit(error = commissionerIdTlv.AppendTo(*message));
847     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
848     SuccessOrExit(
849         error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, Commissioner::HandleLeaderPetitionResponse, this));
850 
851     LogInfo("sent petition");
852 
853 exit:
854     FreeMessageOnError(message, error);
855     return error;
856 }
857 
HandleLeaderPetitionResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)858 void Commissioner::HandleLeaderPetitionResponse(void *               aContext,
859                                                 otMessage *          aMessage,
860                                                 const otMessageInfo *aMessageInfo,
861                                                 Error                aResult)
862 {
863     static_cast<Commissioner *>(aContext)->HandleLeaderPetitionResponse(AsCoapMessagePtr(aMessage),
864                                                                         AsCoreTypePtr(aMessageInfo), aResult);
865 }
866 
HandleLeaderPetitionResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)867 void Commissioner::HandleLeaderPetitionResponse(Coap::Message *         aMessage,
868                                                 const Ip6::MessageInfo *aMessageInfo,
869                                                 Error                   aResult)
870 {
871     OT_UNUSED_VARIABLE(aMessageInfo);
872 
873     uint8_t state;
874     bool    retransmit = false;
875 
876     VerifyOrExit(mState != kStateActive);
877     VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged,
878                  retransmit = (mState == kStatePetition));
879 
880     LogInfo("received Leader Petition response");
881 
882     SuccessOrExit(Tlv::Find<StateTlv>(*aMessage, state));
883     VerifyOrExit(state == StateTlv::kAccept, IgnoreError(Stop(kDoNotSendKeepAlive)));
884 
885     SuccessOrExit(Tlv::Find<CommissionerSessionIdTlv>(*aMessage, mSessionId));
886 
887     // reject this session by sending KeepAlive reject if commissioner is in disabled state
888     // this could happen if commissioner is stopped by API during petitioning
889     if (mState == kStateDisabled)
890     {
891         SendKeepAlive(mSessionId);
892         ExitNow();
893     }
894 
895     IgnoreError(Get<Mle::MleRouter>().GetCommissionerAloc(mCommissionerAloc.GetAddress(), mSessionId));
896     Get<ThreadNetif>().AddUnicastAddress(mCommissionerAloc);
897 
898     AddCoapResources();
899     SetState(kStateActive);
900 
901     mTransmitAttempts = 0;
902     mTimer.Start(Time::SecToMsec(kKeepAliveTimeout) / 2);
903 
904 exit:
905 
906     if (retransmit)
907     {
908         if (mTransmitAttempts >= kPetitionRetryCount)
909         {
910             IgnoreError(Stop(kDoNotSendKeepAlive));
911         }
912         else
913         {
914             mTimer.Start(Time::SecToMsec(kPetitionRetryDelay));
915         }
916     }
917 }
918 
SendKeepAlive(void)919 void Commissioner::SendKeepAlive(void)
920 {
921     SendKeepAlive(mSessionId);
922 }
923 
SendKeepAlive(uint16_t aSessionId)924 void Commissioner::SendKeepAlive(uint16_t aSessionId)
925 {
926     Error            error   = kErrorNone;
927     Coap::Message *  message = nullptr;
928     Tmf::MessageInfo messageInfo(GetInstance());
929 
930     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kLeaderKeepAlive);
931     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
932 
933     SuccessOrExit(
934         error = Tlv::Append<StateTlv>(*message, (mState == kStateActive) ? StateTlv::kAccept : StateTlv::kReject));
935 
936     SuccessOrExit(error = Tlv::Append<CommissionerSessionIdTlv>(*message, aSessionId));
937 
938     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
939     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo,
940                                                         Commissioner::HandleLeaderKeepAliveResponse, this));
941 
942     LogInfo("sent keep alive");
943 
944 exit:
945     FreeMessageOnError(message, error);
946     LogError("send keep alive", error);
947 }
948 
HandleLeaderKeepAliveResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)949 void Commissioner::HandleLeaderKeepAliveResponse(void *               aContext,
950                                                  otMessage *          aMessage,
951                                                  const otMessageInfo *aMessageInfo,
952                                                  Error                aResult)
953 {
954     static_cast<Commissioner *>(aContext)->HandleLeaderKeepAliveResponse(AsCoapMessagePtr(aMessage),
955                                                                          AsCoreTypePtr(aMessageInfo), aResult);
956 }
957 
HandleLeaderKeepAliveResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)958 void Commissioner::HandleLeaderKeepAliveResponse(Coap::Message *         aMessage,
959                                                  const Ip6::MessageInfo *aMessageInfo,
960                                                  Error                   aResult)
961 {
962     OT_UNUSED_VARIABLE(aMessageInfo);
963 
964     uint8_t state;
965 
966     VerifyOrExit(mState == kStateActive);
967     VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged,
968                  IgnoreError(Stop(kDoNotSendKeepAlive)));
969 
970     LogInfo("received Leader keep-alive response");
971 
972     SuccessOrExit(Tlv::Find<StateTlv>(*aMessage, state));
973     VerifyOrExit(state == StateTlv::kAccept, IgnoreError(Stop(kDoNotSendKeepAlive)));
974 
975     mTimer.Start(Time::SecToMsec(kKeepAliveTimeout) / 2);
976 
977 exit:
978     return;
979 }
980 
HandleRelayReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)981 void Commissioner::HandleRelayReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
982 {
983     static_cast<Commissioner *>(aContext)->HandleRelayReceive(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
984 }
985 
HandleRelayReceive(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)986 void Commissioner::HandleRelayReceive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
987 {
988     OT_UNUSED_VARIABLE(aMessageInfo);
989 
990     Error                    error;
991     uint16_t                 joinerPort;
992     Ip6::InterfaceIdentifier joinerIid;
993     uint16_t                 joinerRloc;
994     Ip6::MessageInfo         joinerMessageInfo;
995     uint16_t                 offset;
996     uint16_t                 length;
997 
998     VerifyOrExit(mState == kStateActive, error = kErrorInvalidState);
999 
1000     VerifyOrExit(aMessage.IsNonConfirmablePostRequest());
1001 
1002     SuccessOrExit(error = Tlv::Find<JoinerUdpPortTlv>(aMessage, joinerPort));
1003     SuccessOrExit(error = Tlv::Find<JoinerIidTlv>(aMessage, joinerIid));
1004     SuccessOrExit(error = Tlv::Find<JoinerRouterLocatorTlv>(aMessage, joinerRloc));
1005 
1006     SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Tlv::kJoinerDtlsEncapsulation, offset, length));
1007     VerifyOrExit(length <= aMessage.GetLength() - offset, error = kErrorParse);
1008 
1009     if (!Get<Coap::CoapSecure>().IsConnectionActive())
1010     {
1011         Mac::ExtAddress receivedId;
1012         Joiner *        joiner;
1013 
1014         mJoinerIid = joinerIid;
1015         mJoinerIid.ConvertToExtAddress(receivedId);
1016 
1017         joiner = FindBestMatchingJoinerEntry(receivedId);
1018         VerifyOrExit(joiner != nullptr);
1019 
1020         Get<Coap::CoapSecure>().SetPsk(joiner->mPskd);
1021         mActiveJoiner = joiner;
1022 
1023         LogJoinerEntry("Starting new session with", *joiner);
1024         SignalJoinerEvent(kJoinerEventStart, joiner);
1025     }
1026     else
1027     {
1028         VerifyOrExit(mJoinerIid == joinerIid);
1029     }
1030 
1031     mJoinerPort = joinerPort;
1032     mJoinerRloc = joinerRloc;
1033 
1034     LogInfo("Received Relay Receive (%s, 0x%04x)", mJoinerIid.ToString().AsCString(), mJoinerRloc);
1035 
1036     aMessage.SetOffset(offset);
1037     SuccessOrExit(error = aMessage.SetLength(offset + length));
1038 
1039     joinerMessageInfo.SetPeerAddr(Get<Mle::MleRouter>().GetMeshLocal64());
1040     joinerMessageInfo.GetPeerAddr().SetIid(mJoinerIid);
1041     joinerMessageInfo.SetPeerPort(mJoinerPort);
1042 
1043     Get<Coap::CoapSecure>().HandleUdpReceive(aMessage, joinerMessageInfo);
1044 
1045 exit:
1046     return;
1047 }
1048 
HandleDatasetChanged(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1049 void Commissioner::HandleDatasetChanged(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1050 {
1051     static_cast<Commissioner *>(aContext)->HandleDatasetChanged(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
1052 }
1053 
HandleDatasetChanged(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1054 void Commissioner::HandleDatasetChanged(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1055 {
1056     VerifyOrExit(aMessage.IsConfirmablePostRequest());
1057 
1058     LogInfo("received dataset changed");
1059 
1060     SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
1061 
1062     LogInfo("sent dataset changed acknowledgment");
1063 
1064 exit:
1065     return;
1066 }
1067 
HandleJoinerFinalize(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1068 void Commissioner::HandleJoinerFinalize(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1069 {
1070     static_cast<Commissioner *>(aContext)->HandleJoinerFinalize(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
1071 }
1072 
HandleJoinerFinalize(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1073 void Commissioner::HandleJoinerFinalize(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1074 {
1075     OT_UNUSED_VARIABLE(aMessageInfo);
1076 
1077     StateTlv::State    state = StateTlv::kAccept;
1078     ProvisioningUrlTlv provisioningUrl;
1079 
1080     LogInfo("received joiner finalize");
1081 
1082     if (Tlv::FindTlv(aMessage, provisioningUrl) == kErrorNone)
1083     {
1084         uint8_t len = static_cast<uint8_t>(StringLength(mProvisioningUrl, sizeof(mProvisioningUrl)));
1085 
1086         if ((provisioningUrl.GetProvisioningUrlLength() != len) ||
1087             !memcmp(provisioningUrl.GetProvisioningUrl(), mProvisioningUrl, len))
1088         {
1089             state = StateTlv::kReject;
1090         }
1091     }
1092 
1093 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1094     if (aMessage.GetLength() <= OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE)
1095     {
1096         uint8_t buf[OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE];
1097 
1098         aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
1099         DumpCert("[THCI] direction=recv | type=JOIN_FIN.req |", buf, aMessage.GetLength() - aMessage.GetOffset());
1100     }
1101 #endif
1102 
1103     SendJoinFinalizeResponse(aMessage, state);
1104 }
1105 
SendJoinFinalizeResponse(const Coap::Message & aRequest,StateTlv::State aState)1106 void Commissioner::SendJoinFinalizeResponse(const Coap::Message &aRequest, StateTlv::State aState)
1107 {
1108     Error            error = kErrorNone;
1109     Ip6::MessageInfo joinerMessageInfo;
1110     Coap::Message *  message;
1111 
1112     message = Get<Coap::CoapSecure>().NewPriorityResponseMessage(aRequest);
1113     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
1114 
1115     message->SetOffset(message->GetLength());
1116     message->SetSubType(Message::kSubTypeJoinerFinalizeResponse);
1117 
1118     SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
1119 
1120     joinerMessageInfo.SetPeerAddr(Get<Mle::MleRouter>().GetMeshLocal64());
1121     joinerMessageInfo.GetPeerAddr().SetIid(mJoinerIid);
1122     joinerMessageInfo.SetPeerPort(mJoinerPort);
1123 
1124 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1125     uint8_t buf[OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE];
1126 
1127     VerifyOrExit(message->GetLength() <= sizeof(buf));
1128     message->ReadBytes(message->GetOffset(), buf, message->GetLength() - message->GetOffset());
1129     DumpCert("[THCI] direction=send | type=JOIN_FIN.rsp |", buf, message->GetLength() - message->GetOffset());
1130 #endif
1131 
1132     SuccessOrExit(error = Get<Coap::CoapSecure>().SendMessage(*message, joinerMessageInfo));
1133 
1134     SignalJoinerEvent(kJoinerEventFinalize, mActiveJoiner);
1135 
1136     if ((mActiveJoiner != nullptr) && (mActiveJoiner->mType != Joiner::kTypeAny))
1137     {
1138         // Remove after kRemoveJoinerDelay (seconds)
1139         RemoveJoiner(*mActiveJoiner, kRemoveJoinerDelay);
1140     }
1141 
1142     LogInfo("sent joiner finalize response");
1143 
1144 exit:
1145     FreeMessageOnError(message, error);
1146 }
1147 
SendRelayTransmit(void * aContext,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1148 Error Commissioner::SendRelayTransmit(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1149 {
1150     return static_cast<Commissioner *>(aContext)->SendRelayTransmit(aMessage, aMessageInfo);
1151 }
1152 
SendRelayTransmit(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1153 Error Commissioner::SendRelayTransmit(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1154 {
1155     OT_UNUSED_VARIABLE(aMessageInfo);
1156 
1157     Error            error = kErrorNone;
1158     ExtendedTlv      tlv;
1159     Coap::Message *  message;
1160     uint16_t         offset;
1161     Tmf::MessageInfo messageInfo(GetInstance());
1162     Kek              kek;
1163 
1164     Get<KeyManager>().ExtractKek(kek);
1165 
1166     message = Get<Tmf::Agent>().NewPriorityNonConfirmablePostMessage(UriPath::kRelayTx);
1167     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
1168 
1169     SuccessOrExit(error = Tlv::Append<JoinerUdpPortTlv>(*message, mJoinerPort));
1170     SuccessOrExit(error = Tlv::Append<JoinerIidTlv>(*message, mJoinerIid));
1171     SuccessOrExit(error = Tlv::Append<JoinerRouterLocatorTlv>(*message, mJoinerRloc));
1172 
1173     if (aMessage.GetSubType() == Message::kSubTypeJoinerFinalizeResponse)
1174     {
1175         SuccessOrExit(error = Tlv::Append<JoinerRouterKekTlv>(*message, kek));
1176     }
1177 
1178     tlv.SetType(Tlv::kJoinerDtlsEncapsulation);
1179     tlv.SetLength(aMessage.GetLength());
1180     SuccessOrExit(error = message->Append(tlv));
1181     offset = message->GetLength();
1182     SuccessOrExit(error = message->SetLength(offset + aMessage.GetLength()));
1183     aMessage.CopyTo(0, offset, aMessage.GetLength(), *message);
1184 
1185     messageInfo.SetSockAddrToRlocPeerAddrTo(mJoinerRloc);
1186 
1187     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
1188 
1189     aMessage.Free();
1190 
1191 exit:
1192     FreeMessageOnError(message, error);
1193     return error;
1194 }
1195 
ApplyMeshLocalPrefix(void)1196 void Commissioner::ApplyMeshLocalPrefix(void)
1197 {
1198     VerifyOrExit(mState == kStateActive);
1199 
1200     Get<ThreadNetif>().RemoveUnicastAddress(mCommissionerAloc);
1201     mCommissionerAloc.GetAddress().SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
1202     Get<ThreadNetif>().AddUnicastAddress(mCommissionerAloc);
1203 
1204 exit:
1205     return;
1206 }
1207 
1208 // LCOV_EXCL_START
1209 
1210 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1211 
StateToString(State aState)1212 const char *Commissioner::StateToString(State aState)
1213 {
1214     static const char *const kStateStrings[] = {
1215         "disabled", // (0) kStateDisabled
1216         "petition", // (1) kStatePetition
1217         "active",   // (2) kStateActive
1218     };
1219 
1220     static_assert(kStateDisabled == 0, "kStateDisabled value is incorrect");
1221     static_assert(kStatePetition == 1, "kStatePetition value is incorrect");
1222     static_assert(kStateActive == 2, "kStateActive value is incorrect");
1223 
1224     return kStateStrings[aState];
1225 }
1226 
LogJoinerEntry(const char * aAction,const Joiner & aJoiner) const1227 void Commissioner::LogJoinerEntry(const char *aAction, const Joiner &aJoiner) const
1228 {
1229     switch (aJoiner.mType)
1230     {
1231     case Joiner::kTypeUnused:
1232         break;
1233 
1234     case Joiner::kTypeAny:
1235         LogInfo("%s Joiner (any, %s)", aAction, aJoiner.mPskd.GetAsCString());
1236         break;
1237 
1238     case Joiner::kTypeEui64:
1239         LogInfo("%s Joiner (eui64:%s, %s)", aAction, aJoiner.mSharedId.mEui64.ToString().AsCString(),
1240                 aJoiner.mPskd.GetAsCString());
1241         break;
1242 
1243     case Joiner::kTypeDiscerner:
1244         LogInfo("%s Joiner (disc:%s, %s)", aAction, aJoiner.mSharedId.mDiscerner.ToString().AsCString(),
1245                 aJoiner.mPskd.GetAsCString());
1246         break;
1247     }
1248 }
1249 
1250 #else
1251 
LogJoinerEntry(const char *,const Joiner &) const1252 void Commissioner::LogJoinerEntry(const char *, const Joiner &) const
1253 {
1254 }
1255 
1256 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1257 
1258 // LCOV_EXCL_STOP
1259 
1260 } // namespace MeshCoP
1261 } // namespace ot
1262 
1263 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
1264