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