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