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/instance.hpp"
38 #include "common/locator_getters.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.IsLinkLocal())
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::Address & aMacAddress)170 Neighbor *NeighborTable::FindRxOnlyNeighborRouter(const Mac::Address &aMacAddress)
171 {
172     Neighbor *neighbor = nullptr;
173 
174     VerifyOrExit(Get<Mle::Mle>().IsChild());
175     neighbor = Get<RouterTable>().GetNeighbor(aMacAddress);
176 
177 exit:
178     return neighbor;
179 }
180 
GetNextNeighborInfo(otNeighborInfoIterator & aIterator,Neighbor::Info & aNeighInfo)181 Error NeighborTable::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo)
182 {
183     Error   error = kErrorNone;
184     int16_t index;
185 
186     // Non-negative iterator value gives the Child index into child table
187 
188     if (aIterator >= 0)
189     {
190         for (index = aIterator;; index++)
191         {
192             Child *child = Get<ChildTable>().GetChildAtIndex(static_cast<uint16_t>(index));
193 
194             if (child == nullptr)
195             {
196                 break;
197             }
198 
199             if (child->IsStateValid())
200             {
201                 aNeighInfo.SetFrom(*child);
202                 aNeighInfo.mIsChild = true;
203                 index++;
204                 aIterator = index;
205                 ExitNow();
206             }
207         }
208 
209         aIterator = 0;
210     }
211 
212     // Negative iterator value gives the current index into mRouters array
213 
214     for (index = -aIterator; index <= Mle::kMaxRouterId; index++)
215     {
216         Router *router = Get<RouterTable>().GetRouter(static_cast<uint8_t>(index));
217 
218         if (router != nullptr && router->IsStateValid())
219         {
220             aNeighInfo.SetFrom(*router);
221             aNeighInfo.mIsChild = false;
222             index++;
223             aIterator = -index;
224             ExitNow();
225         }
226     }
227 
228     aIterator = -index;
229     error     = kErrorNotFound;
230 
231 exit:
232     return error;
233 }
234 
235 #endif // OPENTHREAD_FTD
236 
237 #if OPENTHREAD_MTD
238 
GetNextNeighborInfo(otNeighborInfoIterator & aIterator,Neighbor::Info & aNeighInfo)239 Error NeighborTable::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo)
240 {
241     Error error = kErrorNotFound;
242 
243     VerifyOrExit(aIterator == OT_NEIGHBOR_INFO_ITERATOR_INIT);
244 
245     aIterator++;
246     VerifyOrExit(Get<Mle::Mle>().GetParent().IsStateValid());
247 
248     aNeighInfo.SetFrom(Get<Mle::Mle>().GetParent());
249     aNeighInfo.mIsChild = false;
250     error               = kErrorNone;
251 
252 exit:
253     return error;
254 }
255 
256 #endif
257 
Signal(Event aEvent,const Neighbor & aNeighbor)258 void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor)
259 {
260 #if !OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
261     if (mCallback != nullptr)
262 #endif
263     {
264         EntryInfo info;
265 
266         info.mInstance = &GetInstance();
267 
268         switch (aEvent)
269         {
270         case kChildAdded:
271         case kChildRemoved:
272         case kChildModeChanged:
273 #if OPENTHREAD_FTD
274             static_cast<Child::Info &>(info.mInfo.mChild).SetFrom(static_cast<const Child &>(aNeighbor));
275 #endif
276             break;
277 
278         case kRouterAdded:
279         case kRouterRemoved:
280             static_cast<Neighbor::Info &>(info.mInfo.mRouter).SetFrom(aNeighbor);
281             break;
282         }
283 
284 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
285         Get<Utils::HistoryTracker>().RecordNeighborEvent(aEvent, info);
286 
287         if (mCallback != nullptr)
288 #endif
289         {
290             mCallback(static_cast<otNeighborTableEvent>(aEvent), &info);
291         }
292     }
293 
294 #if OPENTHREAD_CONFIG_OTNS_ENABLE
295     Get<Utils::Otns>().EmitNeighborChange(aEvent, aNeighbor);
296 #endif
297 
298     switch (aEvent)
299     {
300     case kChildAdded:
301         Get<Notifier>().Signal(kEventThreadChildAdded);
302         break;
303 
304     case kChildRemoved:
305         Get<Notifier>().Signal(kEventThreadChildRemoved);
306 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
307         Get<DuaManager>().UpdateChildDomainUnicastAddress(static_cast<const Child &>(aNeighbor),
308                                                           Mle::ChildDuaState::kRemoved);
309 #endif
310         break;
311 
312     default:
313         break;
314     }
315 }
316 
317 } // namespace ot
318