blob: 1d21317b8e6d703b2b84f550742683fe9314b68c [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 common methods for manipulating Thread Network Data.
*/
#include "network_data.hpp"
#include "coap/coap_message.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
#include "mac/mac_types.hpp"
#include "thread/thread_netif.hpp"
#include "thread/thread_tlvs.hpp"
#include "thread/thread_uri_paths.hpp"
namespace ot {
namespace NetworkData {
NetworkData::NetworkData(Instance &aInstance, Type aType)
: InstanceLocator(aInstance)
, mType(aType)
{
mLength = 0;
}
void NetworkData::Clear(void)
{
mLength = 0;
}
const NetworkDataTlv *NetworkData::FindTlv(const NetworkDataTlv *aStart,
const NetworkDataTlv *aEnd,
NetworkDataTlv::Type aType)
{
const NetworkDataTlv *tlv;
for (tlv = aStart; tlv < aEnd; tlv = tlv->GetNext())
{
VerifyOrExit((tlv + 1) <= aEnd && tlv->GetNext() <= aEnd, tlv = NULL);
if (tlv->GetType() == aType)
{
ExitNow();
}
}
tlv = NULL;
exit:
return tlv;
}
const NetworkDataTlv *NetworkData::FindTlv(const NetworkDataTlv *aStart,
const NetworkDataTlv *aEnd,
NetworkDataTlv::Type aType,
bool aStable)
{
const NetworkDataTlv *tlv;
for (tlv = aStart; tlv < aEnd; tlv = tlv->GetNext())
{
VerifyOrExit((tlv + 1) <= aEnd && tlv->GetNext() <= aEnd, tlv = NULL);
if ((tlv->GetType() == aType) && (tlv->IsStable() == aStable))
{
ExitNow();
}
}
tlv = NULL;
exit:
return tlv;
}
otError NetworkData::GetNetworkData(bool aStable, uint8_t *aData, uint8_t &aDataLength) const
{
otError error = OT_ERROR_NONE;
OT_ASSERT(aData != NULL);
VerifyOrExit(aDataLength >= mLength, error = OT_ERROR_NO_BUFS);
memcpy(aData, mTlvs, mLength);
aDataLength = mLength;
if (aStable)
{
RemoveTemporaryData(aData, aDataLength);
}
exit:
return error;
}
otError NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, OnMeshPrefixConfig &aConfig) const
{
return GetNextOnMeshPrefix(aIterator, Mac::kShortAddrBroadcast, aConfig);
}
otError NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, uint16_t aRloc16, OnMeshPrefixConfig &aConfig) const
{
Config config;
config.mOnMeshPrefix = &aConfig;
config.mExternalRoute = NULL;
config.mService = NULL;
return Iterate(aIterator, aRloc16, config);
}
otError NetworkData::GetNextExternalRoute(Iterator &aIterator, ExternalRouteConfig &aConfig) const
{
return GetNextExternalRoute(aIterator, Mac::kShortAddrBroadcast, aConfig);
}
otError NetworkData::GetNextExternalRoute(Iterator &aIterator, uint16_t aRloc16, ExternalRouteConfig &aConfig) const
{
Config config;
config.mOnMeshPrefix = NULL;
config.mExternalRoute = &aConfig;
config.mService = NULL;
return Iterate(aIterator, aRloc16, config);
}
otError NetworkData::GetNextService(Iterator &aIterator, ServiceConfig &aConfig) const
{
return GetNextService(aIterator, Mac::kShortAddrBroadcast, aConfig);
}
otError NetworkData::GetNextService(Iterator &aIterator, uint16_t aRloc16, ServiceConfig &aConfig) const
{
Config config;
config.mOnMeshPrefix = NULL;
config.mExternalRoute = NULL;
config.mService = &aConfig;
return Iterate(aIterator, aRloc16, config);
}
otError NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfig) const
{
// Iterate to the next entry in Network Data matching `aRloc16`
// (can be set to `Mac::kShortAddrBroadcast` to allow any RLOC).
// The `aIterator` is used to track and save the current position.
// On input, the non-NULL pointer members in `aConfig` specify the
// Network Data entry types (`mOnMeshPrefix`, `mExternalRoute`,
// `mService`) to iterate over. On successful exit, the `aConfig`
// is updated such that only one member pointer is not NULL
// indicating the type of entry and the non-NULL config is updated
// with the entry info.
otError error = OT_ERROR_NOT_FOUND;
NetworkDataIterator iterator(aIterator);
for (const NetworkDataTlv *cur; (cur = iterator.GetTlv(mTlvs)) < GetTlvsEnd(); iterator.AdvanceTlv(mTlvs))
{
const NetworkDataTlv *subTlvs = NULL;
switch (cur->GetType())
{
case NetworkDataTlv::kTypePrefix:
if ((aConfig.mOnMeshPrefix != NULL) || (aConfig.mExternalRoute != NULL))
{
subTlvs = static_cast<const PrefixTlv *>(cur)->GetSubTlvs();
}
break;
case NetworkDataTlv::kTypeService:
if (aConfig.mService != NULL)
{
subTlvs = static_cast<const ServiceTlv *>(cur)->GetSubTlvs();
}
break;
default:
break;
}
if (subTlvs == NULL)
{
continue;
}
for (const NetworkDataTlv *subCur; (subCur = iterator.GetSubTlv(subTlvs)) < cur->GetNext();
iterator.AdvaceSubTlv(subTlvs))
{
if (cur->GetType() == NetworkDataTlv::kTypePrefix)
{
const PrefixTlv *prefix = static_cast<const PrefixTlv *>(cur);
switch (subCur->GetType())
{
case NetworkDataTlv::kTypeBorderRouter:
{
const BorderRouterTlv *borderRouter = static_cast<const BorderRouterTlv *>(subCur);
if (aConfig.mOnMeshPrefix == NULL)
{
continue;
}
for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < borderRouter->GetNumEntries();)
{
if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(index)->GetRloc() == aRloc16)
{
const BorderRouterEntry *borderRouterEntry = borderRouter->GetEntry(index);
aConfig.mExternalRoute = NULL;
aConfig.mService = NULL;
memset(aConfig.mOnMeshPrefix, 0, sizeof(OnMeshPrefixConfig));
memcpy(&aConfig.mOnMeshPrefix->mPrefix.mPrefix, prefix->GetPrefix(),
BitVectorBytes(prefix->GetPrefixLength()));
aConfig.mOnMeshPrefix->mPrefix.mLength = prefix->GetPrefixLength();
aConfig.mOnMeshPrefix->mPreference = borderRouterEntry->GetPreference();
aConfig.mOnMeshPrefix->mPreferred = borderRouterEntry->IsPreferred();
aConfig.mOnMeshPrefix->mSlaac = borderRouterEntry->IsSlaac();
aConfig.mOnMeshPrefix->mDhcp = borderRouterEntry->IsDhcp();
aConfig.mOnMeshPrefix->mConfigure = borderRouterEntry->IsConfigure();
aConfig.mOnMeshPrefix->mDefaultRoute = borderRouterEntry->IsDefaultRoute();
aConfig.mOnMeshPrefix->mOnMesh = borderRouterEntry->IsOnMesh();
aConfig.mOnMeshPrefix->mStable = borderRouter->IsStable();
aConfig.mOnMeshPrefix->mRloc16 = borderRouterEntry->GetRloc();
aConfig.mOnMeshPrefix->mNdDns = borderRouterEntry->IsNdDns();
aConfig.mOnMeshPrefix->mDp = borderRouterEntry->IsDp();
ExitNow(error = OT_ERROR_NONE);
}
}
break;
}
case NetworkDataTlv::kTypeHasRoute:
{
const HasRouteTlv *hasRoute = static_cast<const HasRouteTlv *>(subCur);
if (aConfig.mExternalRoute == NULL)
{
continue;
}
for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < hasRoute->GetNumEntries();)
{
if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(index)->GetRloc() == aRloc16)
{
const HasRouteEntry *hasRouteEntry = hasRoute->GetEntry(index);
aConfig.mOnMeshPrefix = NULL;
aConfig.mService = NULL;
memset(aConfig.mExternalRoute, 0, sizeof(ExternalRouteConfig));
memcpy(&aConfig.mExternalRoute->mPrefix.mPrefix, prefix->GetPrefix(),
BitVectorBytes(prefix->GetPrefixLength()));
aConfig.mExternalRoute->mPrefix.mLength = prefix->GetPrefixLength();
aConfig.mExternalRoute->mPreference = hasRouteEntry->GetPreference();
aConfig.mExternalRoute->mStable = hasRoute->IsStable();
aConfig.mExternalRoute->mRloc16 = hasRouteEntry->GetRloc();
aConfig.mExternalRoute->mNextHopIsThisDevice =
(hasRouteEntry->GetRloc() == Get<Mle::MleRouter>().GetRloc16());
ExitNow(error = OT_ERROR_NONE);
}
}
break;
}
default:
break;
}
}
else // cur is `ServiceTLv`
{
const ServiceTlv *service = static_cast<const ServiceTlv *>(cur);
if (subCur->GetType() == NetworkDataTlv::kTypeServer)
{
const ServerTlv *server = static_cast<const ServerTlv *>(subCur);
if (!iterator.IsNewEntry())
{
continue;
}
if ((aRloc16 == Mac::kShortAddrBroadcast) || (server->GetServer16() == aRloc16))
{
aConfig.mOnMeshPrefix = NULL;
aConfig.mExternalRoute = NULL;
memset(aConfig.mService, 0, sizeof(ServiceConfig));
aConfig.mService->mServiceId = service->GetServiceId();
aConfig.mService->mEnterpriseNumber = service->GetEnterpriseNumber();
aConfig.mService->mServiceDataLength = service->GetServiceDataLength();
memcpy(&aConfig.mService->mServiceData, service->GetServiceData(),
service->GetServiceDataLength());
aConfig.mService->mServerConfig.mStable = server->IsStable();
aConfig.mService->mServerConfig.mServerDataLength = server->GetServerDataLength();
memcpy(&aConfig.mService->mServerConfig.mServerData, server->GetServerData(),
server->GetServerDataLength());
aConfig.mService->mServerConfig.mRloc16 = server->GetServer16();
iterator.MarkEntryAsNotNew();
ExitNow(error = OT_ERROR_NONE);
}
}
}
}
}
exit:
return error;
}
otError NetworkData::GetNextServiceId(Iterator &aIterator, uint16_t aRloc16, uint8_t &aServiceId) const
{
otError error;
ServiceConfig config;
SuccessOrExit(error = GetNextService(aIterator, aRloc16, config));
aServiceId = config.mServiceId;
exit:
return error;
}
bool NetworkData::ContainsOnMeshPrefixes(const NetworkData &aCompare, uint16_t aRloc16) const
{
Iterator outerIterator = kIteratorInit;
OnMeshPrefixConfig outerConfig;
bool rval = true;
while (aCompare.GetNextOnMeshPrefix(outerIterator, aRloc16, outerConfig) == OT_ERROR_NONE)
{
Iterator innerIterator = kIteratorInit;
OnMeshPrefixConfig innerConfig;
otError error;
while ((error = GetNextOnMeshPrefix(innerIterator, aRloc16, innerConfig)) == OT_ERROR_NONE)
{
if (memcmp(&outerConfig, &innerConfig, sizeof(outerConfig)) == 0)
{
break;
}
}
if (error != OT_ERROR_NONE)
{
ExitNow(rval = false);
}
}
exit:
return rval;
}
bool NetworkData::ContainsExternalRoutes(const NetworkData &aCompare, uint16_t aRloc16) const
{
Iterator outerIterator = kIteratorInit;
ExternalRouteConfig outerConfig;
bool rval = true;
while (aCompare.GetNextExternalRoute(outerIterator, aRloc16, outerConfig) == OT_ERROR_NONE)
{
Iterator innerIterator = kIteratorInit;
ExternalRouteConfig innerConfig;
otError error;
while ((error = GetNextExternalRoute(innerIterator, aRloc16, innerConfig)) == OT_ERROR_NONE)
{
if (memcmp(&outerConfig, &innerConfig, sizeof(outerConfig)) == 0)
{
break;
}
}
if (error != OT_ERROR_NONE)
{
ExitNow(rval = false);
}
}
exit:
return rval;
}
bool NetworkData::ContainsServices(const NetworkData &aCompare, uint16_t aRloc16) const
{
Iterator outerIterator = kIteratorInit;
ServiceConfig outerConfig;
bool rval = true;
while (aCompare.GetNextService(outerIterator, aRloc16, outerConfig) == OT_ERROR_NONE)
{
Iterator innerIterator = kIteratorInit;
ServiceConfig innerConfig;
otError error;
while ((error = GetNextService(innerIterator, aRloc16, innerConfig)) == OT_ERROR_NONE)
{
if ((outerConfig.mEnterpriseNumber == innerConfig.mEnterpriseNumber) &&
(outerConfig.mServiceDataLength == innerConfig.mServiceDataLength) &&
(memcmp(outerConfig.mServiceData, innerConfig.mServiceData, outerConfig.mServiceDataLength) == 0) &&
(outerConfig.mServerConfig.mStable == innerConfig.mServerConfig.mStable) &&
(outerConfig.mServerConfig.mServerDataLength == innerConfig.mServerConfig.mServerDataLength) &&
(memcmp(outerConfig.mServerConfig.mServerData, innerConfig.mServerConfig.mServerData,
outerConfig.mServerConfig.mServerDataLength) == 0))
{
break;
}
}
if (error != OT_ERROR_NONE)
{
ExitNow(rval = false);
}
}
exit:
return rval;
}
bool NetworkData::ContainsService(uint8_t aServiceId, uint16_t aRloc16) const
{
Iterator iterator = kIteratorInit;
uint8_t serviceId;
bool rval = false;
while (GetNextServiceId(iterator, aRloc16, serviceId) == OT_ERROR_NONE)
{
if (serviceId == aServiceId)
{
ExitNow(rval = true);
}
}
exit:
return rval;
}
void NetworkData::RemoveTemporaryData(uint8_t *aData, uint8_t &aDataLength)
{
NetworkDataTlv *cur = reinterpret_cast<NetworkDataTlv *>(aData);
while (cur < reinterpret_cast<NetworkDataTlv *>(aData + aDataLength))
{
switch (cur->GetType())
{
case NetworkDataTlv::kTypePrefix:
{
PrefixTlv *prefix = static_cast<PrefixTlv *>(cur);
RemoveTemporaryData(aData, aDataLength, *prefix);
if (prefix->GetSubTlvsLength() == 0)
{
RemoveTlv(aData, aDataLength, cur);
continue;
}
otDumpDebgNetData("remove prefix done", aData, aDataLength);
break;
}
case NetworkDataTlv::kTypeService:
{
ServiceTlv *service = static_cast<ServiceTlv *>(cur);
RemoveTemporaryData(aData, aDataLength, *service);
if (service->GetSubTlvsLength() == 0)
{
RemoveTlv(aData, aDataLength, cur);
continue;
}
otDumpDebgNetData("remove service done", aData, aDataLength);
break;
}
default:
// remove temporary tlv
if (!cur->IsStable())
{
RemoveTlv(aData, aDataLength, cur);
continue;
}
break;
}
cur = cur->GetNext();
}
otDumpDebgNetData("remove done", aData, aDataLength);
}
void NetworkData::RemoveTemporaryData(uint8_t *aData, uint8_t &aDataLength, PrefixTlv &aPrefix)
{
NetworkDataTlv *cur = aPrefix.GetSubTlvs();
while (cur < aPrefix.GetNext())
{
if (cur->IsStable())
{
switch (cur->GetType())
{
case NetworkDataTlv::kTypeBorderRouter:
{
BorderRouterTlv *borderRouter = static_cast<BorderRouterTlv *>(cur);
ContextTlv * context = FindContext(aPrefix);
// Replace p_border_router_16
for (BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry();
entry = entry->GetNext())
{
if ((entry->IsDhcp() || entry->IsConfigure()) && (context != NULL))
{
entry->SetRloc(0xfc00 | context->GetContextId());
}
else
{
entry->SetRloc(0xfffe);
}
}
break;
}
case NetworkDataTlv::kTypeHasRoute:
{
HasRouteTlv *hasRoute = static_cast<HasRouteTlv *>(cur);
// Replace r_border_router_16
for (HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
entry = entry->GetNext())
{
entry->SetRloc(0xfffe);
}
break;
}
default:
break;
}
// keep stable tlv
cur = cur->GetNext();
}
else
{
// remove temporary tlv
uint8_t subTlvSize = cur->GetSize();
RemoveTlv(aData, aDataLength, cur);
aPrefix.SetSubTlvsLength(aPrefix.GetSubTlvsLength() - subTlvSize);
}
}
}
void NetworkData::RemoveTemporaryData(uint8_t *aData, uint8_t &aDataLength, ServiceTlv &aService)
{
NetworkDataTlv *cur = aService.GetSubTlvs();
while (cur < aService.GetNext())
{
if (cur->IsStable())
{
switch (cur->GetType())
{
case NetworkDataTlv::kTypeServer:
{
ServerTlv *server = static_cast<ServerTlv *>(cur);
server->SetServer16(Mle::Mle::ServiceAlocFromId(aService.GetServiceId()));
break;
}
default:
break;
}
// keep stable tlv
cur = cur->GetNext();
}
else
{
// remove temporary tlv
uint8_t subTlvSize = cur->GetSize();
RemoveTlv(aData, aDataLength, cur);
aService.SetSubTlvsLength(aService.GetSubTlvsLength() - subTlvSize);
}
}
}
const BorderRouterTlv *NetworkData::FindBorderRouter(const PrefixTlv &aPrefix)
{
return FindTlv<BorderRouterTlv>(aPrefix.GetSubTlvs(), aPrefix.GetNext());
}
const BorderRouterTlv *NetworkData::FindBorderRouter(const PrefixTlv &aPrefix, bool aStable)
{
return FindTlv<BorderRouterTlv>(aPrefix.GetSubTlvs(), aPrefix.GetNext(), aStable);
}
const HasRouteTlv *NetworkData::FindHasRoute(const PrefixTlv &aPrefix)
{
return FindTlv<HasRouteTlv>(aPrefix.GetSubTlvs(), aPrefix.GetNext());
}
const HasRouteTlv *NetworkData::FindHasRoute(const PrefixTlv &aPrefix, bool aStable)
{
return FindTlv<HasRouteTlv>(aPrefix.GetSubTlvs(), aPrefix.GetNext(), aStable);
}
const ContextTlv *NetworkData::FindContext(const PrefixTlv &aPrefix)
{
return FindTlv<ContextTlv>(aPrefix.GetSubTlvs(), aPrefix.GetNext());
}
const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
{
return FindPrefix(aPrefix, aPrefixLength, mTlvs, mLength);
}
const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix,
uint8_t aPrefixLength,
const uint8_t *aTlvs,
uint8_t aTlvsLength)
{
const NetworkDataTlv *start = reinterpret_cast<const NetworkDataTlv *>(aTlvs);
const NetworkDataTlv *end = reinterpret_cast<const NetworkDataTlv *>(aTlvs + aTlvsLength);
const PrefixTlv * prefixTlv;
while (start < end)
{
prefixTlv = FindTlv<PrefixTlv>(start, end);
VerifyOrExit(prefixTlv != NULL);
if (prefixTlv->GetPrefixLength() == aPrefixLength &&
PrefixMatch(prefixTlv->GetPrefix(), aPrefix, aPrefixLength) >= aPrefixLength)
{
ExitNow();
}
start = prefixTlv->GetNext();
}
prefixTlv = NULL;
exit:
return prefixTlv;
}
int8_t NetworkData::PrefixMatch(const uint8_t *a, const uint8_t *b, uint8_t aLength)
{
uint8_t matchedLength;
// Note that he `Ip6::Address::PrefixMatch` expects the prefix
// length to be in bytes unit.
matchedLength = Ip6::Address::PrefixMatch(a, b, BitVectorBytes(aLength));
return (matchedLength >= aLength) ? static_cast<int8_t>(matchedLength) : -1;
}
const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength) const
{
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, mTlvs, mLength);
}
const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength,
const uint8_t *aTlvs,
uint8_t aTlvsLength)
{
const NetworkDataTlv *start = reinterpret_cast<const NetworkDataTlv *>(aTlvs);
const NetworkDataTlv *end = reinterpret_cast<const NetworkDataTlv *>(aTlvs + aTlvsLength);
const ServiceTlv * serviceTlv;
while (start < end)
{
serviceTlv = FindTlv<ServiceTlv>(start, end);
VerifyOrExit(serviceTlv != NULL);
if ((serviceTlv->GetEnterpriseNumber() == aEnterpriseNumber) &&
(serviceTlv->GetServiceDataLength() == aServiceDataLength) &&
(memcmp(serviceTlv->GetServiceData(), aServiceData, aServiceDataLength) == 0))
{
ExitNow();
}
start = serviceTlv->GetNext();
}
serviceTlv = NULL;
exit:
return serviceTlv;
}
NetworkDataTlv *NetworkData::AppendTlv(uint16_t aTlvSize)
{
NetworkDataTlv *tlv;
VerifyOrExit(CanInsert(aTlvSize), tlv = NULL);
tlv = GetTlvsEnd();
mLength += static_cast<uint8_t>(aTlvSize);
exit:
return tlv;
}
void NetworkData::Insert(void *aStart, uint8_t aLength)
{
uint8_t *start = reinterpret_cast<uint8_t *>(aStart);
OT_ASSERT(CanInsert(aLength) && mTlvs <= start && start <= mTlvs + mLength);
memmove(start + aLength, start, mLength - static_cast<size_t>(start - mTlvs));
mLength += aLength;
}
void NetworkData::Remove(uint8_t *aData, uint8_t &aDataLength, uint8_t *aRemoveStart, uint8_t aRemoveLength)
{
uint8_t *dataEnd = aData + aDataLength;
uint8_t *removeEnd = aRemoveStart + aRemoveLength;
OT_ASSERT((aRemoveLength <= aDataLength) && (aData <= aRemoveStart) && (removeEnd <= dataEnd));
memmove(aRemoveStart, removeEnd, static_cast<uint8_t>(dataEnd - removeEnd));
aDataLength -= aRemoveLength;
}
void NetworkData::RemoveTlv(uint8_t *aData, uint8_t &aDataLength, NetworkDataTlv *aTlv)
{
Remove(aData, aDataLength, reinterpret_cast<uint8_t *>(aTlv), aTlv->GetSize());
}
void NetworkData::Remove(void *aRemoveStart, uint8_t aRemoveLength)
{
NetworkData::Remove(mTlvs, mLength, reinterpret_cast<uint8_t *>(aRemoveStart), aRemoveLength);
}
void NetworkData::RemoveTlv(NetworkDataTlv *aTlv)
{
NetworkData::RemoveTlv(mTlvs, mLength, aTlv);
}
otError NetworkData::SendServerDataNotification(uint16_t aRloc16, Coap::ResponseHandler aHandler, void *aContext)
{
otError error = OT_ERROR_NONE;
Coap::Message * message = NULL;
Ip6::MessageInfo messageInfo;
VerifyOrExit((message = Get<Coap::Coap>().NewMessage()) != NULL, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error = message->Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST, OT_URI_PATH_SERVER_DATA));
SuccessOrExit(error = message->SetPayloadMarker());
if (mType == kTypeLocal)
{
ThreadTlv tlv;
tlv.SetType(ThreadTlv::kThreadNetworkData);
tlv.SetLength(mLength);
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
SuccessOrExit(error = message->Append(mTlvs, mLength));
}
if (aRloc16 != Mac::kShortAddrInvalid)
{
SuccessOrExit(error = Tlv::AppendUint16Tlv(*message, ThreadTlv::kRloc16, aRloc16));
}
Get<Mle::MleRouter>().GetLeaderAloc(messageInfo.GetPeerAddr());
messageInfo.SetSockAddr(Get<Mle::MleRouter>().GetMeshLocal16());
messageInfo.SetPeerPort(kCoapUdpPort);
SuccessOrExit(error = Get<Coap::Coap>().SendMessage(*message, messageInfo, aHandler, aContext));
otLogInfoNetData("Sent server data notification");
exit:
if (error != OT_ERROR_NONE && message != NULL)
{
message->Free();
}
return error;
}
otError NetworkData::GetNextServer(Iterator &aIterator, uint16_t &aRloc16) const
{
otError error;
OnMeshPrefixConfig prefixConfig;
ExternalRouteConfig routeConfig;
ServiceConfig serviceConfig;
Config config;
config.mOnMeshPrefix = &prefixConfig;
config.mExternalRoute = &routeConfig;
config.mService = &serviceConfig;
SuccessOrExit(error = Iterate(aIterator, Mac::kShortAddrBroadcast, config));
if (config.mOnMeshPrefix != NULL)
{
aRloc16 = config.mOnMeshPrefix->mRloc16;
}
else if (config.mExternalRoute != NULL)
{
aRloc16 = config.mExternalRoute->mRloc16;
}
else if (config.mService != NULL)
{
aRloc16 = config.mService->mServerConfig.mRloc16;
}
else
{
OT_ASSERT(false);
}
exit:
return error;
}
} // namespace NetworkData
} // namespace ot