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 MLR management.
32 */
33
34 #include "mlr_manager.hpp"
35
36 #if OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
37
38 #include "common/code_utils.hpp"
39 #include "common/instance.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/logging.hpp"
42 #include "net/ip6_address.hpp"
43 #include "thread/thread_netif.hpp"
44 #include "thread/uri_paths.hpp"
45 #include "utils/slaac_address.hpp"
46
47 namespace ot {
48
MlrManager(Instance & aInstance)49 MlrManager::MlrManager(Instance &aInstance)
50 : InstanceLocator(aInstance)
51 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
52 , mRegisterMulticastListenersCallback(nullptr)
53 , mRegisterMulticastListenersContext(nullptr)
54 #endif
55 , mReregistrationDelay(0)
56 , mSendDelay(0)
57 , mMlrPending(false)
58 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
59 , mRegisterMulticastListenersPending(false)
60 #endif
61 {
62 }
63
HandleNotifierEvents(Events aEvents)64 void MlrManager::HandleNotifierEvents(Events aEvents)
65 {
66 #if OPENTHREAD_CONFIG_MLR_ENABLE
67 if (aEvents.Contains(kEventIp6MulticastSubscribed))
68 {
69 UpdateLocalSubscriptions();
70 }
71 #endif
72
73 if (aEvents.Contains(kEventThreadRoleChanged) && Get<Mle::MleRouter>().IsChild())
74 {
75 // Reregistration after re-attach
76 UpdateReregistrationDelay(true);
77 }
78 }
79
HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState,const BackboneRouter::BackboneRouterConfig & aConfig)80 void MlrManager::HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState,
81 const BackboneRouter::BackboneRouterConfig &aConfig)
82 {
83 OT_UNUSED_VARIABLE(aConfig);
84
85 bool needRereg =
86 aState == BackboneRouter::Leader::kStateAdded || aState == BackboneRouter::Leader::kStateToTriggerRereg;
87
88 UpdateReregistrationDelay(needRereg);
89 }
90
91 #if OPENTHREAD_CONFIG_MLR_ENABLE
UpdateLocalSubscriptions(void)92 void MlrManager::UpdateLocalSubscriptions(void)
93 {
94 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
95 // Check multicast addresses are newly listened against Children
96 for (Ip6::Netif::ExternalMulticastAddress &addr :
97 Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
98 {
99 if (addr.GetMlrState() == kMlrStateToRegister && IsAddressMlrRegisteredByAnyChild(addr.GetAddress()))
100 {
101 addr.SetMlrState(kMlrStateRegistered);
102 }
103 }
104 #endif
105
106 CheckInvariants();
107 ScheduleSend(0);
108 }
109
IsAddressMlrRegisteredByNetif(const Ip6::Address & aAddress) const110 bool MlrManager::IsAddressMlrRegisteredByNetif(const Ip6::Address &aAddress) const
111 {
112 bool ret = false;
113
114 OT_ASSERT(aAddress.IsMulticastLargerThanRealmLocal());
115
116 for (const Ip6::Netif::ExternalMulticastAddress &addr : Get<ThreadNetif>().IterateExternalMulticastAddresses())
117 {
118 if (addr.GetAddress() == aAddress && addr.GetMlrState() == kMlrStateRegistered)
119 {
120 ExitNow(ret = true);
121 }
122 }
123
124 exit:
125 return ret;
126 }
127
128 #endif // OPENTHREAD_CONFIG_MLR_ENABLE
129
130 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
131
IsAddressMlrRegisteredByAnyChildExcept(const Ip6::Address & aAddress,const Child * aExceptChild) const132 bool MlrManager::IsAddressMlrRegisteredByAnyChildExcept(const Ip6::Address &aAddress, const Child *aExceptChild) const
133 {
134 bool ret = false;
135
136 OT_ASSERT(aAddress.IsMulticastLargerThanRealmLocal());
137
138 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
139 {
140 if (&child != aExceptChild && child.HasMlrRegisteredAddress(aAddress))
141 {
142 ExitNow(ret = true);
143 }
144 }
145
146 exit:
147 return ret;
148 }
149
UpdateProxiedSubscriptions(Child & aChild,const Ip6::Address * aOldMlrRegisteredAddresses,uint16_t aOldMlrRegisteredAddressNum)150 void MlrManager::UpdateProxiedSubscriptions(Child & aChild,
151 const Ip6::Address *aOldMlrRegisteredAddresses,
152 uint16_t aOldMlrRegisteredAddressNum)
153 {
154 VerifyOrExit(aChild.IsStateValid());
155
156 // Search the new multicast addresses and set its flag accordingly
157 for (const Ip6::Address &address : aChild.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
158 {
159 bool isMlrRegistered = false;
160
161 // Check if it's a new multicast address against old addresses
162 for (size_t i = 0; i < aOldMlrRegisteredAddressNum; i++)
163 {
164 if (aOldMlrRegisteredAddresses[i] == address)
165 {
166 isMlrRegistered = true;
167 break;
168 }
169 }
170
171 #if OPENTHREAD_CONFIG_MLR_ENABLE
172 // Check if it's a new multicast address against parent Netif
173 isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByNetif(address);
174 #endif
175 // Check if it's a new multicast address against other Children
176 isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByAnyChildExcept(address, &aChild);
177
178 aChild.SetAddressMlrState(address, isMlrRegistered ? kMlrStateRegistered : kMlrStateToRegister);
179 }
180
181 exit:
182 LogMulticastAddresses();
183 CheckInvariants();
184
185 if (aChild.HasAnyMlrToRegisterAddress())
186 {
187 ScheduleSend(Random::NonCrypto::GetUint16InRange(1, Mle::kParentAggregateDelay));
188 }
189 }
190
191 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
192
ScheduleSend(uint16_t aDelay)193 void MlrManager::ScheduleSend(uint16_t aDelay)
194 {
195 OT_ASSERT(!mMlrPending || mSendDelay == 0);
196
197 VerifyOrExit(!mMlrPending);
198
199 if (aDelay == 0)
200 {
201 mSendDelay = 0;
202 SendMulticastListenerRegistration();
203 }
204 else if (mSendDelay == 0 || mSendDelay > aDelay)
205 {
206 mSendDelay = aDelay;
207 }
208
209 UpdateTimeTickerRegistration();
210 exit:
211 return;
212 }
213
UpdateTimeTickerRegistration(void)214 void MlrManager::UpdateTimeTickerRegistration(void)
215 {
216 if (mSendDelay == 0 && mReregistrationDelay == 0)
217 {
218 Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMlrManager);
219 }
220 else
221 {
222 Get<TimeTicker>().RegisterReceiver(TimeTicker::kMlrManager);
223 }
224 }
225
SendMulticastListenerRegistration(void)226 void MlrManager::SendMulticastListenerRegistration(void)
227 {
228 Error error;
229 Mle::MleRouter &mle = Get<Mle::MleRouter>();
230 Ip6::Address addresses[kIp6AddressesNumMax];
231 uint8_t addressesNum = 0;
232
233 VerifyOrExit(!mMlrPending, error = kErrorBusy);
234 VerifyOrExit(mle.IsAttached(), error = kErrorInvalidState);
235 VerifyOrExit(mle.IsFullThreadDevice() || mle.GetParent().IsThreadVersion1p1(), error = kErrorInvalidState);
236 VerifyOrExit(Get<BackboneRouter::Leader>().HasPrimary(), error = kErrorInvalidState);
237
238 #if OPENTHREAD_CONFIG_MLR_ENABLE
239 // Append Netif multicast addresses
240 for (Ip6::Netif::ExternalMulticastAddress &addr :
241 Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
242 {
243 if (addressesNum >= kIp6AddressesNumMax)
244 {
245 break;
246 }
247
248 if (addr.GetMlrState() == kMlrStateToRegister)
249 {
250 AppendToUniqueAddressList(addresses, addressesNum, addr.GetAddress());
251 addr.SetMlrState(kMlrStateRegistering);
252 }
253 }
254 #endif
255
256 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
257 // Append Child multicast addresses
258 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
259 {
260 if (addressesNum >= kIp6AddressesNumMax)
261 {
262 break;
263 }
264
265 if (!child.HasAnyMlrToRegisterAddress())
266 {
267 continue;
268 }
269
270 for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
271 {
272 if (addressesNum >= kIp6AddressesNumMax)
273 {
274 break;
275 }
276
277 if (child.GetAddressMlrState(address) == kMlrStateToRegister)
278 {
279 AppendToUniqueAddressList(addresses, addressesNum, address);
280 child.SetAddressMlrState(address, kMlrStateRegistering);
281 }
282 }
283 }
284 #endif
285
286 VerifyOrExit(addressesNum > 0, error = kErrorNotFound);
287 SuccessOrExit(
288 error = SendMulticastListenerRegistrationMessage(
289 addresses, addressesNum, nullptr, &MlrManager::HandleMulticastListenerRegistrationResponse, this));
290
291 mMlrPending = true;
292
293 // Generally Thread 1.2 Router would send MLR.req on bebelf for MA (scope >=4) subscribed by its MTD child.
294 // When Thread 1.2 MTD attaches to Thread 1.1 parent, 1.2 MTD should send MLR.req to PBBR itself.
295 // In this case, Thread 1.2 sleepy end device relies on fast data poll to fetch the response timely.
296 if (!Get<Mle::Mle>().IsRxOnWhenIdle())
297 {
298 Get<DataPollSender>().SendFastPolls();
299 }
300
301 exit:
302 if (error != kErrorNone)
303 {
304 SetMulticastAddressMlrState(kMlrStateRegistering, kMlrStateToRegister);
305
306 if (error == kErrorNoBufs)
307 {
308 ScheduleSend(1);
309 }
310 }
311
312 LogMulticastAddresses();
313 CheckInvariants();
314 }
315
316 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
RegisterMulticastListeners(const otIp6Address * aAddresses,uint8_t aAddressNum,const uint32_t * aTimeout,otIp6RegisterMulticastListenersCallback aCallback,void * aContext)317 Error MlrManager::RegisterMulticastListeners(const otIp6Address * aAddresses,
318 uint8_t aAddressNum,
319 const uint32_t * aTimeout,
320 otIp6RegisterMulticastListenersCallback aCallback,
321 void * aContext)
322 {
323 Error error;
324
325 VerifyOrExit(aAddresses != nullptr, error = kErrorInvalidArgs);
326 VerifyOrExit(aAddressNum > 0 && aAddressNum <= kIp6AddressesNumMax, error = kErrorInvalidArgs);
327 VerifyOrExit(aContext == nullptr || aCallback != nullptr, error = kErrorInvalidArgs);
328 #if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
329 VerifyOrExit(Get<MeshCoP::Commissioner>().IsActive(), error = kErrorInvalidState);
330 #else
331 if (!Get<MeshCoP::Commissioner>().IsActive())
332 {
333 otLogWarnMlr("MLR.req without active commissioner session for test.");
334 }
335 #endif
336
337 // Only allow one outstanding registration if callback is specified.
338 VerifyOrExit(!mRegisterMulticastListenersPending, error = kErrorBusy);
339
340 SuccessOrExit(error = SendMulticastListenerRegistrationMessage(
341 aAddresses, aAddressNum, aTimeout, &MlrManager::HandleRegisterMulticastListenersResponse, this));
342
343 mRegisterMulticastListenersPending = true;
344 mRegisterMulticastListenersCallback = aCallback;
345 mRegisterMulticastListenersContext = aContext;
346
347 exit:
348 return error;
349 }
350
HandleRegisterMulticastListenersResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)351 void MlrManager::HandleRegisterMulticastListenersResponse(void * aContext,
352 otMessage * aMessage,
353 const otMessageInfo *aMessageInfo,
354 Error aResult)
355 {
356 static_cast<MlrManager *>(aContext)->HandleRegisterMulticastListenersResponse(
357 static_cast<Coap::Message *>(aMessage), static_cast<const Ip6::MessageInfo *>(aMessageInfo), aResult);
358 }
359
HandleRegisterMulticastListenersResponse(otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)360 void MlrManager::HandleRegisterMulticastListenersResponse(otMessage * aMessage,
361 const otMessageInfo *aMessageInfo,
362 Error aResult)
363 {
364 OT_UNUSED_VARIABLE(aMessageInfo);
365
366 uint8_t status;
367 Error error;
368 Ip6::Address failedAddresses[kIp6AddressesNumMax];
369 uint8_t failedAddressNum = 0;
370 otIp6RegisterMulticastListenersCallback callback = mRegisterMulticastListenersCallback;
371 void * context = mRegisterMulticastListenersContext;
372
373 mRegisterMulticastListenersPending = false;
374 mRegisterMulticastListenersCallback = nullptr;
375 mRegisterMulticastListenersContext = nullptr;
376
377 error = ParseMulticastListenerRegistrationResponse(aResult, static_cast<Coap::Message *>(aMessage), status,
378 failedAddresses, failedAddressNum);
379
380 if (callback != nullptr)
381 {
382 callback(context, error, status, failedAddresses, failedAddressNum);
383 }
384 }
385
386 #endif // (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
387
SendMulticastListenerRegistrationMessage(const otIp6Address * aAddresses,uint8_t aAddressNum,const uint32_t * aTimeout,Coap::ResponseHandler aResponseHandler,void * aResponseContext)388 Error MlrManager::SendMulticastListenerRegistrationMessage(const otIp6Address * aAddresses,
389 uint8_t aAddressNum,
390 const uint32_t * aTimeout,
391 Coap::ResponseHandler aResponseHandler,
392 void * aResponseContext)
393 {
394 OT_UNUSED_VARIABLE(aTimeout);
395
396 Error error = kErrorNone;
397 Mle::MleRouter & mle = Get<Mle::MleRouter>();
398 Coap::Message * message = nullptr;
399 Ip6::MessageInfo messageInfo;
400 Ip6AddressesTlv addressesTlv;
401
402 VerifyOrExit(Get<BackboneRouter::Leader>().HasPrimary(), error = kErrorInvalidState);
403
404 VerifyOrExit((message = Get<Tmf::Agent>().NewMessage()) != nullptr, error = kErrorNoBufs);
405
406 message->InitAsConfirmablePost();
407 SuccessOrExit(message->GenerateRandomToken(Coap::Message::kDefaultTokenLength));
408 SuccessOrExit(message->AppendUriPathOptions(UriPath::kMlr));
409 SuccessOrExit(message->SetPayloadMarker());
410
411 addressesTlv.Init();
412 addressesTlv.SetLength(sizeof(Ip6::Address) * aAddressNum);
413 SuccessOrExit(error = message->Append(addressesTlv));
414 SuccessOrExit(error = message->AppendBytes(aAddresses, sizeof(Ip6::Address) * aAddressNum));
415
416 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
417 if (Get<MeshCoP::Commissioner>().IsActive())
418 {
419 SuccessOrExit(
420 error = Tlv::Append<ThreadCommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
421 }
422
423 if (aTimeout != nullptr)
424 {
425 SuccessOrExit(error = Tlv::Append<ThreadTimeoutTlv>(*message, *aTimeout));
426 }
427 #else
428 OT_ASSERT(aTimeout == nullptr);
429 #endif
430
431 if (!mle.IsFullThreadDevice() && mle.GetParent().IsThreadVersion1p1())
432 {
433 uint8_t pbbrServiceId;
434
435 SuccessOrExit(error = Get<BackboneRouter::Leader>().GetServiceId(pbbrServiceId));
436 SuccessOrExit(error = mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr()));
437 }
438 else
439 {
440 messageInfo.GetPeerAddr().SetToRoutingLocator(mle.GetMeshLocalPrefix(),
441 Get<BackboneRouter::Leader>().GetServer16());
442 }
443
444 messageInfo.SetPeerPort(Tmf::kUdpPort);
445 messageInfo.SetSockAddr(mle.GetMeshLocal16());
446
447 error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, aResponseHandler, aResponseContext);
448
449 otLogInfoMlr("Sent MLR.req: addressNum=%d", aAddressNum);
450
451 exit:
452 otLogInfoMlr("SendMulticastListenerRegistrationMessage(): %s", ErrorToString(error));
453 FreeMessageOnError(message, error);
454 return error;
455 }
456
HandleMulticastListenerRegistrationResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)457 void MlrManager::HandleMulticastListenerRegistrationResponse(void * aContext,
458 otMessage * aMessage,
459 const otMessageInfo *aMessageInfo,
460 Error aResult)
461 {
462 static_cast<MlrManager *>(aContext)->HandleMulticastListenerRegistrationResponse(
463 static_cast<Coap::Message *>(aMessage), static_cast<const Ip6::MessageInfo *>(aMessageInfo), aResult);
464 }
465
HandleMulticastListenerRegistrationResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)466 void MlrManager::HandleMulticastListenerRegistrationResponse(Coap::Message * aMessage,
467 const Ip6::MessageInfo *aMessageInfo,
468 Error aResult)
469 {
470 OT_UNUSED_VARIABLE(aMessageInfo);
471
472 uint8_t status;
473 Error error;
474 Ip6::Address failedAddresses[kIp6AddressesNumMax];
475 uint8_t failedAddressNum = 0;
476
477 error = ParseMulticastListenerRegistrationResponse(aResult, aMessage, status, failedAddresses, failedAddressNum);
478
479 FinishMulticastListenerRegistration(error == kErrorNone && status == ThreadStatusTlv::MlrStatus::kMlrSuccess,
480 failedAddresses, failedAddressNum);
481
482 if (error == kErrorNone && status == ThreadStatusTlv::MlrStatus::kMlrSuccess)
483 {
484 // keep sending until all multicast addresses are registered.
485 ScheduleSend(0);
486 }
487 else
488 {
489 otBackboneRouterConfig config;
490 uint16_t reregDelay;
491
492 // The Device has just attempted a Multicast Listener Registration which failed, and it retries the same
493 // registration with a random time delay chosen in the interval [0, Reregistration Delay].
494 // This is required by Thread 1.2 Specification 5.24.2.3
495 if (Get<BackboneRouter::Leader>().GetConfig(config) == kErrorNone)
496 {
497 reregDelay = config.mReregistrationDelay > 1
498 ? Random::NonCrypto::GetUint16InRange(1, config.mReregistrationDelay)
499 : 1;
500 ScheduleSend(reregDelay);
501 }
502 }
503 }
504
ParseMulticastListenerRegistrationResponse(Error aResult,Coap::Message * aMessage,uint8_t & aStatus,Ip6::Address * aFailedAddresses,uint8_t & aFailedAddressNum)505 Error MlrManager::ParseMulticastListenerRegistrationResponse(Error aResult,
506 Coap::Message *aMessage,
507 uint8_t & aStatus,
508 Ip6::Address * aFailedAddresses,
509 uint8_t & aFailedAddressNum)
510 {
511 Error error;
512 uint16_t addressesOffset, addressesLength;
513
514 aStatus = ThreadStatusTlv::MlrStatus::kMlrGeneralFailure;
515
516 VerifyOrExit(aResult == kErrorNone && aMessage != nullptr, error = kErrorParse);
517 VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged, error = kErrorParse);
518
519 SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(*aMessage, aStatus));
520
521 if (ThreadTlv::FindTlvValueOffset(*aMessage, Ip6AddressesTlv::kIp6Addresses, addressesOffset, addressesLength) ==
522 kErrorNone)
523 {
524 VerifyOrExit(addressesLength % sizeof(Ip6::Address) == 0, error = kErrorParse);
525 VerifyOrExit(addressesLength / sizeof(Ip6::Address) <= kIp6AddressesNumMax, error = kErrorParse);
526
527 for (uint16_t offset = 0; offset < addressesLength; offset += sizeof(Ip6::Address))
528 {
529 IgnoreError(aMessage->Read(addressesOffset + offset, aFailedAddresses[aFailedAddressNum]));
530 aFailedAddressNum++;
531 }
532 }
533
534 VerifyOrExit(aFailedAddressNum == 0 || aStatus != ThreadStatusTlv::MlrStatus::kMlrSuccess, error = kErrorParse);
535
536 exit:
537 LogMlrResponse(aResult, error, aStatus, aFailedAddresses, aFailedAddressNum);
538 return aResult != kErrorNone ? aResult : error;
539 }
540
SetMulticastAddressMlrState(MlrState aFromState,MlrState aToState)541 void MlrManager::SetMulticastAddressMlrState(MlrState aFromState, MlrState aToState)
542 {
543 #if OPENTHREAD_CONFIG_MLR_ENABLE
544 for (Ip6::Netif::ExternalMulticastAddress &addr :
545 Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
546 {
547 if (addr.GetMlrState() == aFromState)
548 {
549 addr.SetMlrState(aToState);
550 }
551 }
552 #endif
553 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
554 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
555 {
556 for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
557 {
558 if (child.GetAddressMlrState(address) == aFromState)
559 {
560 child.SetAddressMlrState(address, aToState);
561 }
562 }
563 }
564 #endif
565 }
566
FinishMulticastListenerRegistration(bool aSuccess,const Ip6::Address * aFailedAddresses,uint8_t aFailedAddressNum)567 void MlrManager::FinishMulticastListenerRegistration(bool aSuccess,
568 const Ip6::Address *aFailedAddresses,
569 uint8_t aFailedAddressNum)
570 {
571 OT_ASSERT(mMlrPending);
572
573 mMlrPending = false;
574
575 #if OPENTHREAD_CONFIG_MLR_ENABLE
576 for (Ip6::Netif::ExternalMulticastAddress &addr :
577 Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
578 {
579 if (addr.GetMlrState() == kMlrStateRegistering)
580 {
581 bool success = aSuccess || !AddressListContains(aFailedAddresses, aFailedAddressNum, addr.GetAddress());
582
583 addr.SetMlrState(success ? kMlrStateRegistered : kMlrStateToRegister);
584 }
585 }
586 #endif
587 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
588 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
589 {
590 for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
591 {
592 if (child.GetAddressMlrState(address) == kMlrStateRegistering)
593 {
594 bool success = aSuccess || !AddressListContains(aFailedAddresses, aFailedAddressNum, address);
595
596 child.SetAddressMlrState(address, success ? kMlrStateRegistered : kMlrStateToRegister);
597 }
598 }
599 }
600 #endif
601
602 LogMulticastAddresses();
603 CheckInvariants();
604 }
605
HandleTimeTick(void)606 void MlrManager::HandleTimeTick(void)
607 {
608 if (mSendDelay > 0 && --mSendDelay == 0)
609 {
610 SendMulticastListenerRegistration();
611 }
612
613 if (mReregistrationDelay > 0 && --mReregistrationDelay == 0)
614 {
615 Reregister();
616 }
617
618 UpdateTimeTickerRegistration();
619 }
620
Reregister(void)621 void MlrManager::Reregister(void)
622 {
623 otLogInfoMlr("MLR Reregister!");
624
625 SetMulticastAddressMlrState(kMlrStateRegistered, kMlrStateToRegister);
626 CheckInvariants();
627
628 ScheduleSend(0);
629
630 // Schedule for the next renewing.
631 UpdateReregistrationDelay(false);
632 }
633
UpdateReregistrationDelay(bool aRereg)634 void MlrManager::UpdateReregistrationDelay(bool aRereg)
635 {
636 Mle::MleRouter &mle = Get<Mle::MleRouter>();
637
638 bool needSendMlr = (mle.IsFullThreadDevice() || mle.GetParent().IsThreadVersion1p1()) &&
639 Get<BackboneRouter::Leader>().HasPrimary();
640
641 if (!needSendMlr)
642 {
643 mReregistrationDelay = 0;
644 }
645 else
646 {
647 BackboneRouter::BackboneRouterConfig config;
648 uint32_t reregDelay;
649 uint32_t effectiveMlrTimeout;
650
651 IgnoreError(Get<BackboneRouter::Leader>().GetConfig(config));
652
653 if (aRereg)
654 {
655 reregDelay = config.mReregistrationDelay > 1
656 ? Random::NonCrypto::GetUint16InRange(1, config.mReregistrationDelay)
657 : 1;
658 }
659 else
660 {
661 // Calculate renewing period according to Thread Spec. 5.24.2.3.2
662 // The random time t SHOULD be chosen such that (0.5* MLR-Timeout) < t < (MLR-Timeout – 9 seconds).
663 effectiveMlrTimeout = config.mMlrTimeout > Mle::kMlrTimeoutMin ? config.mMlrTimeout
664 : static_cast<uint32_t>(Mle::kMlrTimeoutMin);
665 reregDelay = Random::NonCrypto::GetUint32InRange((effectiveMlrTimeout >> 1u) + 1, effectiveMlrTimeout - 9);
666 }
667
668 if (mReregistrationDelay == 0 || mReregistrationDelay > reregDelay)
669 {
670 mReregistrationDelay = reregDelay;
671 }
672 }
673
674 UpdateTimeTickerRegistration();
675
676 otLogDebgMlr("MlrManager::UpdateReregistrationDelay: rereg=%d, needSendMlr=%d, ReregDelay=%lu", aRereg, needSendMlr,
677 mReregistrationDelay);
678 }
679
LogMulticastAddresses(void)680 void MlrManager::LogMulticastAddresses(void)
681 {
682 #if OPENTHREAD_CONFIG_LOG_MLR && OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_DEBG
683 otLogDebgMlr("-------- Multicast Addresses --------");
684
685 #if OPENTHREAD_CONFIG_MLR_ENABLE
686 for (const Ip6::Netif::ExternalMulticastAddress &addr : Get<ThreadNetif>().IterateExternalMulticastAddresses())
687 {
688 otLogDebgMlr("%-32s%c", addr.GetAddress().ToString().AsCString(), "-rR"[addr.GetMlrState()]);
689 }
690 #endif
691
692 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
693 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
694 {
695 for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
696 {
697 otLogDebgMlr("%-32s%c %04x", address.ToString().AsCString(), "-rR"[child.GetAddressMlrState(address)],
698 child.GetRloc16());
699 }
700 }
701 #endif
702
703 #endif // OPENTHREAD_CONFIG_LOG_MLR && OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_DEBG
704 }
705
AppendToUniqueAddressList(Ip6::Address (& aAddresses)[kIp6AddressesNumMax],uint8_t & aAddressNum,const Ip6::Address & aAddress)706 void MlrManager::AppendToUniqueAddressList(Ip6::Address (&aAddresses)[kIp6AddressesNumMax],
707 uint8_t & aAddressNum,
708 const Ip6::Address &aAddress)
709 {
710 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
711 for (uint8_t i = 0; i < aAddressNum; i++)
712 {
713 if (aAddresses[i] == aAddress)
714 {
715 ExitNow();
716 }
717 }
718 #endif
719
720 aAddresses[aAddressNum++] = aAddress;
721
722 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
723 exit:
724 #endif
725 return;
726 }
727
AddressListContains(const Ip6::Address * aAddressList,uint8_t aAddressListSize,const Ip6::Address & aAddress)728 bool MlrManager::AddressListContains(const Ip6::Address *aAddressList,
729 uint8_t aAddressListSize,
730 const Ip6::Address &aAddress)
731 {
732 bool contains = false;
733
734 // An empty address list is treated as if it contains all failed addresses.
735 VerifyOrExit(aAddressListSize > 0, contains = true);
736
737 for (uint8_t i = 0; i < aAddressListSize; i++)
738 {
739 if (aAddressList[i] == aAddress)
740 {
741 ExitNow(contains = true);
742 }
743 }
744
745 exit:
746 return contains;
747 }
748
LogMlrResponse(Error aResult,Error aError,uint8_t aStatus,const Ip6::Address * aFailedAddresses,uint8_t aFailedAddressNum)749 void MlrManager::LogMlrResponse(Error aResult,
750 Error aError,
751 uint8_t aStatus,
752 const Ip6::Address *aFailedAddresses,
753 uint8_t aFailedAddressNum)
754 {
755 OT_UNUSED_VARIABLE(aResult);
756 OT_UNUSED_VARIABLE(aError);
757 OT_UNUSED_VARIABLE(aStatus);
758 OT_UNUSED_VARIABLE(aFailedAddresses);
759 OT_UNUSED_VARIABLE(aFailedAddressNum);
760
761 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN) && (OPENTHREAD_CONFIG_LOG_MLR == 1)
762 if (aResult == kErrorNone && aError == kErrorNone && aStatus == ThreadStatusTlv::MlrStatus::kMlrSuccess)
763 {
764 otLogInfoMlr("Receive MLR.rsp OK");
765 }
766 else
767 {
768 otLogWarnMlr("Receive MLR.rsp: result=%s, error=%s, status=%d, failedAddressNum=%d", ErrorToString(aResult),
769 ErrorToString(aError), aStatus, aFailedAddressNum);
770
771 for (uint8_t i = 0; i < aFailedAddressNum; i++)
772 {
773 otLogWarnMlr("MA failed: %s", aFailedAddresses[i].ToString().AsCString());
774 }
775 }
776 #endif
777 }
778
CheckInvariants(void) const779 void MlrManager::CheckInvariants(void) const
780 {
781 #if OPENTHREAD_EXAMPLES_SIMULATION
782 uint16_t registeringNum = 0;
783
784 OT_ASSERT(!mMlrPending || mSendDelay == 0);
785
786 #if OPENTHREAD_CONFIG_MLR_ENABLE
787 for (Ip6::Netif::ExternalMulticastAddress &addr :
788 Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
789 {
790 registeringNum += (addr.GetMlrState() == kMlrStateRegistering);
791 }
792 #endif
793 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
794 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
795 {
796 for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
797 {
798 registeringNum += (child.GetAddressMlrState(address) == kMlrStateRegistering);
799 }
800 }
801 #endif
802
803 OT_ASSERT(registeringNum == 0 || mMlrPending);
804 #endif // OPENTHREAD_EXAMPLES_SIMULATION
805 }
806
807 } // namespace ot
808
809 #endif // OPENTHREAD_CONFIG_MLR_ENABLE
810