| /* |
| * 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 |