1 /*
2  *  Copyright (c) 2016-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 Thread neighbor table.
32  */
33 
34 #include "neighbor_table.hpp"
35 
36 #include "common/code_utils.hpp"
37 #include "common/locator_getters.hpp"
38 #include "instance/instance.hpp"
39 #include "thread/dua_manager.hpp"
40 
41 namespace ot {
42 
NeighborTable(Instance & aInstance)43 NeighborTable::NeighborTable(Instance &aInstance)
44     : InstanceLocator(aInstance)
45     , mCallback(nullptr)
46 {
47 }
48 
FindParent(const Neighbor::AddressMatcher & aMatcher)49 Neighbor *NeighborTable::FindParent(const Neighbor::AddressMatcher &aMatcher)
50 {
51     Neighbor *neighbor = nullptr;
52     Mle::Mle &mle      = Get<Mle::Mle>();
53 
54     if (mle.GetParent().Matches(aMatcher))
55     {
56         neighbor = &mle.GetParent();
57     }
58     else if (mle.GetParentCandidate().Matches(aMatcher))
59     {
60         neighbor = &mle.GetParentCandidate();
61     }
62 
63     return neighbor;
64 }
65 
FindParent(Mac::ShortAddress aShortAddress,Neighbor::StateFilter aFilter)66 Neighbor *NeighborTable::FindParent(Mac::ShortAddress aShortAddress, Neighbor::StateFilter aFilter)
67 {
68     return FindParent(Neighbor::AddressMatcher(aShortAddress, aFilter));
69 }
70 
FindParent(const Mac::ExtAddress & aExtAddress,Neighbor::StateFilter aFilter)71 Neighbor *NeighborTable::FindParent(const Mac::ExtAddress &aExtAddress, Neighbor::StateFilter aFilter)
72 {
73     return FindParent(Neighbor::AddressMatcher(aExtAddress, aFilter));
74 }
75 
FindParent(const Mac::Address & aMacAddress,Neighbor::StateFilter aFilter)76 Neighbor *NeighborTable::FindParent(const Mac::Address &aMacAddress, Neighbor::StateFilter aFilter)
77 {
78     return FindParent(Neighbor::AddressMatcher(aMacAddress, aFilter));
79 }
80 
FindNeighbor(const Neighbor::AddressMatcher & aMatcher)81 Neighbor *NeighborTable::FindNeighbor(const Neighbor::AddressMatcher &aMatcher)
82 {
83     Neighbor *neighbor = nullptr;
84 
85 #if OPENTHREAD_FTD
86     if (Get<Mle::Mle>().IsRouterOrLeader())
87     {
88         neighbor = FindChildOrRouter(aMatcher);
89     }
90 
91     if (neighbor == nullptr)
92 #endif
93     {
94         neighbor = FindParent(aMatcher);
95     }
96 
97     return neighbor;
98 }
99 
FindNeighbor(Mac::ShortAddress aShortAddress,Neighbor::StateFilter aFilter)100 Neighbor *NeighborTable::FindNeighbor(Mac::ShortAddress aShortAddress, Neighbor::StateFilter aFilter)
101 {
102     Neighbor *neighbor = nullptr;
103 
104     VerifyOrExit((aShortAddress != Mac::kShortAddrBroadcast) && (aShortAddress != Mac::kShortAddrInvalid));
105     neighbor = FindNeighbor(Neighbor::AddressMatcher(aShortAddress, aFilter));
106 
107 exit:
108     return neighbor;
109 }
110 
FindNeighbor(const Mac::ExtAddress & aExtAddress,Neighbor::StateFilter aFilter)111 Neighbor *NeighborTable::FindNeighbor(const Mac::ExtAddress &aExtAddress, Neighbor::StateFilter aFilter)
112 {
113     return FindNeighbor(Neighbor::AddressMatcher(aExtAddress, aFilter));
114 }
115 
FindNeighbor(const Mac::Address & aMacAddress,Neighbor::StateFilter aFilter)116 Neighbor *NeighborTable::FindNeighbor(const Mac::Address &aMacAddress, Neighbor::StateFilter aFilter)
117 {
118     return FindNeighbor(Neighbor::AddressMatcher(aMacAddress, aFilter));
119 }
120 
121 #if OPENTHREAD_FTD
122 
FindChildOrRouter(const Neighbor::AddressMatcher & aMatcher)123 Neighbor *NeighborTable::FindChildOrRouter(const Neighbor::AddressMatcher &aMatcher)
124 {
125     Neighbor *neighbor;
126 
127     neighbor = Get<ChildTable>().FindChild(aMatcher);
128 
129     if (neighbor == nullptr)
130     {
131         neighbor = Get<RouterTable>().FindRouter(aMatcher);
132     }
133 
134     return neighbor;
135 }
136 
FindNeighbor(const Ip6::Address & aIp6Address,Neighbor::StateFilter aFilter)137 Neighbor *NeighborTable::FindNeighbor(const Ip6::Address &aIp6Address, Neighbor::StateFilter aFilter)
138 {
139     Neighbor    *neighbor = nullptr;
140     Mac::Address macAddress;
141 
142     if (aIp6Address.IsLinkLocalUnicast())
143     {
144         aIp6Address.GetIid().ConvertToMacAddress(macAddress);
145     }
146 
147     if (Get<Mle::Mle>().IsRoutingLocator(aIp6Address))
148     {
149         macAddress.SetShort(aIp6Address.GetIid().GetLocator());
150     }
151 
152     if (!macAddress.IsNone())
153     {
154         neighbor = FindNeighbor(Neighbor::AddressMatcher(macAddress, aFilter));
155         ExitNow();
156     }
157 
158     for (Child &child : Get<ChildTable>().Iterate(aFilter))
159     {
160         if (child.HasIp6Address(aIp6Address))
161         {
162             ExitNow(neighbor = &child);
163         }
164     }
165 
166 exit:
167     return neighbor;
168 }
169 
FindRxOnlyNeighborRouter(const Mac::ExtAddress & aExtAddress)170 Neighbor *NeighborTable::FindRxOnlyNeighborRouter(const Mac::ExtAddress &aExtAddress)
171 {
172     Mac::Address macAddress;
173 
174     macAddress.SetExtended(aExtAddress);
175 
176     return FindRxOnlyNeighborRouter(macAddress);
177 }
178 
FindRxOnlyNeighborRouter(const Mac::Address & aMacAddress)179 Neighbor *NeighborTable::FindRxOnlyNeighborRouter(const Mac::Address &aMacAddress)
180 {
181     Neighbor *neighbor = nullptr;
182 
183     VerifyOrExit(Get<Mle::Mle>().IsChild());
184     neighbor = Get<RouterTable>().FindNeighbor(aMacAddress);
185 
186 exit:
187     return neighbor;
188 }
189 
GetNextNeighborInfo(otNeighborInfoIterator & aIterator,Neighbor::Info & aNeighInfo)190 Error NeighborTable::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo)
191 {
192     Error   error = kErrorNone;
193     int16_t index;
194 
195     // Non-negative iterator value gives the Child index into child table
196 
197     if (aIterator >= 0)
198     {
199         for (index = aIterator;; index++)
200         {
201             Child *child = Get<ChildTable>().GetChildAtIndex(static_cast<uint16_t>(index));
202 
203             if (child == nullptr)
204             {
205                 break;
206             }
207 
208             if (child->IsStateValid())
209             {
210                 aNeighInfo.SetFrom(*child);
211                 aNeighInfo.mIsChild = true;
212                 index++;
213                 aIterator = index;
214                 ExitNow();
215             }
216         }
217 
218         aIterator = 0;
219     }
220 
221     // Negative iterator value gives the current index into mRouters array
222 
223     for (index = -aIterator; index <= Mle::kMaxRouterId; index++)
224     {
225         Router *router = Get<RouterTable>().FindRouterById(static_cast<uint8_t>(index));
226 
227         if (router != nullptr && router->IsStateValid())
228         {
229             aNeighInfo.SetFrom(*router);
230             aNeighInfo.mIsChild = false;
231             index++;
232             aIterator = -index;
233             ExitNow();
234         }
235     }
236 
237     aIterator = -index;
238     error     = kErrorNotFound;
239 
240 exit:
241     return error;
242 }
243 
244 #endif // OPENTHREAD_FTD
245 
246 #if OPENTHREAD_MTD
247 
GetNextNeighborInfo(otNeighborInfoIterator & aIterator,Neighbor::Info & aNeighInfo)248 Error NeighborTable::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo)
249 {
250     Error error = kErrorNotFound;
251 
252     VerifyOrExit(aIterator == OT_NEIGHBOR_INFO_ITERATOR_INIT);
253 
254     aIterator++;
255     VerifyOrExit(Get<Mle::Mle>().GetParent().IsStateValid());
256 
257     aNeighInfo.SetFrom(Get<Mle::Mle>().GetParent());
258     aNeighInfo.mIsChild = false;
259     error               = kErrorNone;
260 
261 exit:
262     return error;
263 }
264 
265 #endif
266 
Signal(Event aEvent,const Neighbor & aNeighbor)267 void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor)
268 {
269 #if !OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
270     if (mCallback != nullptr)
271 #endif
272     {
273         EntryInfo info;
274 
275         info.mInstance = &GetInstance();
276 
277         switch (aEvent)
278         {
279         case kChildAdded:
280         case kChildRemoved:
281         case kChildModeChanged:
282 #if OPENTHREAD_FTD
283             OT_ASSERT(Get<ChildTable>().Contains(aNeighbor));
284             static_cast<Child::Info &>(info.mInfo.mChild).SetFrom(static_cast<const Child &>(aNeighbor));
285 #endif
286             break;
287 
288         case kRouterAdded:
289         case kRouterRemoved:
290             static_cast<Neighbor::Info &>(info.mInfo.mRouter).SetFrom(aNeighbor);
291             break;
292         }
293 
294 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
295         Get<Utils::HistoryTracker>().RecordNeighborEvent(aEvent, info);
296 
297         if (mCallback != nullptr)
298 #endif
299         {
300             mCallback(static_cast<otNeighborTableEvent>(aEvent), &info);
301         }
302     }
303 
304 #if OPENTHREAD_CONFIG_OTNS_ENABLE
305     Get<Utils::Otns>().EmitNeighborChange(aEvent, aNeighbor);
306 #endif
307 
308     switch (aEvent)
309     {
310     case kChildAdded:
311         Get<Notifier>().Signal(kEventThreadChildAdded);
312         break;
313 
314     case kChildRemoved:
315         Get<Notifier>().Signal(kEventThreadChildRemoved);
316 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
317         Get<DuaManager>().HandleChildDuaAddressEvent(static_cast<const Child &>(aNeighbor),
318                                                      DuaManager::kAddressRemoved);
319 #endif
320         break;
321 
322 #if OPENTHREAD_FTD
323     case kRouterAdded:
324     case kRouterRemoved:
325         Get<RouterTable>().SignalTableChanged();
326         break;
327 #endif
328 
329     default:
330         break;
331     }
332 }
333 
334 } // namespace ot
335