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 includes definitions for managing Multicast Listener Registration feature defined in Thread 1.2.
32  */
33 
34 #ifndef MLR_MANAGER_HPP_
35 #define MLR_MANAGER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
40 
41 #if OPENTHREAD_CONFIG_MLR_ENABLE && (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
42 #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MLR_ENABLE"
43 #endif
44 
45 #include "backbone_router/bbr_leader.hpp"
46 #include "coap/coap_message.hpp"
47 #include "common/array.hpp"
48 #include "common/callback.hpp"
49 #include "common/locator.hpp"
50 #include "common/non_copyable.hpp"
51 #include "common/notifier.hpp"
52 #include "common/time_ticker.hpp"
53 #include "common/timer.hpp"
54 #include "net/netif.hpp"
55 #include "thread/child.hpp"
56 #include "thread/thread_tlvs.hpp"
57 
58 namespace ot {
59 
60 /**
61  * @addtogroup core-mlr
62  *
63  * @brief
64  *   This module includes definitions for Multicast Listener Registration.
65  *
66  * @{
67  *
68  * @defgroup core-mlr Mlr
69  *
70  * @}
71  *
72  */
73 
74 /**
75  * Implements MLR management.
76  *
77  */
78 class MlrManager : public InstanceLocator, private NonCopyable
79 {
80     friend class ot::Notifier;
81     friend class ot::TimeTicker;
82 
83 public:
84     typedef otIp6RegisterMulticastListenersCallback MlrCallback;
85 
86     /**
87      * Initializes the object.
88      *
89      * @param[in]  aInstance     A reference to the OpenThread instance.
90      *
91      */
92     explicit MlrManager(Instance &aInstance);
93 
94     /**
95      * Notifies Primary Backbone Router status.
96      *
97      * @param[in]  aState   The state or state change of Primary Backbone Router.
98      * @param[in]  aConfig  The Primary Backbone Router service.
99      *
100      */
101     void HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState, const BackboneRouter::Config &aConfig);
102 
103 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
104     static constexpr uint16_t kMaxMlrAddresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; ///< Max MLR addresses
105 
106     typedef Array<Ip6::Address, kMaxMlrAddresses> MlrAddressArray; ///< Registered MLR addresses array.
107 
108     /**
109      * Updates the Multicast Subscription Table according to the Child information.
110      *
111      * @param[in]  aChild                       A reference to the child information.
112      * @param[in]  aOldMlrRegisteredAddresses   Array of the Child's previously registered IPv6 addresses.
113      *
114      */
115     void UpdateProxiedSubscriptions(Child &aChild, const MlrAddressArray &aOldMlrRegisteredAddresses);
116 #endif
117 
118 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
119     /**
120      * Registers Multicast Listeners to Primary Backbone Router.
121      *
122      * Note: only available when both `(OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)` and
123      * `OPENTHREAD_CONFIG_COMMISSIONER_ENABLE` are enabled)
124      *
125      * @param aAddresses   A pointer to IPv6 multicast addresses to register.
126      * @param aAddressNum  The number of IPv6 multicast addresses.
127      * @param aTimeout     A pointer to the timeout (in seconds), or `nullptr` to use the default MLR timeout.
128      *                     A timeout of 0 seconds removes the Multicast Listener addresses.
129      * @param aCallback    A callback function.
130      * @param aContext     A user context pointer.
131      *
132      * @retval kErrorNone          Successfully sent MLR.req. The @p aCallback will be called iff this method
133      *                             returns kErrorNone.
134      * @retval kErrorBusy          If a previous registration was ongoing.
135      * @retval kErrorInvalidArgs   If one or more arguments are invalid.
136      * @retval kErrorInvalidState  If the device was not in a valid state to send MLR.req (e.g. Commissioner not
137      *                             started, Primary Backbone Router not found).
138      * @retval kErrorNoBufs        If insufficient message buffers available.
139      *
140      */
141     Error RegisterMulticastListeners(const Ip6::Address *aAddresses,
142                                      uint8_t             aAddressNum,
143                                      const uint32_t     *aTimeout,
144                                      MlrCallback         aCallback,
145                                      void               *aContext);
146 #endif
147 
148 private:
149     class AddressArray : public Array<Ip6::Address, Ip6AddressesTlv::kMaxAddresses>
150     {
151     public:
IsEmptyOrContains(const Ip6::Address & aAddress) const152         bool IsEmptyOrContains(const Ip6::Address &aAddress) const { return IsEmpty() || Contains(aAddress); }
153         void AddUnique(const Ip6::Address &aAddress);
154     };
155 
156     void HandleNotifierEvents(Events aEvents);
157 
158     void  SendMlr(void);
159     Error SendMlrMessage(const Ip6::Address   *aAddresses,
160                          uint8_t               aAddressNum,
161                          const uint32_t       *aTimeout,
162                          Coap::ResponseHandler aResponseHandler,
163                          void                 *aResponseContext);
164 
165     static void  HandleMlrResponse(void                *aContext,
166                                    otMessage           *aMessage,
167                                    const otMessageInfo *aMessageInfo,
168                                    Error                aResult);
169     void         HandleMlrResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
170     static Error ParseMlrResponse(Error          aResult,
171                                   Coap::Message *aMessage,
172                                   uint8_t       &aStatus,
173                                   AddressArray  &aFailedAddresses);
174 
175 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
176     static void HandleRegisterResponse(void                *aContext,
177                                        otMessage           *aMessage,
178                                        const otMessageInfo *aMessageInfo,
179                                        Error                aResult);
180     void        HandleRegisterResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, Error aResult);
181 #endif
182 
183 #if OPENTHREAD_CONFIG_MLR_ENABLE
184     void UpdateLocalSubscriptions(void);
185     bool IsAddressMlrRegisteredByNetif(const Ip6::Address &aAddress) const;
186 #endif
187 
188 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
IsAddressMlrRegisteredByAnyChild(const Ip6::Address & aAddress) const189     bool IsAddressMlrRegisteredByAnyChild(const Ip6::Address &aAddress) const
190     {
191         return IsAddressMlrRegisteredByAnyChildExcept(aAddress, nullptr);
192     }
193     bool IsAddressMlrRegisteredByAnyChildExcept(const Ip6::Address &aAddress, const Child *aExceptChild) const;
194 #endif
195 
196     void SetMulticastAddressMlrState(MlrState aFromState, MlrState aToState);
197     void FinishMlr(bool aSuccess, const AddressArray &aFailedAddresses);
198 
199     void ScheduleSend(uint16_t aDelay);
200     void UpdateTimeTickerRegistration(void);
201     void UpdateReregistrationDelay(bool aRereg);
202     void Reregister(void);
203     void HandleTimeTick(void);
204 
205     void        LogMulticastAddresses(void);
206     void        CheckInvariants(void) const;
207     static void LogMlrResponse(Error aResult, Error aError, uint8_t aStatus, const AddressArray &aFailedAddresses);
208 
209 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
210     Callback<MlrCallback> mRegisterCallback;
211 #endif
212 
213     uint32_t mReregistrationDelay;
214     uint16_t mSendDelay;
215 
216     bool mMlrPending : 1;
217 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
218     bool mRegisterPending : 1;
219 #endif
220 };
221 
222 } // namespace ot
223 
224 #endif // OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
225 #endif // MLR_MANAGER_HPP_
226