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 Multicast Listeners Table.
32  */
33 
34 #ifndef MULTICAST_LISTENERS_TABLE_HPP
35 #define MULTICAST_LISTENERS_TABLE_HPP
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
40 
41 #include <openthread/backbone_router_ftd.h>
42 
43 #include "common/as_core_type.hpp"
44 #include "common/callback.hpp"
45 #include "common/non_copyable.hpp"
46 #include "common/notifier.hpp"
47 #include "common/time.hpp"
48 #include "net/ip6_address.hpp"
49 
50 namespace ot {
51 
52 namespace BackboneRouter {
53 
54 /**
55  * Implements the definitions for Multicast Listeners Table.
56  */
57 class MulticastListenersTable : public InstanceLocator, private NonCopyable
58 {
59     class IteratorBuilder;
60 
61 public:
62     /**
63      * Represents a Multicast Listener entry.
64      */
65     class Listener : public Clearable<Listener>
66     {
67         friend class MulticastListenersTable;
68 
69     public:
70         typedef otBackboneRouterMulticastListenerCallback Callback; ///< Listener callback.
71         typedef otBackboneRouterMulticastListenerIterator Iterator; ///< Iterator to go over Listener entries.
72         typedef otBackboneRouterMulticastListenerInfo     Info;     ///< Listener info.
73 
74         enum Event : uint8_t ///< Listener Event
75         {
76             kEventAdded   = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED,   ///< Listener was added.
77             kEventRemoved = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED, ///< Listener was removed.
78         };
79 
80         /**
81          * Initializes the `Listener` object.
82          */
Listener(void)83         Listener(void) { Clear(); }
84 
85         /**
86          * Returns the Multicast Listener address.
87          *
88          * @returns The Multicast Listener address.
89          */
GetAddress(void) const90         const Ip6::Address &GetAddress(void) const { return mAddress; }
91 
92         /**
93          * Returns the expire time of the Multicast Listener.
94          *
95          * @returns The Multicast Listener expire time.
96          */
GetExpireTime(void) const97         const TimeMilli GetExpireTime(void) const { return mExpireTime; }
98 
99     private:
SetAddress(const Ip6::Address & aAddress)100         void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; }
SetExpireTime(TimeMilli aExpireTime)101         void SetExpireTime(TimeMilli aExpireTime) { mExpireTime = aExpireTime; }
102 
operator <(const Listener & aOther) const103         bool operator<(const Listener &aOther) const { return GetExpireTime() < aOther.GetExpireTime(); }
104 
105         Ip6::Address mAddress;
106         TimeMilli    mExpireTime;
107     };
108 
109     /**
110      * Initializes the Multicast Listeners Table.
111      *
112      * @param[in] aInstance  A reference to the OpenThread instance.
113      */
MulticastListenersTable(Instance & aInstance)114     explicit MulticastListenersTable(Instance &aInstance)
115         : InstanceLocator(aInstance)
116         , mNumValidListeners(0)
117     {
118     }
119 
120     /**
121      * Adds a Multicast Listener with given address and expire time.
122      *
123      * @param[in] aAddress     The Multicast Listener address.
124      * @param[in] aExpireTime  The Multicast Listener expire time.
125      *
126      * @retval kErrorNone         If the Multicast Listener was successfully added.
127      * @retval kErrorInvalidArgs  If the Multicast Listener address was invalid.
128      * @retval kErrorNoBufs       No space available to save the Multicast Listener.
129      */
130     Error Add(const Ip6::Address &aAddress, TimeMilli aExpireTime);
131 
132     /**
133      * Removes a given Multicast Listener.
134      *
135      * @param[in] aAddress  The Multicast Listener address.
136      */
137     void Remove(const Ip6::Address &aAddress);
138 
139     /**
140      * Removes expired Multicast Listeners.
141      */
142     void Expire(void);
143 
144     /**
145      * Counts the number of valid Multicast Listeners.
146      *
147      * @returns The number of valid Multicast Listeners.
148      */
Count(void) const149     uint16_t Count(void) const { return mNumValidListeners; }
150 
151     /**
152      * Enables range-based `for` loop iteration over all Multicast Listeners.
153      *
154      * Should be used as follows:
155      *
156      *     for (MulticastListenersTable::Listener &listener : Get<MulticastListenersTable>().Iterate())
157      *
158      * @returns An IteratorBuilder instance.
159      */
Iterate(void)160     IteratorBuilder Iterate(void) { return IteratorBuilder(GetInstance()); }
161 
162     /**
163      * Removes all the Multicast Listeners.
164      */
165     void Clear(void);
166 
167     /**
168      * Sets the Multicast Listener callback.
169      *
170      * @param[in] aCallback  The callback function.
171      * @param[in] aContext   A user context pointer.
172      */
173     void SetCallback(Listener::Callback aCallback, void *aContext);
174 
175     /**
176      * Gets the next Multicast Listener.
177      *
178      * @param[in]  aIterator      A pointer to the Multicast Listener Iterator.
179      * @param[out] aInfo          A reference to output the Multicast Listener info.
180      *
181      * @retval kErrorNone         Successfully found the next Multicast Listener info.
182      * @retval kErrorNotFound     No subsequent Multicast Listener was found.
183      */
184     Error GetNext(Listener::Iterator &aIterator, Listener::Info &aInfo);
185 
186 private:
187     static constexpr uint16_t kTableSize = OPENTHREAD_CONFIG_MAX_MULTICAST_LISTENERS;
188 
189     static_assert(kTableSize >= 75, "Thread 1.2 Conformance requires table size of at least 75 listeners.");
190 
191     class IteratorBuilder : InstanceLocator
192     {
193     public:
IteratorBuilder(Instance & aInstance)194         explicit IteratorBuilder(Instance &aInstance)
195             : InstanceLocator(aInstance)
196         {
197         }
198 
199         Listener *begin(void);
200         Listener *end(void);
201     };
202 
203     enum Action : uint8_t
204     {
205         kAdd,
206         kRemove,
207         kExpire,
208     };
209 
210     void Log(Action aAction, const Ip6::Address &aAddress, TimeMilli aExpireTime, Error aError) const;
211 
212     void FixHeap(uint16_t aIndex);
213     bool SiftHeapElemDown(uint16_t aIndex);
214     void SiftHeapElemUp(uint16_t aIndex);
215     void CheckInvariants(void) const;
216 
217     Listener                     mListeners[kTableSize];
218     uint16_t                     mNumValidListeners;
219     Callback<Listener::Callback> mCallback;
220 };
221 
222 } // namespace BackboneRouter
223 
224 DefineMapEnum(otBackboneRouterMulticastListenerEvent, BackboneRouter::MulticastListenersTable::Listener::Event);
225 
226 /**
227  * @}
228  */
229 
230 } // namespace ot
231 
232 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
233 
234 #endif // MULTICAST_LISTENERS_TABLE_HPP
235