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