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