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