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