blob: f7856a11dc896bb0fd4e1be95f3aaf9f932ced0d [file] [log] [blame]
/*
* 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/instance.hpp"
#include "common/locator_getters.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.IsLinkLocal())
{
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::Address &aMacAddress)
{
Neighbor *neighbor = nullptr;
VerifyOrExit(Get<Mle::Mle>().IsChild());
neighbor = Get<RouterTable>().GetNeighbor(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>().GetRouter(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
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>().UpdateChildDomainUnicastAddress(static_cast<const Child &>(aNeighbor),
Mle::ChildDuaState::kRemoved);
#endif
break;
default:
break;
}
}
} // namespace ot