blob: 7299befc1552f7548774169a5dec68d2a938f7b5 [file] [log] [blame]
/*
* Copyright (c) 2016, 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 implements the local Thread Network Data.
*/
#include "network_data_local.hpp"
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "mac/mac_types.hpp"
#include "thread/mle_types.hpp"
#include "thread/thread_netif.hpp"
namespace ot {
namespace NetworkData {
RegisterLogModule("NetworkData");
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
Error Local::AddOnMeshPrefix(const OnMeshPrefixConfig &aConfig)
{
Error error = kErrorInvalidArgs;
VerifyOrExit(aConfig.IsValid(GetInstance()));
error =
AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeBorderRouter, aConfig.ConvertToTlvFlags(), aConfig.mStable);
exit:
return error;
}
bool Local::ContainsOnMeshPrefix(const Ip6::Prefix &aPrefix) const
{
const PrefixTlv *tlv;
bool contains = false;
VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr);
VerifyOrExit(tlv->FindSubTlv(NetworkDataTlv::kTypeBorderRouter) != nullptr);
contains = true;
exit:
return contains;
}
Error Local::AddHasRoutePrefix(const ExternalRouteConfig &aConfig)
{
Error error = kErrorInvalidArgs;
VerifyOrExit(aConfig.IsValid(GetInstance()));
error = AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeHasRoute, aConfig.ConvertToTlvFlags(), aConfig.mStable);
exit:
return error;
}
Error Local::AddPrefix(const Ip6::Prefix &aPrefix, NetworkDataTlv::Type aSubTlvType, uint16_t aFlags, bool aStable)
{
Error error = kErrorNone;
uint8_t subTlvLength;
PrefixTlv *prefixTlv;
IgnoreError(RemovePrefix(aPrefix));
subTlvLength = (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
? sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry)
: sizeof(HasRouteTlv) + sizeof(HasRouteEntry);
prefixTlv = As<PrefixTlv>(AppendTlv(sizeof(PrefixTlv) + aPrefix.GetBytesSize() + subTlvLength));
VerifyOrExit(prefixTlv != nullptr, error = kErrorNoBufs);
prefixTlv->Init(0, aPrefix);
prefixTlv->SetSubTlvsLength(subTlvLength);
if (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
{
BorderRouterTlv *brTlv = As<BorderRouterTlv>(prefixTlv->GetSubTlvs());
brTlv->Init();
brTlv->SetLength(brTlv->GetLength() + sizeof(BorderRouterEntry));
brTlv->GetEntry(0)->Init();
brTlv->GetEntry(0)->SetFlags(aFlags);
}
else // aSubTlvType is NetworkDataTlv::kTypeHasRoute
{
HasRouteTlv *hasRouteTlv = As<HasRouteTlv>(prefixTlv->GetSubTlvs());
hasRouteTlv->Init();
hasRouteTlv->SetLength(hasRouteTlv->GetLength() + sizeof(HasRouteEntry));
hasRouteTlv->GetEntry(0)->Init();
hasRouteTlv->GetEntry(0)->SetFlags(static_cast<uint8_t>(aFlags));
}
if (aStable)
{
prefixTlv->SetStable();
prefixTlv->GetSubTlvs()->SetStable();
}
DumpDebg("AddPrefix", GetBytes(), GetLength());
exit:
return error;
}
Error Local::RemovePrefix(const Ip6::Prefix &aPrefix)
{
Error error = kErrorNone;
PrefixTlv *tlv;
VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr, error = kErrorNotFound);
RemoveTlv(tlv);
exit:
DumpDebg("RmvPrefix", GetBytes(), GetLength());
return error;
}
void Local::UpdateRloc(PrefixTlv &aPrefixTlv)
{
uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
for (NetworkDataTlv *cur = aPrefixTlv.GetSubTlvs(); cur < aPrefixTlv.GetNext(); cur = cur->GetNext())
{
switch (cur->GetType())
{
case NetworkDataTlv::kTypeHasRoute:
As<HasRouteTlv>(cur)->GetEntry(0)->SetRloc(rloc16);
break;
case NetworkDataTlv::kTypeBorderRouter:
As<BorderRouterTlv>(cur)->GetEntry(0)->SetRloc(rloc16);
break;
default:
OT_ASSERT(false);
OT_UNREACHABLE_CODE(break);
}
}
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
Error Local::AddService(uint32_t aEnterpriseNumber,
const ServiceData &aServiceData,
bool aServerStable,
const ServerData & aServerData)
{
Error error = kErrorNone;
ServiceTlv *serviceTlv;
ServerTlv * serverTlv;
uint16_t serviceTlvSize = ServiceTlv::CalculateSize(aEnterpriseNumber, aServiceData.GetLength()) +
sizeof(ServerTlv) + aServerData.GetLength();
IgnoreError(RemoveService(aEnterpriseNumber, aServiceData));
VerifyOrExit(serviceTlvSize <= kMaxSize, error = kErrorNoBufs);
serviceTlv = As<ServiceTlv>(AppendTlv(serviceTlvSize));
VerifyOrExit(serviceTlv != nullptr, error = kErrorNoBufs);
serviceTlv->Init(/* aServiceId */ 0, aEnterpriseNumber, aServiceData);
serviceTlv->SetSubTlvsLength(sizeof(ServerTlv) + aServerData.GetLength());
serverTlv = As<ServerTlv>(serviceTlv->GetSubTlvs());
serverTlv->Init(Get<Mle::MleRouter>().GetRloc16(), aServerData);
// According to Thread spec 1.1.1, section 5.18.6 Service TLV:
// "The Stable flag is set if any of the included sub-TLVs have their Stable flag set."
// The meaning also seems to be 'if and only if'.
if (aServerStable)
{
serviceTlv->SetStable();
serverTlv->SetStable();
}
DumpDebg("AddService", GetBytes(), GetLength());
exit:
return error;
}
Error Local::RemoveService(uint32_t aEnterpriseNumber, const ServiceData &aServiceData)
{
Error error = kErrorNone;
ServiceTlv *tlv;
VerifyOrExit((tlv = FindService(aEnterpriseNumber, aServiceData, kServiceExactMatch)) != nullptr,
error = kErrorNotFound);
RemoveTlv(tlv);
exit:
DumpDebg("RmvService", GetBytes(), GetLength());
return error;
}
void Local::UpdateRloc(ServiceTlv &aService)
{
uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
for (NetworkDataTlv *cur = aService.GetSubTlvs(); cur < aService.GetNext(); cur = cur->GetNext())
{
switch (cur->GetType())
{
case NetworkDataTlv::kTypeServer:
As<ServerTlv>(cur)->SetServer16(rloc16);
break;
default:
OT_ASSERT(false);
OT_UNREACHABLE_CODE(break);
}
}
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
void Local::UpdateRloc(void)
{
for (NetworkDataTlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
{
switch (cur->GetType())
{
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
case NetworkDataTlv::kTypePrefix:
UpdateRloc(*As<PrefixTlv>(cur));
break;
#endif
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
case NetworkDataTlv::kTypeService:
UpdateRloc(*As<ServiceTlv>(cur));
break;
#endif
default:
OT_ASSERT(false);
OT_UNREACHABLE_CODE(break);
}
}
}
bool Local::IsConsistent(void) const
{
return Get<Leader>().ContainsEntriesFrom(*this, Get<Mle::MleRouter>().GetRloc16()) &&
ContainsEntriesFrom(Get<Leader>(), Get<Mle::MleRouter>().GetRloc16());
}
Error Local::UpdateInconsistentServerData(Coap::ResponseHandler aHandler, void *aContext)
{
Error error = kErrorNone;
uint16_t rloc = Get<Mle::MleRouter>().GetRloc16();
#if OPENTHREAD_FTD
// Don't send this Server Data Notification if the device is going to upgrade to Router
if (Get<Mle::MleRouter>().IsExpectedToBecomeRouterSoon())
{
ExitNow(error = kErrorInvalidState);
}
#endif
UpdateRloc();
VerifyOrExit(!IsConsistent(), error = kErrorNotFound);
if (mOldRloc == rloc)
{
mOldRloc = Mac::kShortAddrInvalid;
}
SuccessOrExit(error = SendServerDataNotification(mOldRloc, /* aAppendNetDataTlv */ true, aHandler, aContext));
mOldRloc = rloc;
exit:
return error;
}
} // namespace NetworkData
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE