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