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