Skip to content

Commit

Permalink
[netdata] simplify and update HandleTmf<kUriCommissionerSet>() (ope…
Browse files Browse the repository at this point in the history
…nthread#9550)

This commit updates `HandleTmf<kUriCommissionerSet>()`, which is used
to set the Commissioning Dataset. The following changes have been made:
- `Tlv::Find<TlvType>()` methods are used to find and parse TLVs in the
  received request message.
- The existing code required the dataset to contain either Joiner UDP
  or Steering Data TLVs. This check has been removed, making the
  implementation aligned with the Thread specification. This permits a
  commissioner to disallow MeshCoP Joining by not including Steering
  Data.
- A new flavor of `SetCommisioningData()` is added, which reads the
  TLVs directly from a given `aMessage`. This method is now used
  when processing `kUriCommissionerSet` to avoid using temporary
  local buffers to read and copy the TLVs.
- `SetCommisioningData()` and its related methods have been moved to
  `network_data_leader_ftd` since they are limited to and used on
  FTD devices acting as leader.
- A new private `UpdateCommissioningData()` method has been added.
  This method first checks whether or not we can add a Commissioning
  Data TLV with a given length into Network Data, before removing
  the current TLV. This is used as a common method when Commissioning
  Data is set from a message or from a given data buffer.
  • Loading branch information
abtink authored Oct 20, 2023
1 parent c8aeeef commit 837c7fd
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 132 deletions.
36 changes: 0 additions & 36 deletions src/core/thread/network_data_leader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,31 +428,6 @@ Error LeaderBase::SetNetworkData(uint8_t aVersion,
return error;
}

Error LeaderBase::SetCommissioningData(const void *aValue, uint8_t aValueLength)
{
Error error = kErrorNone;
CommissioningDataTlv *commissioningDataTlv;

RemoveCommissioningData();

if (aValueLength > 0)
{
VerifyOrExit(aValueLength <= kMaxSize - sizeof(CommissioningDataTlv), error = kErrorNoBufs);
commissioningDataTlv = As<CommissioningDataTlv>(AppendTlv(sizeof(CommissioningDataTlv) + aValueLength));
VerifyOrExit(commissioningDataTlv != nullptr, error = kErrorNoBufs);

commissioningDataTlv->Init();
commissioningDataTlv->SetLength(aValueLength);
memcpy(commissioningDataTlv->GetValue(), aValue, aValueLength);
}

mVersion++;
SignalNetDataChanged();

exit:
return error;
}

const CommissioningDataTlv *LeaderBase::FindCommissioningData(void) const
{
return NetworkDataTlv::Find<CommissioningDataTlv>(GetTlvsStart(), GetTlvsEnd());
Expand Down Expand Up @@ -520,17 +495,6 @@ bool LeaderBase::IsJoiningAllowed(void) const
return isAllowed;
}

void LeaderBase::RemoveCommissioningData(void)
{
CommissioningDataTlv *tlv = FindCommissioningData();

VerifyOrExit(tlv != nullptr);
RemoveTlv(tlv);

exit:
return;
}

Error LeaderBase::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const
{
Error error = kErrorNone;
Expand Down
14 changes: 0 additions & 14 deletions src/core/thread/network_data_leader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,6 @@ class LeaderBase : public MutableNetworkData
*/
bool IsJoiningAllowed(void) const;

/**
* Adds Commissioning Data to the Thread Network Data.
*
* @param[in] aValue A pointer to the Commissioning Data value.
* @param[in] aValueLength The length of @p aValue.
*
* @retval kErrorNone Successfully added the Commissioning Data.
* @retval kErrorNoBufs Insufficient space to add the Commissioning Data.
*
*/
Error SetCommissioningData(const void *aValue, uint8_t aValueLength);

/**
* Checks if the steering data includes a Joiner.
*
Expand Down Expand Up @@ -339,8 +327,6 @@ class LeaderBase : public MutableNetworkData

const PrefixTlv *FindNextMatchingPrefixTlv(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const;

void RemoveCommissioningData(void);

template <typename EntryType> int CompareRouteEntries(const EntryType &aFirst, const EntryType &aSecond) const;
int CompareRouteEntries(int8_t aFirstPreference,
uint16_t aFirstRloc,
Expand Down
172 changes: 90 additions & 82 deletions src/core/thread/network_data_leader_ftd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,96 +186,37 @@ template <> void Leader::HandleTmf<kUriServerData>(Coap::Message &aMessage, cons

template <> void Leader::HandleTmf<kUriCommissionerSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
uint16_t offset = aMessage.GetOffset();
uint16_t length = aMessage.GetLength() - aMessage.GetOffset();
uint8_t tlvs[NetworkData::kMaxSize];
MeshCoP::StateTlv::State state = MeshCoP::StateTlv::kReject;
bool hasSessionId = false;
bool hasValidTlv = false;
uint16_t sessionId = 0;
CommissioningDataTlv *commDataTlv;

MeshCoP::Tlv *cur;
MeshCoP::Tlv *end;
MeshCoP::StateTlv::State state = MeshCoP::StateTlv::kReject;
uint16_t borderAgentRloc;
uint16_t sessionId;
uint16_t localSessionId;

VerifyOrExit(Get<Mle::Mle>().IsLeader() && !mWaitingForNetDataSync);

VerifyOrExit(length <= sizeof(tlvs));
// Validate that there is no Border Agent Locator TLV. This also
// validates that all included TLVs are properly formatted.

aMessage.ReadBytes(offset, tlvs, length);
VerifyOrExit(Tlv::Find<MeshCoP::BorderAgentLocatorTlv>(aMessage, borderAgentRloc) == kErrorNotFound);

// Session Id and Border Router Locator MUST NOT be set, but accept including unexpected or
// unknown TLV as long as there is at least one valid TLV.
cur = reinterpret_cast<MeshCoP::Tlv *>(tlvs);
end = reinterpret_cast<MeshCoP::Tlv *>(tlvs + length);
SuccessOrExit(Tlv::Find<MeshCoP::CommissionerSessionIdTlv>(aMessage, sessionId));

while (cur < end)
if (FindCommissioningSessionId(localSessionId) == kErrorNone)
{
MeshCoP::Tlv::Type type;

VerifyOrExit(((cur + 1) <= end) && !cur->IsExtended() && (cur->GetNext() <= end));

type = cur->GetType();

if (type == MeshCoP::Tlv::kJoinerUdpPort || type == MeshCoP::Tlv::kSteeringData)
{
hasValidTlv = true;
}
else if (type == MeshCoP::Tlv::kBorderAgentLocator)
{
ExitNow();
}
else if (type == MeshCoP::Tlv::kCommissionerSessionId)
{
MeshCoP::CommissionerSessionIdTlv *tlv = As<MeshCoP::CommissionerSessionIdTlv>(cur);

VerifyOrExit(tlv->IsValid());
sessionId = tlv->GetCommissionerSessionId();
hasSessionId = true;
}
else
{
// do nothing for unexpected or unknown TLV
}

cur = cur->GetNext();
VerifyOrExit(sessionId == localSessionId);
}

// verify whether or not commissioner session id TLV is included
VerifyOrExit(hasSessionId);

// verify whether or not MGMT_COMM_SET.req includes at least one valid TLV
VerifyOrExit(hasValidTlv);
// Add the Border Agent RLOC TLV from Network Data.

// Find Commissioning Data TLV
commDataTlv = FindCommissioningData();

if (commDataTlv != nullptr)
if (FindBorderAgentRloc(borderAgentRloc) == kErrorNone)
{
// Iterate over MeshCoP TLVs and extract desired data
for (cur = reinterpret_cast<MeshCoP::Tlv *>(commDataTlv->GetValue());
cur < reinterpret_cast<MeshCoP::Tlv *>(commDataTlv->GetValue() + commDataTlv->GetLength());
cur = cur->GetNext())
{
if (cur->GetType() == MeshCoP::Tlv::kCommissionerSessionId)
{
VerifyOrExit(sessionId == As<MeshCoP::CommissionerSessionIdTlv>(cur)->GetCommissionerSessionId());
}
else if (cur->GetType() == MeshCoP::Tlv::kBorderAgentLocator)
{
VerifyOrExit(length + cur->GetSize() <= sizeof(tlvs));
memcpy(tlvs + length, reinterpret_cast<uint8_t *>(cur), cur->GetSize());
length += cur->GetSize();
}
}
SuccessOrExit(Tlv::Append<MeshCoP::BorderAgentLocatorTlv>(aMessage, borderAgentRloc));
}

IgnoreError(SetCommissioningData(tlvs, static_cast<uint8_t>(length)));
SuccessOrExit(SetCommissioningData(aMessage));

state = MeshCoP::StateTlv::kAccept;

exit:

if (Get<Mle::MleRouter>().IsLeader())
{
SendCommissioningSetResponse(aMessage, aMessageInfo, state);
Expand Down Expand Up @@ -337,20 +278,18 @@ void Leader::SendCommissioningSetResponse(const Coap::Message &aRequest,
const Ip6::MessageInfo &aMessageInfo,
MeshCoP::StateTlv::State aState)
{
Error error = kErrorNone;
Coap::Message *message;
Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);

message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
VerifyOrExit(message != nullptr);
SuccessOrExit(Tlv::Append<MeshCoP::StateTlv>(*message, aState));

SuccessOrExit(error = Tlv::Append<MeshCoP::StateTlv>(*message, aState));
SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
message = nullptr; // `SendMessage` takes ownership on success

SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));

LogInfo("sent %s response", UriToString<kUriCommissionerSet>());
LogInfo("Sent %s response", UriToString<kUriCommissionerSet>());

exit:
FreeMessageOnError(message, error);
FreeMessage(message);
}

bool Leader::RlocMatch(uint16_t aFirstRloc16, uint16_t aSecondRloc16, MatchMode aMatchMode)
Expand Down Expand Up @@ -1362,6 +1301,75 @@ void Leader::HandleNetworkDataRestoredAfterReset(void)
}
}

Error Leader::UpdateCommissioningData(uint16_t aDataLength, CommissioningDataTlv *&aDataTlv)
{
// First determine whether or not we can add Commissioning Data
// TLV with the given `aDataLength`, taking into account that we
// would remove the current Commissioning Data TLV. Then remove
// the current TLV and append a new TLV with proper size which is
// returned in `aDataTlv`.

Error error = kErrorNone;
CommissioningDataTlv *dataTlv = FindCommissioningData();
uint16_t insertLength;

if (dataTlv != nullptr)
{
insertLength = (aDataLength <= dataTlv->GetLength()) ? 0 : aDataLength - dataTlv->GetLength();
}
else
{
insertLength = sizeof(CommissioningDataTlv) + aDataLength;
}

VerifyOrExit(CanInsert(insertLength), error = kErrorNoBufs);

if (dataTlv != nullptr)
{
RemoveTlv(dataTlv);
}

aDataTlv = As<CommissioningDataTlv>(AppendTlv(sizeof(CommissioningDataTlv) + aDataLength));

OT_ASSERT(aDataTlv != nullptr);

aDataTlv->Init();
aDataTlv->SetLength(static_cast<uint8_t>(aDataLength));

// The caller would fill the `aDataTlv` value.

mVersion++;
SignalNetDataChanged();

exit:
return error;
}

Error Leader::SetCommissioningData(const void *aData, uint8_t aDataLength)
{
Error error = kErrorNone;
CommissioningDataTlv *dataTlv;

SuccessOrExit(error = UpdateCommissioningData(aDataLength, dataTlv));
memcpy(dataTlv->GetValue(), aData, aDataLength);

exit:
return error;
}

Error Leader::SetCommissioningData(const Message &aMessage)
{
Error error = kErrorNone;
uint16_t dataLength = aMessage.GetLength() - aMessage.GetOffset();
CommissioningDataTlv *dataTlv;

SuccessOrExit(error = UpdateCommissioningData(dataLength, dataTlv));
aMessage.ReadBytes(aMessage.GetOffset(), dataTlv->GetValue(), dataLength);

exit:
return error;
}

void Leader::HandleTimer(void)
{
if (mWaitingForNetDataSync)
Expand Down
15 changes: 15 additions & 0 deletions src/core/thread/network_data_leader_ftd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ class Leader : public LeaderBase, private NonCopyable
*/
void RemoveBorderRouter(uint16_t aRloc16, MatchMode aMatchMode);

/**
* Updates Commissioning Data in Network Data.
*
* @param[in] aData A pointer to the Commissioning Data.
* @param[in] aDataLength The length of @p aData.
*
* @retval kErrorNone Successfully updated the Commissioning Data.
* @retval kErrorNoBufs Insufficient space to add the Commissioning Data.
*
*/
Error SetCommissioningData(const void *aData, uint8_t aDataLength);

/**
* Synchronizes internal 6LoWPAN Context ID Set with recently obtained Thread Network Data.
*
Expand Down Expand Up @@ -329,6 +341,9 @@ class Leader : public LeaderBase, private NonCopyable
UpdateStatus UpdateService(ServiceTlv &aService);
UpdateStatus UpdateTlv(NetworkDataTlv &aTlv, const NetworkDataTlv *aSubTlvs);

Error UpdateCommissioningData(uint16_t aDataLength, CommissioningDataTlv *&aDataTlv);
Error SetCommissioningData(const Message &aMessage);

void SendCommissioningSetResponse(const Coap::Message &aRequest,
const Ip6::MessageInfo &aMessageInfo,
MeshCoP::StateTlv::State aState);
Expand Down

0 comments on commit 837c7fd

Please sign in to comment.