blob: fc7f6b1fee56b4af6921018a92823db8cdea6d12 [file] [log] [blame]
/*
* Copyright (c) 2016-2017, 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 maintaining Thread network topologies.
*/
#include "topology.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
namespace ot {
bool Neighbor::IsStateValidOrAttaching(void) const
{
bool rval = false;
switch (GetState())
{
case kStateInvalid:
case kStateParentRequest:
case kStateParentResponse:
break;
case kStateRestored:
case kStateChildIdRequest:
case kStateLinkRequest:
case kStateChildUpdateRequest:
case kStateValid:
rval = true;
break;
}
return rval;
}
bool Neighbor::MatchesFilter(StateFilter aFilter) const
{
bool matches = false;
switch (aFilter)
{
case kInStateValid:
matches = IsStateValid();
break;
case kInStateValidOrRestoring:
matches = IsStateValidOrRestoring();
break;
case kInStateChildIdRequest:
matches = IsStateChildIdRequest();
break;
case kInStateValidOrAttaching:
matches = IsStateValidOrAttaching();
break;
case kInStateAnyExceptInvalid:
matches = !IsStateInvalid();
break;
case kInStateAnyExceptValidOrRestoring:
matches = !IsStateValidOrRestoring();
break;
}
return matches;
}
void Neighbor::GenerateChallenge(void)
{
Random::Crypto::FillBuffer(mValidPending.mPending.mChallenge, sizeof(mValidPending.mPending.mChallenge));
}
void Child::Clear(void)
{
memset(reinterpret_cast<void *>(this), 0, sizeof(Child));
SetState(kStateInvalid);
}
void Child::ClearIp6Addresses(void)
{
memset(mMeshLocalIid, 0, sizeof(mMeshLocalIid));
memset(mIp6Address, 0, sizeof(mIp6Address));
}
/**
* Determines if all elements in an array are zero.
*
* @param[in] aArray A pointer to an array of bytes.
* @param[in] aLength Array length (number of bytes).
*
* @returns TRUE if all bytes in the array are zero, FALSE otherwise.
*
*/
static bool IsAllZero(const uint8_t *aArray, uint8_t aLength)
{
bool retval = true;
for (; aLength != 0; aArray++, aLength--)
{
VerifyOrExit(*aArray == 0, retval = false);
}
exit:
return retval;
}
otError Child::GetMeshLocalIp6Address(Instance &aInstance, Ip6::Address &aAddress) const
{
otError error = OT_ERROR_NONE;
VerifyOrExit(!IsAllZero(mMeshLocalIid, sizeof(mMeshLocalIid)), error = OT_ERROR_NOT_FOUND);
memcpy(aAddress.mFields.m8, aInstance.Get<Mle::MleRouter>().GetMeshLocalPrefix().m8,
Ip6::Address::kMeshLocalPrefixSize);
aAddress.SetIid(mMeshLocalIid);
exit:
return error;
}
otError Child::GetNextIp6Address(Instance &aInstance, Ip6AddressIterator &aIterator, Ip6::Address &aAddress) const
{
otError error = OT_ERROR_NONE;
otChildIp6AddressIterator index;
// Index zero corresponds to the Mesh Local IPv6 address (if any).
if (aIterator.Get() == 0)
{
aIterator.Increment();
VerifyOrExit(GetMeshLocalIp6Address(aInstance, aAddress) == OT_ERROR_NOT_FOUND);
}
index = aIterator.Get() - 1;
VerifyOrExit(index < kNumIp6Addresses, error = OT_ERROR_NOT_FOUND);
VerifyOrExit(!mIp6Address[index].IsUnspecified(), error = OT_ERROR_NOT_FOUND);
aAddress = mIp6Address[index];
aIterator.Increment();
exit:
return error;
}
otError Child::AddIp6Address(Instance &aInstance, const Ip6::Address &aAddress)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(!aAddress.IsUnspecified(), error = OT_ERROR_INVALID_ARGS);
if (aInstance.Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
{
VerifyOrExit(IsAllZero(mMeshLocalIid, sizeof(mMeshLocalIid)), error = OT_ERROR_ALREADY);
memcpy(mMeshLocalIid, aAddress.GetIid(), Ip6::Address::kInterfaceIdentifierSize);
ExitNow();
}
for (uint16_t index = 0; index < kNumIp6Addresses; index++)
{
if (mIp6Address[index].IsUnspecified())
{
mIp6Address[index] = aAddress;
ExitNow();
}
VerifyOrExit(mIp6Address[index] != aAddress, error = OT_ERROR_ALREADY);
}
error = OT_ERROR_NO_BUFS;
exit:
return error;
}
otError Child::RemoveIp6Address(Instance &aInstance, const Ip6::Address &aAddress)
{
otError error = OT_ERROR_NOT_FOUND;
uint16_t index;
VerifyOrExit(!aAddress.IsUnspecified(), error = OT_ERROR_INVALID_ARGS);
if (aInstance.Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
{
if (memcmp(aAddress.GetIid(), mMeshLocalIid, Ip6::Address::kInterfaceIdentifierSize) == 0)
{
memset(mMeshLocalIid, 0, sizeof(mMeshLocalIid));
error = OT_ERROR_NONE;
}
ExitNow();
}
for (index = 0; index < kNumIp6Addresses; index++)
{
VerifyOrExit(!mIp6Address[index].IsUnspecified());
if (mIp6Address[index] == aAddress)
{
error = OT_ERROR_NONE;
break;
}
}
SuccessOrExit(error);
for (; index < kNumIp6Addresses - 1; index++)
{
mIp6Address[index] = mIp6Address[index + 1];
}
mIp6Address[kNumIp6Addresses - 1].Clear();
exit:
return error;
}
bool Child::HasIp6Address(Instance &aInstance, const Ip6::Address &aAddress) const
{
bool retval = false;
VerifyOrExit(!aAddress.IsUnspecified());
if (aInstance.Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
{
retval = (memcmp(aAddress.GetIid(), mMeshLocalIid, Ip6::Address::kInterfaceIdentifierSize) == 0);
ExitNow();
}
for (uint16_t index = 0; index < kNumIp6Addresses; index++)
{
VerifyOrExit(!mIp6Address[index].IsUnspecified());
if (mIp6Address[index] == aAddress)
{
ExitNow(retval = true);
}
}
exit:
return retval;
}
void Child::GenerateChallenge(void)
{
Random::Crypto::FillBuffer(mAttachChallenge, sizeof(mAttachChallenge));
}
void Router::Clear(void)
{
memset(reinterpret_cast<void *>(this), 0, sizeof(Router));
SetState(kStateInvalid);
}
} // namespace ot