/* * Copyright (c) 2016-2020, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file * This file includes definitions for Thread neighbor table. */ #include "neighbor_table.hpp" #include "common/code_utils.hpp" #include "common/locator_getters.hpp" #include "instance/instance.hpp" #include "thread/dua_manager.hpp" namespace ot { NeighborTable::NeighborTable(Instance &aInstance) : InstanceLocator(aInstance) , mCallback(nullptr) { } Neighbor *NeighborTable::FindParent(const Neighbor::AddressMatcher &aMatcher) { Neighbor *neighbor = nullptr; Mle::Mle &mle = Get<Mle::Mle>(); if (mle.GetParent().Matches(aMatcher)) { neighbor = &mle.GetParent(); } else if (mle.GetParentCandidate().Matches(aMatcher)) { neighbor = &mle.GetParentCandidate(); } return neighbor; } Neighbor *NeighborTable::FindParent(Mac::ShortAddress aShortAddress, Neighbor::StateFilter aFilter) { return FindParent(Neighbor::AddressMatcher(aShortAddress, aFilter)); } Neighbor *NeighborTable::FindParent(const Mac::ExtAddress &aExtAddress, Neighbor::StateFilter aFilter) { return FindParent(Neighbor::AddressMatcher(aExtAddress, aFilter)); } Neighbor *NeighborTable::FindParent(const Mac::Address &aMacAddress, Neighbor::StateFilter aFilter) { return FindParent(Neighbor::AddressMatcher(aMacAddress, aFilter)); } Neighbor *NeighborTable::FindNeighbor(const Neighbor::AddressMatcher &aMatcher) { Neighbor *neighbor = nullptr; #if OPENTHREAD_FTD if (Get<Mle::Mle>().IsRouterOrLeader()) { neighbor = FindChildOrRouter(aMatcher); } if (neighbor == nullptr) #endif { neighbor = FindParent(aMatcher); } return neighbor; } Neighbor *NeighborTable::FindNeighbor(Mac::ShortAddress aShortAddress, Neighbor::StateFilter aFilter) { Neighbor *neighbor = nullptr; VerifyOrExit((aShortAddress != Mac::kShortAddrBroadcast) && (aShortAddress != Mac::kShortAddrInvalid)); neighbor = FindNeighbor(Neighbor::AddressMatcher(aShortAddress, aFilter)); exit: return neighbor; } Neighbor *NeighborTable::FindNeighbor(const Mac::ExtAddress &aExtAddress, Neighbor::StateFilter aFilter) { return FindNeighbor(Neighbor::AddressMatcher(aExtAddress, aFilter)); } Neighbor *NeighborTable::FindNeighbor(const Mac::Address &aMacAddress, Neighbor::StateFilter aFilter) { return FindNeighbor(Neighbor::AddressMatcher(aMacAddress, aFilter)); } #if OPENTHREAD_FTD Neighbor *NeighborTable::FindChildOrRouter(const Neighbor::AddressMatcher &aMatcher) { Neighbor *neighbor; neighbor = Get<ChildTable>().FindChild(aMatcher); if (neighbor == nullptr) { neighbor = Get<RouterTable>().FindRouter(aMatcher); } return neighbor; } Neighbor *NeighborTable::FindNeighbor(const Ip6::Address &aIp6Address, Neighbor::StateFilter aFilter) { Neighbor *neighbor = nullptr; Mac::Address macAddress; if (aIp6Address.IsLinkLocalUnicast()) { aIp6Address.GetIid().ConvertToMacAddress(macAddress); } if (Get<Mle::Mle>().IsRoutingLocator(aIp6Address)) { macAddress.SetShort(aIp6Address.GetIid().GetLocator()); } if (!macAddress.IsNone()) { neighbor = FindNeighbor(Neighbor::AddressMatcher(macAddress, aFilter)); ExitNow(); } for (Child &child : Get<ChildTable>().Iterate(aFilter)) { if (child.HasIp6Address(aIp6Address)) { ExitNow(neighbor = &child); } } exit: return neighbor; } Neighbor *NeighborTable::FindRxOnlyNeighborRouter(const Mac::ExtAddress &aExtAddress) { Mac::Address macAddress; macAddress.SetExtended(aExtAddress); return FindRxOnlyNeighborRouter(macAddress); } Neighbor *NeighborTable::FindRxOnlyNeighborRouter(const Mac::Address &aMacAddress) { Neighbor *neighbor = nullptr; VerifyOrExit(Get<Mle::Mle>().IsChild()); neighbor = Get<RouterTable>().FindNeighbor(aMacAddress); exit: return neighbor; } Error NeighborTable::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo) { Error error = kErrorNone; int16_t index; // Non-negative iterator value gives the Child index into child table if (aIterator >= 0) { for (index = aIterator;; index++) { Child *child = Get<ChildTable>().GetChildAtIndex(static_cast<uint16_t>(index)); if (child == nullptr) { break; } if (child->IsStateValid()) { aNeighInfo.SetFrom(*child); aNeighInfo.mIsChild = true; index++; aIterator = index; ExitNow(); } } aIterator = 0; } // Negative iterator value gives the current index into mRouters array for (index = -aIterator; index <= Mle::kMaxRouterId; index++) { Router *router = Get<RouterTable>().FindRouterById(static_cast<uint8_t>(index)); if (router != nullptr && router->IsStateValid()) { aNeighInfo.SetFrom(*router); aNeighInfo.mIsChild = false; index++; aIterator = -index; ExitNow(); } } aIterator = -index; error = kErrorNotFound; exit: return error; } #endif // OPENTHREAD_FTD #if OPENTHREAD_MTD Error NeighborTable::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo) { Error error = kErrorNotFound; VerifyOrExit(aIterator == OT_NEIGHBOR_INFO_ITERATOR_INIT); aIterator++; VerifyOrExit(Get<Mle::Mle>().GetParent().IsStateValid()); aNeighInfo.SetFrom(Get<Mle::Mle>().GetParent()); aNeighInfo.mIsChild = false; error = kErrorNone; exit: return error; } #endif void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor) { #if !OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE if (mCallback != nullptr) #endif { EntryInfo info; info.mInstance = &GetInstance(); switch (aEvent) { case kChildAdded: case kChildRemoved: case kChildModeChanged: #if OPENTHREAD_FTD OT_ASSERT(Get<ChildTable>().Contains(aNeighbor)); static_cast<Child::Info &>(info.mInfo.mChild).SetFrom(static_cast<const Child &>(aNeighbor)); #endif break; case kRouterAdded: case kRouterRemoved: static_cast<Neighbor::Info &>(info.mInfo.mRouter).SetFrom(aNeighbor); break; } #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE Get<Utils::HistoryTracker>().RecordNeighborEvent(aEvent, info); if (mCallback != nullptr) #endif { mCallback(static_cast<otNeighborTableEvent>(aEvent), &info); } } #if OPENTHREAD_CONFIG_OTNS_ENABLE Get<Utils::Otns>().EmitNeighborChange(aEvent, aNeighbor); #endif switch (aEvent) { case kChildAdded: Get<Notifier>().Signal(kEventThreadChildAdded); break; case kChildRemoved: Get<Notifier>().Signal(kEventThreadChildRemoved); #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE Get<DuaManager>().HandleChildDuaAddressEvent(static_cast<const Child &>(aNeighbor), DuaManager::kAddressRemoved); #endif break; #if OPENTHREAD_FTD case kRouterAdded: case kRouterRemoved: Get<RouterTable>().SignalTableChanged(); break; #endif default: break; } } } // namespace ot