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