1 /*
2 * Copyright (c) 2020, 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 managing DUA.
32 */
33
34 #include "dua_manager.hpp"
35
36 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
37
38 #include "common/as_core_type.hpp"
39 #include "common/code_utils.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/settings.hpp"
44 #include "net/ip6_address.hpp"
45 #include "thread/mle_types.hpp"
46 #include "thread/thread_netif.hpp"
47 #include "thread/thread_tlvs.hpp"
48 #include "thread/uri_paths.hpp"
49 #include "utils/slaac_address.hpp"
50
51 namespace ot {
52
53 RegisterLogModule("DuaManager");
54
DuaManager(Instance & aInstance)55 DuaManager::DuaManager(Instance &aInstance)
56 : InstanceLocator(aInstance)
57 , mRegistrationTask(aInstance)
58 , mIsDuaPending(false)
59 #if OPENTHREAD_CONFIG_DUA_ENABLE
60 , mDuaState(kNotExist)
61 , mDadCounter(0)
62 , mLastRegistrationTime(0)
63 #endif
64 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
65 , mChildIndexDuaRegistering(Mle::kMaxChildren)
66 #endif
67 {
68 mDelay.mValue = 0;
69
70 #if OPENTHREAD_CONFIG_DUA_ENABLE
71 mDomainUnicastAddress.InitAsThreadOriginGlobalScope();
72 mFixedDuaInterfaceIdentifier.Clear();
73 #endif
74
75 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
76 mChildDuaMask.Clear();
77 mChildDuaRegisteredMask.Clear();
78 #endif
79 }
80
HandleDomainPrefixUpdate(BackboneRouter::Leader::DomainPrefixState aState)81 void DuaManager::HandleDomainPrefixUpdate(BackboneRouter::Leader::DomainPrefixState aState)
82 {
83 if ((aState == BackboneRouter::Leader::kDomainPrefixRemoved) ||
84 (aState == BackboneRouter::Leader::kDomainPrefixRefreshed))
85 {
86 if (mIsDuaPending)
87 {
88 IgnoreError(Get<Tmf::Agent>().AbortTransaction(&DuaManager::HandleDuaResponse, this));
89 }
90
91 #if OPENTHREAD_CONFIG_DUA_ENABLE
92 RemoveDomainUnicastAddress();
93 #endif
94
95 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
96 if (mChildDuaMask.HasAny())
97 {
98 mChildDuaMask.Clear();
99 mChildDuaRegisteredMask.Clear();
100 }
101 #endif
102 }
103
104 #if OPENTHREAD_CONFIG_DUA_ENABLE
105 switch (aState)
106 {
107 case BackboneRouter::Leader::kDomainPrefixUnchanged:
108 // In case removed for some reason e.g. the kDuaInvalid response from PBBR forcefully
109 VerifyOrExit(!Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()));
110
111 OT_FALL_THROUGH;
112
113 case BackboneRouter::Leader::kDomainPrefixRefreshed:
114 case BackboneRouter::Leader::kDomainPrefixAdded:
115 {
116 const Ip6::Prefix *prefix = Get<BackboneRouter::Leader>().GetDomainPrefix();
117 OT_ASSERT(prefix != nullptr);
118 mDomainUnicastAddress.mPrefixLength = prefix->GetLength();
119 mDomainUnicastAddress.GetAddress().Clear();
120 mDomainUnicastAddress.GetAddress().SetPrefix(*prefix);
121 }
122 break;
123 default:
124 ExitNow();
125 }
126
127 // Apply cached DUA Interface Identifier manually specified.
128 if (IsFixedDuaInterfaceIdentifierSet())
129 {
130 mDomainUnicastAddress.GetAddress().SetIid(mFixedDuaInterfaceIdentifier);
131 }
132 else
133 {
134 SuccessOrExit(GenerateDomainUnicastAddressIid());
135 }
136
137 AddDomainUnicastAddress();
138
139 exit:
140 return;
141 #endif
142 }
143
144 #if OPENTHREAD_CONFIG_DUA_ENABLE
GenerateDomainUnicastAddressIid(void)145 Error DuaManager::GenerateDomainUnicastAddressIid(void)
146 {
147 Error error;
148 uint8_t dadCounter = mDadCounter;
149
150 if ((error = Get<Utils::Slaac>().GenerateIid(mDomainUnicastAddress, nullptr, 0, &dadCounter)) == kErrorNone)
151 {
152 if (dadCounter != mDadCounter)
153 {
154 mDadCounter = dadCounter;
155 IgnoreError(Store());
156 }
157
158 LogInfo("Generated DUA: %s", mDomainUnicastAddress.GetAddress().ToString().AsCString());
159 }
160 else
161 {
162 LogWarn("Generate DUA: %s", ErrorToString(error));
163 }
164
165 return error;
166 }
167
SetFixedDuaInterfaceIdentifier(const Ip6::InterfaceIdentifier & aIid)168 Error DuaManager::SetFixedDuaInterfaceIdentifier(const Ip6::InterfaceIdentifier &aIid)
169 {
170 Error error = kErrorNone;
171
172 VerifyOrExit(!aIid.IsReserved(), error = kErrorInvalidArgs);
173 VerifyOrExit(mFixedDuaInterfaceIdentifier.IsUnspecified() || mFixedDuaInterfaceIdentifier != aIid);
174
175 mFixedDuaInterfaceIdentifier = aIid;
176 LogInfo("Set DUA IID: %s", mFixedDuaInterfaceIdentifier.ToString().AsCString());
177
178 if (Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()))
179 {
180 RemoveDomainUnicastAddress();
181 mDomainUnicastAddress.GetAddress().SetIid(mFixedDuaInterfaceIdentifier);
182 AddDomainUnicastAddress();
183 }
184
185 exit:
186 return error;
187 }
188
ClearFixedDuaInterfaceIdentifier(void)189 void DuaManager::ClearFixedDuaInterfaceIdentifier(void)
190 {
191 // Nothing to clear.
192 VerifyOrExit(IsFixedDuaInterfaceIdentifierSet());
193
194 if (GetDomainUnicastAddress().GetIid() == mFixedDuaInterfaceIdentifier &&
195 Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()))
196 {
197 RemoveDomainUnicastAddress();
198
199 if (GenerateDomainUnicastAddressIid() == kErrorNone)
200 {
201 AddDomainUnicastAddress();
202 }
203 }
204
205 LogInfo("Cleared DUA IID: %s", mFixedDuaInterfaceIdentifier.ToString().AsCString());
206 mFixedDuaInterfaceIdentifier.Clear();
207
208 exit:
209 return;
210 }
211
Restore(void)212 void DuaManager::Restore(void)
213 {
214 Settings::DadInfo dadInfo;
215
216 SuccessOrExit(Get<Settings>().Read(dadInfo));
217 mDadCounter = dadInfo.GetDadCounter();
218
219 exit:
220 return;
221 }
222
Store(void)223 Error DuaManager::Store(void)
224 {
225 Settings::DadInfo dadInfo;
226
227 dadInfo.SetDadCounter(mDadCounter);
228 return Get<Settings>().Save(dadInfo);
229 }
230
AddDomainUnicastAddress(void)231 void DuaManager::AddDomainUnicastAddress(void)
232 {
233 mDuaState = kToRegister;
234 mLastRegistrationTime = TimerMilli::GetNow();
235 Get<ThreadNetif>().AddUnicastAddress(mDomainUnicastAddress);
236 }
237
RemoveDomainUnicastAddress(void)238 void DuaManager::RemoveDomainUnicastAddress(void)
239 {
240 if (mDuaState == kRegistering && mIsDuaPending)
241 {
242 IgnoreError(Get<Tmf::Agent>().AbortTransaction(&DuaManager::HandleDuaResponse, this));
243 }
244
245 mDuaState = kNotExist;
246 mDomainUnicastAddress.mPreferred = false;
247 Get<ThreadNetif>().RemoveUnicastAddress(mDomainUnicastAddress);
248 }
249
UpdateRegistrationDelay(uint8_t aDelay)250 void DuaManager::UpdateRegistrationDelay(uint8_t aDelay)
251 {
252 if (mDelay.mFields.mRegistrationDelay == 0 || mDelay.mFields.mRegistrationDelay > aDelay)
253 {
254 mDelay.mFields.mRegistrationDelay = aDelay;
255
256 LogDebg("update regdelay %d", mDelay.mFields.mRegistrationDelay);
257 UpdateTimeTickerRegistration();
258 }
259 }
260
NotifyDuplicateDomainUnicastAddress(void)261 void DuaManager::NotifyDuplicateDomainUnicastAddress(void)
262 {
263 RemoveDomainUnicastAddress();
264 mDadCounter++;
265
266 if (GenerateDomainUnicastAddressIid() == kErrorNone)
267 {
268 AddDomainUnicastAddress();
269 }
270 }
271 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
272
UpdateReregistrationDelay(void)273 void DuaManager::UpdateReregistrationDelay(void)
274 {
275 uint16_t delay = 0;
276 BackboneRouter::Config config;
277
278 VerifyOrExit(Get<BackboneRouter::Leader>().GetConfig(config) == kErrorNone);
279
280 delay = config.mReregistrationDelay > 1 ? Random::NonCrypto::GetUint16InRange(1, config.mReregistrationDelay) : 1;
281
282 if (mDelay.mFields.mReregistrationDelay == 0 || mDelay.mFields.mReregistrationDelay > delay)
283 {
284 mDelay.mFields.mReregistrationDelay = delay;
285 UpdateTimeTickerRegistration();
286 LogDebg("update reregdelay %d", mDelay.mFields.mReregistrationDelay);
287 }
288
289 exit:
290 return;
291 }
292
UpdateCheckDelay(uint8_t aDelay)293 void DuaManager::UpdateCheckDelay(uint8_t aDelay)
294 {
295 if (mDelay.mFields.mCheckDelay == 0 || mDelay.mFields.mCheckDelay > aDelay)
296 {
297 mDelay.mFields.mCheckDelay = aDelay;
298
299 LogDebg("update checkdelay %d", mDelay.mFields.mCheckDelay);
300 UpdateTimeTickerRegistration();
301 }
302 }
303
HandleNotifierEvents(Events aEvents)304 void DuaManager::HandleNotifierEvents(Events aEvents)
305 {
306 Mle::MleRouter &mle = Get<Mle::MleRouter>();
307
308 #if OPENTHREAD_CONFIG_DUA_ENABLE
309 if (aEvents.Contains(kEventThreadNetdataChanged))
310 {
311 Lowpan::Context context;
312 // Remove a stale DUA address if any.
313 if (Get<ThreadNetif>().HasUnicastAddress(Get<DuaManager>().GetDomainUnicastAddress()) &&
314 (Get<NetworkData::Leader>().GetContext(Get<DuaManager>().GetDomainUnicastAddress(), context) != kErrorNone))
315 {
316 RemoveDomainUnicastAddress();
317 }
318 }
319 #endif
320
321 VerifyOrExit(mle.IsAttached(), mDelay.mValue = 0);
322
323 if (aEvents.Contains(kEventThreadRoleChanged))
324 {
325 if (mle.HasRestored())
326 {
327 UpdateReregistrationDelay();
328 }
329 #if OPENTHREAD_CONFIG_DUA_ENABLE && OPENTHREAD_FTD
330 else if (mle.IsRouter())
331 {
332 // Wait for link establishment with neighboring routers.
333 UpdateRegistrationDelay(kNewRouterRegistrationDelay);
334 }
335 else if (mle.IsExpectedToBecomeRouterSoon())
336 {
337 // Will check again in case the device decides to stay REED when jitter timeout expires.
338 UpdateRegistrationDelay(mle.GetRouterSelectionJitterTimeout() + kNewRouterRegistrationDelay + 1);
339 }
340 #endif
341 }
342
343 #if OPENTHREAD_CONFIG_DUA_ENABLE
344 if (aEvents.ContainsAny(kEventIp6AddressAdded))
345 {
346 UpdateRegistrationDelay(kNewDuaRegistrationDelay);
347 }
348 #endif
349
350 exit:
351 return;
352 }
353
HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState,const BackboneRouter::Config & aConfig)354 void DuaManager::HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState,
355 const BackboneRouter::Config &aConfig)
356 {
357 OT_UNUSED_VARIABLE(aConfig);
358
359 if (aState == BackboneRouter::Leader::kStateAdded || aState == BackboneRouter::Leader::kStateToTriggerRereg)
360 {
361 #if OPENTHREAD_CONFIG_DUA_ENABLE
362 if (Get<Mle::Mle>().IsFullThreadDevice() || Get<Mle::Mle>().GetParent().IsThreadVersion1p1())
363 #endif
364 {
365 UpdateReregistrationDelay();
366 }
367 }
368 }
369
HandleTimeTick(void)370 void DuaManager::HandleTimeTick(void)
371 {
372 bool attempt = false;
373
374 #if OPENTHREAD_CONFIG_DUA_ENABLE
375 LogDebg("regdelay %d, reregdelay %d, checkdelay %d", mDelay.mFields.mRegistrationDelay,
376 mDelay.mFields.mReregistrationDelay, mDelay.mFields.mCheckDelay);
377
378 if ((mDuaState != kNotExist) &&
379 (TimerMilli::GetNow() > (mLastRegistrationTime + TimeMilli::SecToMsec(Mle::kDuaDadPeriod))))
380 {
381 mDomainUnicastAddress.mPreferred = true;
382 }
383
384 if ((mDelay.mFields.mRegistrationDelay > 0) && (--mDelay.mFields.mRegistrationDelay == 0))
385 {
386 attempt = true;
387 }
388 #else
389 LogDebg("reregdelay %d, checkdelay %d", mDelay.mFields.mReregistrationDelay, mDelay.mFields.mCheckDelay);
390 #endif
391
392 if ((mDelay.mFields.mCheckDelay > 0) && (--mDelay.mFields.mCheckDelay == 0))
393 {
394 attempt = true;
395 }
396
397 if ((mDelay.mFields.mReregistrationDelay > 0) && (--mDelay.mFields.mReregistrationDelay == 0))
398 {
399 #if OPENTHREAD_CONFIG_DUA_ENABLE
400 if (mDuaState != kNotExist)
401 {
402 mDuaState = kToRegister;
403 }
404 #endif
405
406 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
407 mChildDuaRegisteredMask.Clear();
408 #endif
409 attempt = true;
410 }
411
412 if (attempt)
413 {
414 mRegistrationTask.Post();
415 }
416
417 UpdateTimeTickerRegistration();
418 }
419
UpdateTimeTickerRegistration(void)420 void DuaManager::UpdateTimeTickerRegistration(void)
421 {
422 if (mDelay.mValue == 0)
423 {
424 Get<TimeTicker>().UnregisterReceiver(TimeTicker::kDuaManager);
425 }
426 else
427 {
428 Get<TimeTicker>().RegisterReceiver(TimeTicker::kDuaManager);
429 }
430 }
431
PerformNextRegistration(void)432 void DuaManager::PerformNextRegistration(void)
433 {
434 Error error = kErrorNone;
435 Mle::MleRouter &mle = Get<Mle::MleRouter>();
436 Coap::Message *message = nullptr;
437 Tmf::MessageInfo messageInfo(GetInstance());
438 Ip6::Address dua;
439
440 VerifyOrExit(mle.IsAttached(), error = kErrorInvalidState);
441 VerifyOrExit(Get<BackboneRouter::Leader>().HasPrimary(), error = kErrorInvalidState);
442
443 // Only allow one outgoing DUA.req
444 VerifyOrExit(!mIsDuaPending, error = kErrorBusy);
445
446 // Only send DUA.req when necessary
447 #if OPENTHREAD_CONFIG_DUA_ENABLE
448 #if OPENTHREAD_FTD
449 VerifyOrExit(mle.IsRouterOrLeader() || !mle.IsExpectedToBecomeRouterSoon(), error = kErrorInvalidState);
450 #endif
451 VerifyOrExit(mle.IsFullThreadDevice() || mle.GetParent().IsThreadVersion1p1(), error = kErrorInvalidState);
452 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
453
454 {
455 bool needReg = false;
456
457 #if OPENTHREAD_CONFIG_DUA_ENABLE
458 needReg = (mDuaState == kToRegister && mDelay.mFields.mRegistrationDelay == 0);
459 #endif
460
461 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
462 needReg = needReg || (mChildDuaMask.HasAny() && mChildDuaMask != mChildDuaRegisteredMask);
463 #endif
464 VerifyOrExit(needReg, error = kErrorNotFound);
465 }
466
467 // Prepare DUA.req
468 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriDuaRegistrationRequest);
469 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
470
471 #if OPENTHREAD_CONFIG_DUA_ENABLE
472 if (mDuaState == kToRegister && mDelay.mFields.mRegistrationDelay == 0)
473 {
474 dua = GetDomainUnicastAddress();
475 SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, dua));
476 SuccessOrExit(error = Tlv::Append<ThreadMeshLocalEidTlv>(*message, mle.GetMeshLocal64().GetIid()));
477 mDuaState = kRegistering;
478 mLastRegistrationTime = TimerMilli::GetNow();
479 }
480 else
481 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
482 {
483 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
484 uint32_t lastTransactionTime;
485 const Ip6::Address *duaPtr = nullptr;
486 Child *child = nullptr;
487
488 OT_ASSERT(mChildIndexDuaRegistering == Mle::kMaxChildren);
489
490 for (Child &iter : Get<ChildTable>().Iterate(Child::kInStateValid))
491 {
492 uint16_t childIndex = Get<ChildTable>().GetChildIndex(iter);
493
494 if (mChildDuaMask.Get(childIndex) && !mChildDuaRegisteredMask.Get(childIndex))
495 {
496 mChildIndexDuaRegistering = childIndex;
497 break;
498 }
499 }
500
501 child = Get<ChildTable>().GetChildAtIndex(mChildIndexDuaRegistering);
502 duaPtr = child->GetDomainUnicastAddress();
503
504 OT_ASSERT(duaPtr != nullptr);
505
506 dua = *duaPtr;
507 SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, dua));
508 SuccessOrExit(error = Tlv::Append<ThreadMeshLocalEidTlv>(*message, child->GetMeshLocalIid()));
509
510 lastTransactionTime = Time::MsecToSec(TimerMilli::GetNow() - child->GetLastHeard());
511 SuccessOrExit(error = Tlv::Append<ThreadLastTransactionTimeTlv>(*message, lastTransactionTime));
512 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
513 }
514
515 if (!mle.IsFullThreadDevice() && mle.GetParent().IsThreadVersion1p1())
516 {
517 uint8_t pbbrServiceId;
518
519 SuccessOrExit(error = Get<BackboneRouter::Leader>().GetServiceId(pbbrServiceId));
520 SuccessOrExit(error = mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr()));
521 }
522 else
523 {
524 messageInfo.GetPeerAddr().SetToRoutingLocator(mle.GetMeshLocalPrefix(),
525 Get<BackboneRouter::Leader>().GetServer16());
526 }
527
528 messageInfo.SetSockAddrToRloc();
529
530 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &DuaManager::HandleDuaResponse, this));
531
532 mIsDuaPending = true;
533 mRegisteringDua = dua;
534 mDelay.mValue = 0;
535
536 // Generally Thread 1.2 Router would send DUA.req on behalf for DUA registered by its MTD child.
537 // When Thread 1.2 MTD attaches to Thread 1.1 parent, 1.2 MTD should send DUA.req to PBBR itself.
538 // In this case, Thread 1.2 sleepy end device relies on fast data poll to fetch the response timely.
539 if (!Get<Mle::Mle>().IsRxOnWhenIdle())
540 {
541 Get<DataPollSender>().SendFastPolls();
542 }
543
544 LogInfo("Sent %s for DUA %s", UriToString<kUriDuaRegistrationRequest>(), dua.ToString().AsCString());
545
546 exit:
547 if (error == kErrorNoBufs)
548 {
549 UpdateCheckDelay(Mle::kNoBufDelay);
550 }
551
552 LogInfo("PerformNextRegistration: %s", ErrorToString(error));
553 FreeMessageOnError(message, error);
554 }
555
HandleDuaResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)556 void DuaManager::HandleDuaResponse(void *aContext,
557 otMessage *aMessage,
558 const otMessageInfo *aMessageInfo,
559 Error aResult)
560 {
561 static_cast<DuaManager *>(aContext)->HandleDuaResponse(AsCoapMessagePtr(aMessage), AsCoreTypePtr(aMessageInfo),
562 aResult);
563 }
564
HandleDuaResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)565 void DuaManager::HandleDuaResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult)
566 {
567 OT_UNUSED_VARIABLE(aMessageInfo);
568 Error error;
569
570 mIsDuaPending = false;
571 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
572 mChildIndexDuaRegistering = Mle::kMaxChildren;
573 #endif
574
575 if (aResult == kErrorResponseTimeout)
576 {
577 UpdateCheckDelay(Mle::KResponseTimeoutDelay);
578 ExitNow(error = aResult);
579 }
580
581 VerifyOrExit(aResult == kErrorNone, error = kErrorParse);
582 OT_ASSERT(aMessage != nullptr);
583
584 VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged || aMessage->GetCode() >= Coap::kCodeBadRequest,
585 error = kErrorParse);
586
587 error = ProcessDuaResponse(*aMessage);
588
589 exit:
590 if (error != kErrorResponseTimeout)
591 {
592 mRegistrationTask.Post();
593 }
594
595 LogInfo("Received %s response: %s", UriToString<kUriDuaRegistrationRequest>(), ErrorToString(error));
596 }
597
598 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)599 void DuaManager::HandleTmf<kUriDuaRegistrationNotify>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
600 {
601 OT_UNUSED_VARIABLE(aMessageInfo);
602
603 Error error;
604
605 VerifyOrExit(aMessage.IsPostRequest(), error = kErrorParse);
606
607 if (aMessage.IsConfirmable() && Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo) == kErrorNone)
608 {
609 LogInfo("Sent %s ack", UriToString<kUriDuaRegistrationNotify>());
610 }
611
612 error = ProcessDuaResponse(aMessage);
613
614 exit:
615 OT_UNUSED_VARIABLE(error);
616 LogInfo("Received %s: %s", UriToString<kUriDuaRegistrationNotify>(), ErrorToString(error));
617 }
618
ProcessDuaResponse(Coap::Message & aMessage)619 Error DuaManager::ProcessDuaResponse(Coap::Message &aMessage)
620 {
621 Error error = kErrorNone;
622 Ip6::Address target;
623 uint8_t status;
624
625 if (aMessage.GetCode() >= Coap::kCodeBadRequest)
626 {
627 status = ThreadStatusTlv::kDuaGeneralFailure;
628 target = mRegisteringDua;
629 }
630 else
631 {
632 SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, status));
633 SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMessage, target));
634 }
635
636 VerifyOrExit(Get<BackboneRouter::Leader>().IsDomainUnicast(target), error = kErrorDrop);
637
638 #if OPENTHREAD_CONFIG_DUA_ENABLE
639 if (Get<ThreadNetif>().HasUnicastAddress(target))
640 {
641 switch (static_cast<ThreadStatusTlv::DuaStatus>(status))
642 {
643 case ThreadStatusTlv::kDuaSuccess:
644 mLastRegistrationTime = TimerMilli::GetNow();
645 mDuaState = kRegistered;
646 break;
647 case ThreadStatusTlv::kDuaReRegister:
648 if (Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()))
649 {
650 RemoveDomainUnicastAddress();
651 AddDomainUnicastAddress();
652 }
653 break;
654 case ThreadStatusTlv::kDuaInvalid:
655 // Domain Prefix might be invalid.
656 RemoveDomainUnicastAddress();
657 break;
658 case ThreadStatusTlv::kDuaDuplicate:
659 NotifyDuplicateDomainUnicastAddress();
660 break;
661 case ThreadStatusTlv::kDuaNoResources:
662 case ThreadStatusTlv::kDuaNotPrimary:
663 case ThreadStatusTlv::kDuaGeneralFailure:
664 UpdateReregistrationDelay();
665 break;
666 }
667 }
668 else
669 #endif
670 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
671 {
672 Child *child = nullptr;
673 uint16_t childIndex;
674
675 for (Child &iter : Get<ChildTable>().Iterate(Child::kInStateValid))
676 {
677 if (iter.HasIp6Address(target))
678 {
679 child = &iter;
680 break;
681 }
682 }
683
684 VerifyOrExit(child != nullptr, error = kErrorNotFound);
685
686 childIndex = Get<ChildTable>().GetChildIndex(*child);
687
688 switch (status)
689 {
690 case ThreadStatusTlv::kDuaSuccess:
691 // Mark as Registered
692 if (mChildDuaMask.Get(childIndex))
693 {
694 mChildDuaRegisteredMask.Set(childIndex, true);
695 }
696 break;
697 case ThreadStatusTlv::kDuaReRegister:
698 // Parent stops registering for the Child's DUA until next Child Update Request
699 mChildDuaMask.Set(childIndex, false);
700 mChildDuaRegisteredMask.Set(childIndex, false);
701 break;
702 case ThreadStatusTlv::kDuaInvalid:
703 case ThreadStatusTlv::kDuaDuplicate:
704 IgnoreError(child->RemoveIp6Address(target));
705 mChildDuaMask.Set(childIndex, false);
706 mChildDuaRegisteredMask.Set(childIndex, false);
707 break;
708 case ThreadStatusTlv::kDuaNoResources:
709 case ThreadStatusTlv::kDuaNotPrimary:
710 case ThreadStatusTlv::kDuaGeneralFailure:
711 UpdateReregistrationDelay();
712 break;
713 }
714
715 if (status != ThreadStatusTlv::kDuaSuccess)
716 {
717 SendAddressNotification(target, static_cast<ThreadStatusTlv::DuaStatus>(status), *child);
718 }
719 }
720 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
721
722 exit:
723 UpdateTimeTickerRegistration();
724 return error;
725 }
726
727 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
SendAddressNotification(Ip6::Address & aAddress,ThreadStatusTlv::DuaStatus aStatus,const Child & aChild)728 void DuaManager::SendAddressNotification(Ip6::Address &aAddress,
729 ThreadStatusTlv::DuaStatus aStatus,
730 const Child &aChild)
731 {
732 Coap::Message *message = nullptr;
733 Tmf::MessageInfo messageInfo(GetInstance());
734 Error error;
735
736 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriDuaRegistrationNotify);
737 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
738
739 SuccessOrExit(error = Tlv::Append<ThreadStatusTlv>(*message, aStatus));
740 SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, aAddress));
741
742 messageInfo.SetSockAddrToRlocPeerAddrTo(aChild.GetRloc16());
743
744 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
745
746 LogInfo("Sent %s for child %04x DUA %s", UriToString<kUriDuaRegistrationNotify>(), aChild.GetRloc16(),
747 aAddress.ToString().AsCString());
748
749 exit:
750
751 if (error != kErrorNone)
752 {
753 FreeMessage(message);
754
755 // TODO: (DUA) (P4) may enhance to guarantee the delivery of DUA.ntf
756 LogWarn("Sent %s for child %04x DUA %s Error %s", UriToString<kUriDuaRegistrationNotify>(), aChild.GetRloc16(),
757 aAddress.ToString().AsCString(), ErrorToString(error));
758 }
759 }
760
UpdateChildDomainUnicastAddress(const Child & aChild,Mle::ChildDuaState aState)761 void DuaManager::UpdateChildDomainUnicastAddress(const Child &aChild, Mle::ChildDuaState aState)
762 {
763 uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
764
765 if ((aState == Mle::ChildDuaState::kRemoved || aState == Mle::ChildDuaState::kChanged) &&
766 mChildDuaMask.Get(childIndex))
767 {
768 // Abort on going proxy DUA.req for this child
769 if (mChildIndexDuaRegistering == childIndex)
770 {
771 IgnoreError(Get<Tmf::Agent>().AbortTransaction(&DuaManager::HandleDuaResponse, this));
772 }
773
774 mChildDuaMask.Set(childIndex, false);
775 mChildDuaRegisteredMask.Set(childIndex, false);
776 }
777
778 if (aState == Mle::ChildDuaState::kAdded || aState == Mle::ChildDuaState::kChanged ||
779 (aState == Mle::ChildDuaState::kUnchanged && !mChildDuaMask.Get(childIndex)))
780 {
781 if (mChildDuaMask == mChildDuaRegisteredMask)
782 {
783 UpdateCheckDelay(Random::NonCrypto::GetUint8InRange(1, Mle::kParentAggregateDelay));
784 }
785
786 mChildDuaMask.Set(childIndex, true);
787 mChildDuaRegisteredMask.Set(childIndex, false);
788 }
789 }
790 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
791
792 } // namespace ot
793
794 #endif // OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
795