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