• 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 Thread NdProxy Table management.
32  */
33 
34 #include "ndproxy_table.hpp"
35 
36 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
37 
38 #include "common/array.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/log.hpp"
41 
42 namespace ot {
43 
44 namespace BackboneRouter {
45 
46 RegisterLogModule("BbrNdProxy");
47 
Init(const Ip6::InterfaceIdentifier & aAddressIid,const Ip6::InterfaceIdentifier & aMeshLocalIid,uint16_t aRloc16,uint32_t aTimeSinceLastTransaction)48 void NdProxyTable::NdProxy::Init(const Ip6::InterfaceIdentifier &aAddressIid,
49                                  const Ip6::InterfaceIdentifier &aMeshLocalIid,
50                                  uint16_t                        aRloc16,
51                                  uint32_t                        aTimeSinceLastTransaction)
52 {
53     OT_ASSERT(!mValid);
54 
55     Clear();
56 
57     mValid        = true;
58     mAddressIid   = aAddressIid;
59     mMeshLocalIid = aMeshLocalIid;
60     mDadFlag      = true;
61 
62     Update(aRloc16, aTimeSinceLastTransaction);
63 }
64 
Update(uint16_t aRloc16,uint32_t aTimeSinceLastTransaction)65 void NdProxyTable::NdProxy::Update(uint16_t aRloc16, uint32_t aTimeSinceLastTransaction)
66 {
67     OT_ASSERT(mValid);
68 
69     mRloc16 = aRloc16;
70     aTimeSinceLastTransaction =
71         OT_MIN(aTimeSinceLastTransaction, static_cast<uint32_t>(Mle::kTimeSinceLastTransactionMax));
72     mLastRegistrationTime = TimerMilli::GetNow() - TimeMilli::SecToMsec(aTimeSinceLastTransaction);
73 }
74 
MatchesFilter(const NdProxy & aProxy,Filter aFilter)75 bool NdProxyTable::MatchesFilter(const NdProxy &aProxy, Filter aFilter)
76 {
77     bool rval = false;
78 
79     switch (aFilter)
80     {
81     case kFilterInvalid:
82         rval = !aProxy.mValid;
83         break;
84     case kFilterValid:
85         rval = aProxy.mValid;
86         break;
87     case kFilterDadInProcess:
88         rval = aProxy.mValid && aProxy.mDadFlag;
89         break;
90     }
91 
92     return rval;
93 }
94 
Iterator(Instance & aInstance,Filter aFilter)95 NdProxyTable::Iterator::Iterator(Instance &aInstance, Filter aFilter)
96     : InstanceLocator(aInstance)
97     , mFilter(aFilter)
98 {
99     NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
100 
101     mItem = &table.mProxies[0];
102 
103     if (!MatchesFilter(*mItem, mFilter))
104     {
105         Advance();
106     }
107 }
108 
Iterator(Instance & aInstance,NdProxyTable::Iterator::IteratorType)109 NdProxyTable::Iterator::Iterator(Instance &aInstance, NdProxyTable::Iterator::IteratorType)
110     : InstanceLocator(aInstance)
111 {
112     NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
113     mItem               = GetArrayEnd(table.mProxies);
114 }
115 
Advance(void)116 void NdProxyTable::Iterator::Advance(void)
117 {
118     NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
119 
120     do
121     {
122         mItem++;
123     } while (mItem < GetArrayEnd(table.mProxies) && !MatchesFilter(*mItem, mFilter));
124 }
125 
Erase(NdProxy & aNdProxy)126 void NdProxyTable::Erase(NdProxy &aNdProxy)
127 {
128     aNdProxy.mValid = false;
129 }
130 
HandleDomainPrefixUpdate(Leader::DomainPrefixState aState)131 void NdProxyTable::HandleDomainPrefixUpdate(Leader::DomainPrefixState aState)
132 {
133     if (aState == Leader::kDomainPrefixAdded || aState == Leader::kDomainPrefixRemoved ||
134         aState == Leader::kDomainPrefixRefreshed)
135     {
136         Clear();
137     }
138 }
139 
Clear(void)140 void NdProxyTable::Clear(void)
141 {
142     for (NdProxy &proxy : mProxies)
143     {
144         proxy.Clear();
145     }
146 
147     if (mCallback != nullptr)
148     {
149         mCallback(mCallbackContext, OT_BACKBONE_ROUTER_NDPROXY_CLEARED, nullptr);
150     }
151 
152     LogInfo("NdProxyTable::Clear!");
153 }
154 
Register(const Ip6::InterfaceIdentifier & aAddressIid,const Ip6::InterfaceIdentifier & aMeshLocalIid,uint16_t aRloc16,const uint32_t * aTimeSinceLastTransaction)155 Error NdProxyTable::Register(const Ip6::InterfaceIdentifier &aAddressIid,
156                              const Ip6::InterfaceIdentifier &aMeshLocalIid,
157                              uint16_t                        aRloc16,
158                              const uint32_t *                aTimeSinceLastTransaction)
159 {
160     Error    error                    = kErrorNone;
161     NdProxy *proxy                    = FindByAddressIid(aAddressIid);
162     uint32_t timeSinceLastTransaction = aTimeSinceLastTransaction == nullptr ? 0 : *aTimeSinceLastTransaction;
163 
164     if (proxy != nullptr)
165     {
166         VerifyOrExit(proxy->mMeshLocalIid == aMeshLocalIid, error = kErrorDuplicated);
167 
168         proxy->Update(aRloc16, timeSinceLastTransaction);
169         NotifyDuaRegistrationOnBackboneLink(*proxy, /* aIsRenew */ true);
170         ExitNow();
171     }
172 
173     proxy = FindByMeshLocalIid(aMeshLocalIid);
174     if (proxy != nullptr)
175     {
176         TriggerCallback(OT_BACKBONE_ROUTER_NDPROXY_REMOVED, proxy->mAddressIid);
177         Erase(*proxy);
178     }
179     else
180     {
181         proxy = FindInvalid();
182 
183         // TODO: evict stale DUA entries to have room for this new DUA.
184         VerifyOrExit(proxy != nullptr, error = kErrorNoBufs);
185     }
186 
187     proxy->Init(aAddressIid, aMeshLocalIid, aRloc16, timeSinceLastTransaction);
188     mIsAnyDadInProcess = true;
189 
190 exit:
191     LogInfo("NdProxyTable::Register %s MLIID %s RLOC16 %04x LTT %u => %s", aAddressIid.ToString().AsCString(),
192             aMeshLocalIid.ToString().AsCString(), aRloc16, timeSinceLastTransaction, ErrorToString(error));
193     return error;
194 }
195 
FindByAddressIid(const Ip6::InterfaceIdentifier & aAddressIid)196 NdProxyTable::NdProxy *NdProxyTable::FindByAddressIid(const Ip6::InterfaceIdentifier &aAddressIid)
197 {
198     NdProxy *found = nullptr;
199 
200     for (NdProxy &proxy : Iterate(kFilterValid))
201     {
202         if (proxy.mAddressIid == aAddressIid)
203         {
204             ExitNow(found = &proxy);
205         }
206     }
207 
208 exit:
209     LogDebg("NdProxyTable::FindByAddressIid(%s) => %s", aAddressIid.ToString().AsCString(),
210             found ? found->mMeshLocalIid.ToString().AsCString() : "NOT_FOUND");
211     return found;
212 }
213 
FindByMeshLocalIid(const Ip6::InterfaceIdentifier & aMeshLocalIid)214 NdProxyTable::NdProxy *NdProxyTable::FindByMeshLocalIid(const Ip6::InterfaceIdentifier &aMeshLocalIid)
215 {
216     NdProxy *found = nullptr;
217 
218     for (NdProxy &proxy : Iterate(kFilterValid))
219     {
220         if (proxy.mMeshLocalIid == aMeshLocalIid)
221         {
222             ExitNow(found = &proxy);
223         }
224     }
225 
226 exit:
227     LogDebg("NdProxyTable::FindByMeshLocalIid(%s) => %s", aMeshLocalIid.ToString().AsCString(),
228             found ? found->mAddressIid.ToString().AsCString() : "NOT_FOUND");
229     return found;
230 }
231 
FindInvalid(void)232 NdProxyTable::NdProxy *NdProxyTable::FindInvalid(void)
233 {
234     NdProxy *found = nullptr;
235 
236     for (NdProxy &proxy : Iterate(kFilterInvalid))
237     {
238         ExitNow(found = &proxy);
239     }
240 
241 exit:
242     LogDebg("NdProxyTable::FindInvalid() => %s", found ? "OK" : "NOT_FOUND");
243     return found;
244 }
245 
HandleTimer(void)246 void NdProxyTable::HandleTimer(void)
247 {
248     VerifyOrExit(mIsAnyDadInProcess);
249 
250     mIsAnyDadInProcess = false;
251 
252     for (NdProxy &proxy : Iterate(kFilterDadInProcess))
253     {
254         if (proxy.IsDadAttemptsComplete())
255         {
256             proxy.mDadFlag = false;
257             NotifyDuaRegistrationOnBackboneLink(proxy, /* aIsRenew */ false);
258         }
259         else
260         {
261             mIsAnyDadInProcess = true;
262 
263             if (Get<BackboneRouter::Manager>().SendBackboneQuery(GetDua(proxy)) == kErrorNone)
264             {
265                 proxy.IncreaseDadAttempts();
266             }
267         }
268     }
269 
270 exit:
271     return;
272 }
273 
SetCallback(otBackboneRouterNdProxyCallback aCallback,void * aContext)274 void NdProxyTable::SetCallback(otBackboneRouterNdProxyCallback aCallback, void *aContext)
275 {
276     mCallback        = aCallback;
277     mCallbackContext = aContext;
278 }
279 
TriggerCallback(otBackboneRouterNdProxyEvent aEvent,const Ip6::InterfaceIdentifier & aAddressIid) const280 void NdProxyTable::TriggerCallback(otBackboneRouterNdProxyEvent    aEvent,
281                                    const Ip6::InterfaceIdentifier &aAddressIid) const
282 {
283     Ip6::Address       dua;
284     const Ip6::Prefix *prefix = Get<BackboneRouter::Leader>().GetDomainPrefix();
285 
286     VerifyOrExit(mCallback != nullptr);
287 
288     OT_ASSERT(prefix != nullptr);
289 
290     dua.SetPrefix(*prefix);
291     dua.SetIid(aAddressIid);
292 
293     mCallback(mCallbackContext, aEvent, &dua);
294 
295 exit:
296     return;
297 }
298 
NotifyDadComplete(NdProxyTable::NdProxy & aNdProxy,bool aDuplicated)299 void NdProxyTable::NotifyDadComplete(NdProxyTable::NdProxy &aNdProxy, bool aDuplicated)
300 {
301     if (aDuplicated)
302     {
303         Erase(aNdProxy);
304     }
305     else
306     {
307         aNdProxy.mDadAttempts = Mle::kDuaDadRepeats;
308     }
309 }
310 
GetDua(NdProxy & aNdProxy)311 Ip6::Address NdProxyTable::GetDua(NdProxy &aNdProxy)
312 {
313     Ip6::Address       dua;
314     const Ip6::Prefix *domainPrefix = Get<BackboneRouter::Leader>().GetDomainPrefix();
315 
316     OT_ASSERT(domainPrefix != nullptr);
317 
318     dua.SetPrefix(*domainPrefix);
319     dua.SetIid(aNdProxy.mAddressIid);
320 
321     return dua;
322 }
323 
ResolveDua(const Ip6::Address & aDua)324 NdProxyTable::NdProxy *NdProxyTable::ResolveDua(const Ip6::Address &aDua)
325 {
326     return Get<Leader>().IsDomainUnicast(aDua) ? FindByAddressIid(aDua.GetIid()) : nullptr;
327 }
328 
NotifyDuaRegistrationOnBackboneLink(NdProxyTable::NdProxy & aNdProxy,bool aIsRenew)329 void NdProxyTable::NotifyDuaRegistrationOnBackboneLink(NdProxyTable::NdProxy &aNdProxy, bool aIsRenew)
330 {
331     if (!aNdProxy.mDadFlag)
332     {
333         TriggerCallback(aIsRenew ? OT_BACKBONE_ROUTER_NDPROXY_RENEWED : OT_BACKBONE_ROUTER_NDPROXY_ADDED,
334                         aNdProxy.mAddressIid);
335 
336         IgnoreError(Get<BackboneRouter::Manager>().SendProactiveBackboneNotification(
337             GetDua(aNdProxy), aNdProxy.GetMeshLocalIid(), aNdProxy.GetTimeSinceLastTransaction()));
338     }
339 }
340 
GetInfo(const Ip6::Address & aDua,otBackboneRouterNdProxyInfo & aNdProxyInfo)341 Error NdProxyTable::GetInfo(const Ip6::Address &aDua, otBackboneRouterNdProxyInfo &aNdProxyInfo)
342 {
343     Error error = kErrorNotFound;
344 
345     VerifyOrExit(Get<Leader>().IsDomainUnicast(aDua), error = kErrorInvalidArgs);
346 
347     for (NdProxy &proxy : Iterate(kFilterValid))
348     {
349         if (proxy.mAddressIid == aDua.GetIid())
350         {
351             aNdProxyInfo.mMeshLocalIid             = &proxy.mMeshLocalIid;
352             aNdProxyInfo.mTimeSinceLastTransaction = proxy.GetTimeSinceLastTransaction();
353             aNdProxyInfo.mRloc16                   = proxy.mRloc16;
354 
355             ExitNow(error = kErrorNone);
356         }
357     }
358 
359 exit:
360     return error;
361 }
362 
363 } // namespace BackboneRouter
364 
365 } // namespace ot
366 
367 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
368