• 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 the Multicast Listeners Table.
32  */
33 
34 #include "multicast_listeners_table.hpp"
35 
36 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
37 
38 #include "common/array.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 "common/random.hpp"
44 #include "thread/mle_types.hpp"
45 #include "thread/thread_netif.hpp"
46 #include "thread/uri_paths.hpp"
47 
48 namespace ot {
49 
50 namespace BackboneRouter {
51 
52 RegisterLogModule("BbrMlt");
53 
Add(const Ip6::Address & aAddress,Time aExpireTime)54 Error MulticastListenersTable::Add(const Ip6::Address &aAddress, Time aExpireTime)
55 {
56     Error error = kErrorNone;
57 
58     VerifyOrExit(aAddress.IsMulticastLargerThanRealmLocal(), error = kErrorInvalidArgs);
59 
60     for (uint16_t i = 0; i < mNumValidListeners; i++)
61     {
62         Listener &listener = mListeners[i];
63 
64         if (listener.GetAddress() == aAddress)
65         {
66             listener.SetExpireTime(aExpireTime);
67             FixHeap(i);
68             ExitNow();
69         }
70     }
71 
72     VerifyOrExit(mNumValidListeners < GetArrayLength(mListeners), error = kErrorNoBufs);
73 
74     mListeners[mNumValidListeners].SetAddress(aAddress);
75     mListeners[mNumValidListeners].SetExpireTime(aExpireTime);
76     mNumValidListeners++;
77 
78     FixHeap(mNumValidListeners - 1);
79 
80     if (mCallback != nullptr)
81     {
82         mCallback(mCallbackContext, OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED, &aAddress);
83     }
84 
85 exit:
86     LogMulticastListenersTable("Add", aAddress, aExpireTime, error);
87     CheckInvariants();
88     return error;
89 }
90 
Remove(const Ip6::Address & aAddress)91 void MulticastListenersTable::Remove(const Ip6::Address &aAddress)
92 {
93     Error error = kErrorNotFound;
94 
95     for (uint16_t i = 0; i < mNumValidListeners; i++)
96     {
97         Listener &listener = mListeners[i];
98 
99         if (listener.GetAddress() == aAddress)
100         {
101             mNumValidListeners--;
102 
103             if (i != mNumValidListeners)
104             {
105                 listener = mListeners[mNumValidListeners];
106                 FixHeap(i);
107             }
108 
109             if (mCallback != nullptr)
110             {
111                 mCallback(mCallbackContext, OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED, &aAddress);
112             }
113 
114             ExitNow(error = kErrorNone);
115         }
116     }
117 
118 exit:
119     LogMulticastListenersTable("Remove", aAddress, TimeMilli(0), error);
120     CheckInvariants();
121 }
122 
Expire(void)123 void MulticastListenersTable::Expire(void)
124 {
125     TimeMilli    now = TimerMilli::GetNow();
126     Ip6::Address address;
127 
128     while (mNumValidListeners > 0 && now >= mListeners[0].GetExpireTime())
129     {
130         LogMulticastListenersTable("Expire", mListeners[0].GetAddress(), mListeners[0].GetExpireTime(), kErrorNone);
131         address = mListeners[0].GetAddress();
132 
133         mNumValidListeners--;
134 
135         if (mNumValidListeners > 0)
136         {
137             mListeners[0] = mListeners[mNumValidListeners];
138             FixHeap(0);
139         }
140 
141         if (mCallback != nullptr)
142         {
143             mCallback(mCallbackContext, OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED, &address);
144         }
145     }
146 
147     CheckInvariants();
148 }
149 
LogMulticastListenersTable(const char * aAction,const Ip6::Address & aAddress,TimeMilli aExpireTime,Error aError)150 void MulticastListenersTable::LogMulticastListenersTable(const char *        aAction,
151                                                          const Ip6::Address &aAddress,
152                                                          TimeMilli           aExpireTime,
153                                                          Error               aError)
154 {
155     OT_UNUSED_VARIABLE(aAction);
156     OT_UNUSED_VARIABLE(aAddress);
157     OT_UNUSED_VARIABLE(aExpireTime);
158     OT_UNUSED_VARIABLE(aError);
159 
160     LogDebg("%s %s expire %u: %s", aAction, aAddress.ToString().AsCString(), aExpireTime.GetValue(),
161             ErrorToString(aError));
162 }
163 
FixHeap(uint16_t aIndex)164 void MulticastListenersTable::FixHeap(uint16_t aIndex)
165 {
166     if (!SiftHeapElemDown(aIndex))
167     {
168         SiftHeapElemUp(aIndex);
169     }
170 }
171 
CheckInvariants(void) const172 void MulticastListenersTable::CheckInvariants(void) const
173 {
174 #if OPENTHREAD_EXAMPLES_SIMULATION && OPENTHREAD_CONFIG_ASSERT_ENABLE
175     for (uint16_t child = 1; child < mNumValidListeners; ++child)
176     {
177         uint16_t parent = (child - 1) / 2;
178 
179         OT_ASSERT(!(mListeners[child] < mListeners[parent]));
180     }
181 #endif
182 }
183 
SiftHeapElemDown(uint16_t aIndex)184 bool MulticastListenersTable::SiftHeapElemDown(uint16_t aIndex)
185 {
186     uint16_t index = aIndex;
187     Listener saveElem;
188 
189     OT_ASSERT(aIndex < mNumValidListeners);
190 
191     saveElem = mListeners[aIndex];
192 
193     for (;;)
194     {
195         uint16_t child = 2 * index + 1;
196 
197         if (child >= mNumValidListeners || child <= index) // child <= index after int overflow
198         {
199             break;
200         }
201 
202         if (child + 1 < mNumValidListeners && mListeners[child + 1] < mListeners[child])
203         {
204             child++;
205         }
206 
207         if (!(mListeners[child] < saveElem))
208         {
209             break;
210         }
211 
212         mListeners[index] = mListeners[child];
213 
214         index = child;
215     }
216 
217     if (index > aIndex)
218     {
219         mListeners[index] = saveElem;
220     }
221 
222     return index > aIndex;
223 }
224 
SiftHeapElemUp(uint16_t aIndex)225 void MulticastListenersTable::SiftHeapElemUp(uint16_t aIndex)
226 {
227     uint16_t index = aIndex;
228     Listener saveElem;
229 
230     OT_ASSERT(aIndex < mNumValidListeners);
231 
232     saveElem = mListeners[aIndex];
233 
234     for (;;)
235     {
236         uint16_t parent = (index - 1) / 2;
237 
238         if (index == 0 || !(saveElem < mListeners[parent]))
239         {
240             break;
241         }
242 
243         mListeners[index] = mListeners[parent];
244 
245         index = parent;
246     }
247 
248     if (index < aIndex)
249     {
250         mListeners[index] = saveElem;
251     }
252 }
253 
begin(void)254 MulticastListenersTable::Listener *MulticastListenersTable::IteratorBuilder::begin(void)
255 {
256     return &Get<MulticastListenersTable>().mListeners[0];
257 }
258 
end(void)259 MulticastListenersTable::Listener *MulticastListenersTable::IteratorBuilder::end(void)
260 {
261     return &Get<MulticastListenersTable>().mListeners[Get<MulticastListenersTable>().mNumValidListeners];
262 }
263 
Clear(void)264 void MulticastListenersTable::Clear(void)
265 {
266     if (mCallback != nullptr)
267     {
268         for (uint16_t i = 0; i < mNumValidListeners; i++)
269         {
270             mCallback(mCallbackContext, OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED, &mListeners[i].GetAddress());
271         }
272     }
273 
274     mNumValidListeners = 0;
275 
276     CheckInvariants();
277 }
278 
SetCallback(otBackboneRouterMulticastListenerCallback aCallback,void * aContext)279 void MulticastListenersTable::SetCallback(otBackboneRouterMulticastListenerCallback aCallback, void *aContext)
280 {
281     mCallback        = aCallback;
282     mCallbackContext = aContext;
283 
284     if (mCallback != nullptr)
285     {
286         for (uint16_t i = 0; i < mNumValidListeners; i++)
287         {
288             mCallback(mCallbackContext, OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED, &mListeners[i].GetAddress());
289         }
290     }
291 }
292 
GetNext(otBackboneRouterMulticastListenerIterator & aIterator,otBackboneRouterMulticastListenerInfo & aListenerInfo)293 Error MulticastListenersTable::GetNext(otBackboneRouterMulticastListenerIterator &aIterator,
294                                        otBackboneRouterMulticastListenerInfo &    aListenerInfo)
295 {
296     Error     error = kErrorNone;
297     TimeMilli now;
298 
299     VerifyOrExit(aIterator < mNumValidListeners, error = kErrorNotFound);
300 
301     now = TimerMilli::GetNow();
302 
303     aListenerInfo.mAddress = mListeners[aIterator].mAddress;
304     aListenerInfo.mTimeout =
305         Time::MsecToSec(mListeners[aIterator].mExpireTime > now ? mListeners[aIterator].mExpireTime - now : 0);
306 
307     aIterator++;
308 
309 exit:
310     return error;
311 }
312 
313 } // namespace BackboneRouter
314 
315 } // namespace ot
316 
317 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
318