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  * @file
30  *   This file includes definitions for NdProxy Table on Thread Backbone Border Router.
31  */
32 
33 #ifndef NDPROXY_TABLE_HPP_
34 #define NDPROXY_TABLE_HPP_
35 
36 #include "openthread-core-config.h"
37 
38 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
39 
40 #include <openthread/backbone_router_ftd.h>
41 
42 #include "backbone_router/bbr_leader.hpp"
43 #include "common/as_core_type.hpp"
44 #include "common/callback.hpp"
45 #include "common/iterator_utils.hpp"
46 #include "common/locator.hpp"
47 #include "common/non_copyable.hpp"
48 #include "common/time.hpp"
49 #include "net/ip6_address.hpp"
50 #include "thread/mle_types.hpp"
51 
52 namespace ot {
53 
54 namespace BackboneRouter {
55 
56 /**
57  * This class implements NdProxy Table maintenance on Primary Backbone Router.
58  *
59  */
60 class NdProxyTable : public InstanceLocator, private NonCopyable
61 {
62 public:
63     /**
64      * This class represents a ND Proxy instance.
65      *
66      */
67     class NdProxy : private Clearable<NdProxy>
68     {
69         friend class NdProxyTable;
70         friend class Clearable<NdProxy>;
71 
72     public:
73         typedef otBackboneRouterNdProxyCallback Callback; ///< ND Proxy callback.
74 
75         /**
76          * This type represents the ND Proxy events.
77          *
78          */
79         enum Event
80         {
81             kAdded   = OT_BACKBONE_ROUTER_NDPROXY_ADDED,   ///< ND Proxy was added.
82             kRemoved = OT_BACKBONE_ROUTER_NDPROXY_REMOVED, ///< ND Proxy was removed.
83             kRenewed = OT_BACKBONE_ROUTER_NDPROXY_RENEWED, ///< ND Proxy was renewed.
84             kCleared = OT_BACKBONE_ROUTER_NDPROXY_CLEARED, ///< All ND Proxies were cleared.
85         };
86 
87         /**
88          * This method gets the Mesh-Local IID of the ND Proxy.
89          *
90          * @returns  The Mesh-Local IID.
91          *
92          */
GetMeshLocalIid(void) const93         const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mMeshLocalIid; }
94 
95         /**
96          * This method gets the time since last transaction of the ND Proxy.
97          *
98          * @returns  The time since last transaction in seconds.
99          *
100          */
GetTimeSinceLastTransaction(void) const101         uint32_t GetTimeSinceLastTransaction(void) const
102         {
103             return TimeMilli::MsecToSec(TimerMilli::GetNow() - mLastRegistrationTime);
104         }
105 
106         /**
107          * This method gets the short address of the device who sends the DUA registration.
108          *
109          * @returns  The RLOC16 value.
110          *
111          */
GetRloc16(void) const112         uint16_t GetRloc16(void) const { return mRloc16; }
113 
114         /**
115          * This method gets the DAD flag of the ND Proxy.
116          *
117          * @returns  The DAD flag.
118          *
119          */
GetDadFlag(void) const120         bool GetDadFlag(void) const { return mDadFlag; }
121 
122     private:
NdProxy(void)123         NdProxy(void) { Clear(); }
124 
125         void Init(const Ip6::InterfaceIdentifier &aAddressIid,
126                   const Ip6::InterfaceIdentifier &aMeshLocalIid,
127                   uint16_t                        aRloc16,
128                   uint32_t                        aTimeSinceLastTransaction);
129 
130         void Update(uint16_t aRloc16, uint32_t aTimeSinceLastTransaction);
IncreaseDadAttempts(void)131         void IncreaseDadAttempts(void) { mDadAttempts++; }
IsDadAttemptsComplete() const132         bool IsDadAttemptsComplete() const { return mDadAttempts == Mle::kDuaDadRepeats; }
133 
134         Ip6::InterfaceIdentifier mAddressIid;
135         Ip6::InterfaceIdentifier mMeshLocalIid;
136         TimeMilli                mLastRegistrationTime; ///< in milliseconds
137         uint16_t                 mRloc16;
138         uint8_t                  mDadAttempts : 2;
139         bool                     mDadFlag : 1;
140         bool                     mValid : 1;
141 
142         static_assert(Mle::kDuaDadRepeats < 4, "Mle::kDuaDadRepeats does not fit in mDadAttempts field as 2-bit value");
143     };
144 
145     /**
146      * This constructor initializes the `NdProxyTable` object.
147      *
148      * @param[in]  aInstance     A reference to the OpenThread instance.
149      *
150      */
NdProxyTable(Instance & aInstance)151     explicit NdProxyTable(Instance &aInstance)
152         : InstanceLocator(aInstance)
153         , mIsAnyDadInProcess(false)
154     {
155     }
156 
157     /**
158      * This method registers a given IPv6 address IID with related information to the NdProxy table.
159      *
160      * @param[in] aAddressIid                The IPv6 address IID.
161      * @param[in] aMeshLocalIid              The Mesh-Local IID.
162      * @param[in] aRloc16                    The RLOC16.
163      * @param[in] aTimeSinceLastTransaction  Time since last transaction (in seconds).
164      *
165      * @retval kErrorNone        If registered successfully.
166      * @retval kErrorDuplicated  If the IPv6 address IID is a duplicate.
167      * @retval kErrorNoBufs      Insufficient buffer space available to register.
168      *
169      */
170     Error Register(const Ip6::InterfaceIdentifier &aAddressIid,
171                    const Ip6::InterfaceIdentifier &aMeshLocalIid,
172                    uint16_t                        aRloc16,
173                    const uint32_t                 *aTimeSinceLastTransaction);
174 
175     /**
176      * This method checks if a given IPv6 address IID was registered.
177      *
178      * @param[in] aAddressIid  The IPv6 address IID.
179      *
180      * @retval TRUE   If the IPv6 address IID was registered.
181      * @retval FALSE  If the IPv6 address IID was not registered.
182      *
183      */
IsRegistered(const Ip6::InterfaceIdentifier & aAddressIid)184     bool IsRegistered(const Ip6::InterfaceIdentifier &aAddressIid) { return FindByAddressIid(aAddressIid) != nullptr; }
185 
186     /**
187      * This method notifies Domain Prefix status.
188      *
189      * @param[in]  aState  The Domain Prefix state or state change.
190      *
191      */
192     void HandleDomainPrefixUpdate(Leader::DomainPrefixState aState);
193 
194     /**
195      * This method notifies ND Proxy table of the timer tick.
196      *
197      */
198     void HandleTimer(void);
199 
200     /**
201      * This method gets the ND Proxy info for a given Domain Unicast Address.
202      *
203      * @param[in] aDua  The Domain Unicast Address.
204      *
205      * @returns The `NdProxy` instance matching the specified @p aDua, or nullptr if not found.
206      *
207      */
208     NdProxy *ResolveDua(const Ip6::Address &aDua);
209 
210     /**
211      * This method notifies DAD completed for a given ND Proxy.
212      *
213      * @param[in] aNdProxy      The ND Proxy to notify of.
214      * @param[in] aDuplicated   Whether duplicate was detected.
215      *
216      */
217     static void NotifyDadComplete(NdProxy &aNdProxy, bool aDuplicated);
218 
219     /**
220      * This method removes the ND Proxy.
221      *
222      * @param[in] aNdProxy      The ND Proxy to remove.
223      *
224      */
225     static void Erase(NdProxy &aNdProxy);
226 
227     /*
228      * This method sets the ND Proxy callback.
229      *
230      * @param[in] aCallback  The callback function.
231      * @param[in] aContext   A user context pointer.
232      *
233      */
SetCallback(NdProxy::Callback aCallback,void * aContext)234     void SetCallback(NdProxy::Callback aCallback, void *aContext) { mCallback.Set(aCallback, aContext); }
235 
236     /**
237      * This method retrieves the ND Proxy info of the Domain Unicast Address.
238      *
239      * @param[in] aDua          The Domain Unicast Address to get info.
240      * @param[in] aNdProxyInfo  A pointer to the ND Proxy info.
241      *
242      * @retval kErrorNone       Successfully retrieve the ND Proxy info.
243      * @retval kErrorNotFound   Failed to find the Domain Unicast Address in the ND Proxy table.
244      *
245      */
246     Error GetInfo(const Ip6::Address &aDua, otBackboneRouterNdProxyInfo &aNdProxyInfo);
247 
248 private:
249     static constexpr uint16_t kMaxNdProxyNum = OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM;
250 
251     enum Filter : uint8_t
252     {
253         kFilterInvalid,
254         kFilterValid,
255         kFilterDadInProcess,
256     };
257 
258     /**
259      * This class represents an iterator for iterating through the NdProxy Table.
260      *
261      */
262     class Iterator : public InstanceLocator, public ItemPtrIterator<NdProxy, Iterator>
263     {
264         friend class ItemPtrIterator<NdProxy, Iterator>;
265         friend class NdProxyTable;
266         friend class IteratorBuilder;
267 
268     private:
269         enum IteratorType : uint8_t
270         {
271             kEndIterator,
272         };
273 
274         Iterator(Instance &aInstance, Filter aFilter);
275         Iterator(Instance &aInstance, IteratorType);
276 
277         void Advance(void);
278 
279         Filter mFilter;
280     };
281 
282     class IteratorBuilder : public InstanceLocator
283     {
284         friend class NdProxyTable;
285 
286     private:
IteratorBuilder(Instance & aInstance,Filter aFilter)287         IteratorBuilder(Instance &aInstance, Filter aFilter)
288             : InstanceLocator(aInstance)
289             , mFilter(aFilter)
290         {
291         }
292 
begin(void)293         Iterator begin(void) { return Iterator(GetInstance(), mFilter); }
end(void)294         Iterator end(void) { return Iterator(GetInstance(), Iterator::kEndIterator); }
295 
296         Filter mFilter;
297     };
298 
Iterate(Filter aFilter)299     IteratorBuilder Iterate(Filter aFilter) { return IteratorBuilder(GetInstance(), aFilter); }
300     void            Clear(void);
301     static bool     MatchesFilter(const NdProxy &aProxy, Filter aFilter);
302     NdProxy        *FindByAddressIid(const Ip6::InterfaceIdentifier &aAddressIid);
303     NdProxy        *FindByMeshLocalIid(const Ip6::InterfaceIdentifier &aMeshLocalIid);
304     NdProxy        *FindInvalid(void);
305     Ip6::Address    GetDua(NdProxy &aNdProxy);
306     void            NotifyDuaRegistrationOnBackboneLink(NdProxy &aNdProxy, bool aIsRenew);
307     void            TriggerCallback(NdProxy::Event aEvent, const Ip6::InterfaceIdentifier &aAddressIid) const;
308 
309     NdProxy                     mProxies[kMaxNdProxyNum];
310     Callback<NdProxy::Callback> mCallback;
311     bool                        mIsAnyDadInProcess : 1;
312 };
313 
314 } // namespace BackboneRouter
315 
316 DefineMapEnum(otBackboneRouterNdProxyEvent, BackboneRouter::NdProxyTable::NdProxy::Event);
317 
318 } // namespace ot
319 
320 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
321 
322 #endif // NDPROXY_TABLE_HPP_
323