Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TBRM: Add missing PendingDatasetTimestamp attribute and CASE session check #34768

Merged
merged 8 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Status ServerInstance::HandleGetDatasetRequest(bool isOverCASESession, Delegate:
return Status::Success;
}

Status ServerInstance::HandleSetActiveDatasetRequest(CommandHandler * commandHandler,
Status ServerInstance::HandleSetActiveDatasetRequest(bool isOverCASESession, CommandHandler * commandHandler,
const Commands::SetActiveDatasetRequest::DecodableType & req)
{
// The SetActiveDatasetRequest command SHALL be FailSafeArmed. Upon receiving this command, the Thread BR will set its
Expand All @@ -80,6 +80,7 @@ Status ServerInstance::HandleSetActiveDatasetRequest(CommandHandler * commandHan
// reverted. If the FailSafe timer expires before the Thread BR responds, the Thread BR will respond with a timeout status and
// the active dataset should also be reverted.
VerifyOrDie(mDelegate);
VerifyOrReturnValue(isOverCASESession, Status::UnsupportedAccess);
VerifyOrReturnValue(mFailsafeContext.IsFailSafeArmed(commandHandler->GetAccessingFabricIndex()), Status::FailsafeRequired);

Thread::OperationalDataset activeDataset;
Expand Down Expand Up @@ -109,9 +110,11 @@ Status ServerInstance::HandleSetActiveDatasetRequest(CommandHandler * commandHan
return Status::Success;
}

Status ServerInstance::HandleSetPendingDatasetRequest(const Commands::SetPendingDatasetRequest::DecodableType & req)
Status ServerInstance::HandleSetPendingDatasetRequest(bool isOverCASESession,
const Commands::SetPendingDatasetRequest::DecodableType & req)
{
VerifyOrDie(mDelegate);
VerifyOrReturnValue(isOverCASESession, Status::UnsupportedAccess);
if (!mDelegate->GetPanChangeSupported())
{
return Status::UnsupportedCommand;
Expand Down Expand Up @@ -157,7 +160,7 @@ void ServerInstance::InvokeCommand(HandlerContext & ctxt)
case Commands::SetActiveDatasetRequest::Id:
HandleCommand<Commands::SetActiveDatasetRequest::DecodableType>(ctxt, [this](HandlerContext & ctx, const auto & req) {
mPath = ctx.mRequestPath;
Status status = HandleSetActiveDatasetRequest(&ctx.mCommandHandler, req);
Status status = HandleSetActiveDatasetRequest(IsCommandOverCASESession(ctx), &ctx.mCommandHandler, req);
if (status != Status::Success)
{
// If status is not Success, we should immediately report the status. Otherwise the async work will report the
Expand All @@ -168,7 +171,8 @@ void ServerInstance::InvokeCommand(HandlerContext & ctxt)
break;
case Commands::SetPendingDatasetRequest::Id:
HandleCommand<Commands::SetPendingDatasetRequest::DecodableType>(ctxt, [this](HandlerContext & ctx, const auto & req) {
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, HandleSetPendingDatasetRequest(req));
Status status = HandleSetPendingDatasetRequest(IsCommandOverCASESession(ctx), req);
wqx6 marked this conversation as resolved.
Show resolved Hide resolved
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status);
});
break;
default:
Expand Down Expand Up @@ -211,6 +215,18 @@ Optional<uint64_t> ServerInstance::ReadActiveDatasetTimestamp()
return NullOptional;
}

Optional<uint64_t> ServerInstance::ReadPendingDatasetTimestamp()
{
uint64_t pendingDatasetTimestampValue = 0;
Thread::OperationalDataset pendingDataset;
if ((mDelegate->GetDataset(pendingDataset, Delegate::DatasetType::kPending) == CHIP_NO_ERROR) &&
(pendingDataset.GetActiveTimestamp(pendingDatasetTimestampValue) == CHIP_NO_ERROR))
{
return MakeOptional(pendingDatasetTimestampValue);
}
return NullOptional;
}

CHIP_ERROR ServerInstance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
if (aPath.mClusterId != ThreadBorderRouterManagement::Id)
Expand Down Expand Up @@ -264,6 +280,12 @@ CHIP_ERROR ServerInstance::Read(const ConcreteReadAttributePath & aPath, Attribu
: aEncoder.EncodeNull();
break;
}
case Attributes::PendingDatasetTimestamp::Id: {
Optional<uint64_t> pendingDatasetTimestamp = ReadPendingDatasetTimestamp();
status = pendingDatasetTimestamp.HasValue() ? aEncoder.Encode(DataModel::MakeNullable(pendingDatasetTimestamp.Value()))
wqx6 marked this conversation as resolved.
Show resolved Hide resolved
: aEncoder.EncodeNull();
break;
}
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ class ServerInstance : public CommandHandlerInterface,
{
return HandleGetDatasetRequest(isOverCASESession, Delegate::DatasetType::kPending, dataset);
}
Status HandleSetActiveDatasetRequest(CommandHandler * commandHandler,
Status HandleSetActiveDatasetRequest(bool isOverCASESession, CommandHandler * commandHandler,
const Commands::SetActiveDatasetRequest::DecodableType & req);
Status HandleSetPendingDatasetRequest(const Commands::SetPendingDatasetRequest::DecodableType & req);
Status HandleSetPendingDatasetRequest(bool isOverCASESession, const Commands::SetPendingDatasetRequest::DecodableType & req);
Status HandleGetDatasetRequest(bool isOverCASESession, Delegate::DatasetType type, Thread::OperationalDataset & dataset);

// Attribute Read handlers
void ReadFeatureMap(BitFlags<Feature> & feature);
Optional<uint64_t> ReadActiveDatasetTimestamp();
Optional<uint64_t> ReadPendingDatasetTimestamp();
wqx6 marked this conversation as resolved.
Show resolved Hide resolved
CHIP_ERROR ReadBorderRouterName(MutableCharSpan & borderRouterName);
CHIP_ERROR ReadBorderAgentID(MutableByteSpan & borderAgentId);

Expand Down
16 changes: 8 additions & 8 deletions src/app/tests/TestThreadBorderRouterManagementCluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,14 @@ TEST_F_FROM_FIXTURE(TestThreadBorderRouterManagementCluster, TestCommandHandle)
EXPECT_FALSE(activeDatasetTimestamp.HasValue());
req1.activeDataset = ByteSpan(invalidDataset);
// SetActiveDatasetRequest is FailsafeRequired.
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(&sTestCommandHandler, req1), Status::FailsafeRequired);
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(true, &sTestCommandHandler, req1), Status::FailsafeRequired);
EXPECT_EQ(sTestFailsafeContext.ArmFailSafe(kTestAccessingFabricIndex, System::Clock::Seconds16(1)), CHIP_NO_ERROR);
// SetActiveDatasetRequest should return InvalidCommand when dataset is invalid.
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(&sTestCommandHandler, req1), Status::InvalidCommand);
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(true, &sTestCommandHandler, req1), Status::InvalidCommand);
req1.activeDataset = ByteSpan(validDataset);
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(&sTestCommandHandler, req1), Status::Success);
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(true, &sTestCommandHandler, req1), Status::Success);
// When the Server is handling a SetActiveDatasetRequest command, it should return Busy after receiving another one.
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(&sTestCommandHandler, req1), Status::Busy);
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(true, &sTestCommandHandler, req1), Status::Busy);
EXPECT_FALSE(sTestDelegate.mInterfaceEnabled);
EXPECT_EQ(sTestDelegate.mSetActiveDatasetCommandSequenceNum, static_cast<unsigned int>(1));
// Activate the dataset.
Expand All @@ -311,21 +311,21 @@ TEST_F_FROM_FIXTURE(TestThreadBorderRouterManagementCluster, TestCommandHandle)
EXPECT_TRUE(activeDatasetTimestamp.HasValue());
EXPECT_EQ(sTestFailsafeContext.ArmFailSafe(kTestAccessingFabricIndex, System::Clock::Seconds16(1)), CHIP_NO_ERROR);
// When ActiveDatasetTimestamp is not null, the set active dataset request should return InvalidInState.
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(&sTestCommandHandler, req1), Status::InvalidInState);
EXPECT_EQ(sTestSeverInstance.HandleSetActiveDatasetRequest(true, &sTestCommandHandler, req1), Status::InvalidInState);
sTestFailsafeContext.DisarmFailSafe();
// Test SetPendingDatasetRequest command
Commands::SetPendingDatasetRequest::DecodableType req2;
sTestDelegate.mPanChangeSupported = false;
req2.pendingDataset = ByteSpan(validDataset);
// SetPendingDatasetRequest is supported when PANChange feature is enabled.
EXPECT_EQ(sTestSeverInstance.HandleSetPendingDatasetRequest(req2), Status::UnsupportedCommand);
EXPECT_EQ(sTestSeverInstance.HandleSetPendingDatasetRequest(true, req2), Status::UnsupportedCommand);
sTestDelegate.mPanChangeSupported = true;
req2.pendingDataset = ByteSpan(invalidDataset);
// SetPendingDatasetRequest should return InvalidCommand when dataset is invalid.
EXPECT_EQ(sTestSeverInstance.HandleSetPendingDatasetRequest(req2), Status::InvalidCommand);
EXPECT_EQ(sTestSeverInstance.HandleSetPendingDatasetRequest(true, req2), Status::InvalidCommand);
req2.pendingDataset = ByteSpan(validDataset);
// Success SetPendingDatasetRequest
EXPECT_EQ(sTestSeverInstance.HandleSetPendingDatasetRequest(req2), Status::Success);
EXPECT_EQ(sTestSeverInstance.HandleSetPendingDatasetRequest(true, req2), Status::Success);
EXPECT_EQ(sTestSeverInstance.HandleGetDatasetRequest(true, DatasetType::kPending, dataset), Status::Success);
EXPECT_TRUE(dataset.AsByteSpan().data_equal(ByteSpan(validDataset)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ limitations under the License.

<attribute side="server" code="0x0004" apiMaturity="provisional" define="ACTIVE_DATASET_TIMESTAMP" type="int64u" isNullable="true">ActiveDatasetTimestamp</attribute>

<attribute side="server" code="0x0005" apiMaturity="provisional" define="PENDING_DATASET_TIMESTAMP" type="int64u" isNullable="true">PendingDatasetTimestamp</attribute>

<command source="client" code="0x00" apiMaturity="provisional" name="GetActiveDatasetRequest" response="DatasetResponse" optional="false">
<description>Command to request the active operational dataset of the Thread network to which the border router is connected. This command must be sent over a valid CASE session</description>
<access op="invoke" privilege="manage"/>
Expand Down
1 change: 1 addition & 0 deletions src/app/zap-templates/zcl/zcl-with-test-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@
"ThreadVersion",
"InterfaceEnabled",
"ActiveDatasetTimestamp",
"PendingDatasetTimestamp",
"FeatureMap"
],
"Thread Network Diagnostics": [
Expand Down
1 change: 1 addition & 0 deletions src/app/zap-templates/zcl/zcl.json
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@
"ThreadVersion",
"InterfaceEnabled",
"ActiveDatasetTimestamp",
"PendingDatasetTimestamp",
"FeatureMap"
],
"Thread Network Diagnostics": [
Expand Down
1 change: 1 addition & 0 deletions src/controller/data_model/controller-clusters.matter
Original file line number Diff line number Diff line change
Expand Up @@ -8224,6 +8224,7 @@ provisional cluster ThreadBorderRouterManagement = 1106 {
provisional readonly attribute int16u threadVersion = 2;
provisional readonly attribute boolean interfaceEnabled = 3;
provisional readonly attribute nullable int64u activeDatasetTimestamp = 4;
provisional readonly attribute nullable int64u pendingDatasetTimestamp = 5;
readonly attribute command_id generatedCommandList[] = 65528;
readonly attribute command_id acceptedCommandList[] = 65529;
readonly attribute event_id eventList[] = 65530;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54642,6 +54642,7 @@ public static class ThreadBorderRouterManagementCluster extends BaseChipCluster
private static final long THREAD_VERSION_ATTRIBUTE_ID = 2L;
private static final long INTERFACE_ENABLED_ATTRIBUTE_ID = 3L;
private static final long ACTIVE_DATASET_TIMESTAMP_ATTRIBUTE_ID = 4L;
private static final long PENDING_DATASET_TIMESTAMP_ATTRIBUTE_ID = 5L;
private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L;
private static final long ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID = 65529L;
private static final long EVENT_LIST_ATTRIBUTE_ID = 65530L;
Expand Down Expand Up @@ -54763,6 +54764,10 @@ public interface ActiveDatasetTimestampAttributeCallback extends BaseAttributeCa
void onSuccess(@Nullable Long value);
}

public interface PendingDatasetTimestampAttributeCallback extends BaseAttributeCallback {
void onSuccess(@Nullable Long value);
}

public interface GeneratedCommandListAttributeCallback extends BaseAttributeCallback {
void onSuccess(List<Long> value);
}
Expand Down Expand Up @@ -54909,6 +54914,32 @@ public void onSuccess(byte[] tlv) {
}, ACTIVE_DATASET_TIMESTAMP_ATTRIBUTE_ID, minInterval, maxInterval);
}

public void readPendingDatasetTimestampAttribute(
PendingDatasetTimestampAttributeCallback callback) {
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, PENDING_DATASET_TIMESTAMP_ATTRIBUTE_ID);

readAttribute(new ReportCallbackImpl(callback, path) {
@Override
public void onSuccess(byte[] tlv) {
@Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv);
callback.onSuccess(value);
}
}, PENDING_DATASET_TIMESTAMP_ATTRIBUTE_ID, true);
}

public void subscribePendingDatasetTimestampAttribute(
PendingDatasetTimestampAttributeCallback callback, int minInterval, int maxInterval) {
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, PENDING_DATASET_TIMESTAMP_ATTRIBUTE_ID);

subscribeAttribute(new ReportCallbackImpl(callback, path) {
@Override
public void onSuccess(byte[] tlv) {
@Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv);
callback.onSuccess(value);
}
}, PENDING_DATASET_TIMESTAMP_ATTRIBUTE_ID, minInterval, maxInterval);
}

public void readGeneratedCommandListAttribute(
GeneratedCommandListAttributeCallback callback) {
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14870,6 +14870,7 @@ public enum Attribute {
ThreadVersion(2L),
InterfaceEnabled(3L),
ActiveDatasetTimestamp(4L),
PendingDatasetTimestamp(5L),
GeneratedCommandList(65528L),
AcceptedCommandList(65529L),
EventList(65530L),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18067,6 +18067,27 @@ public void onError(Exception ex) {
}
}

public static class DelegatedThreadBorderRouterManagementClusterPendingDatasetTimestampAttributeCallback implements ChipClusters.ThreadBorderRouterManagementCluster.PendingDatasetTimestampAttributeCallback, DelegatedClusterCallback {
private ClusterCommandCallback callback;
@Override
public void setCallbackDelegate(ClusterCommandCallback callback) {
this.callback = callback;
}

@Override
public void onSuccess(@Nullable Long value) {
Map<CommandResponseInfo, Object> responseValues = new LinkedHashMap<>();
CommandResponseInfo commandResponseInfo = new CommandResponseInfo("value", "Long");
responseValues.put(commandResponseInfo, value);
callback.onSuccess(responseValues);
}

@Override
public void onError(Exception ex) {
callback.onFailure(ex);
}
}

public static class DelegatedThreadBorderRouterManagementClusterGeneratedCommandListAttributeCallback implements ChipClusters.ThreadBorderRouterManagementCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback {
private ClusterCommandCallback callback;
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17140,6 +17140,17 @@ private static Map<String, InteractionInfo> readThreadBorderRouterManagementInte
readThreadBorderRouterManagementActiveDatasetTimestampCommandParams
);
result.put("readActiveDatasetTimestampAttribute", readThreadBorderRouterManagementActiveDatasetTimestampAttributeInteractionInfo);
Map<String, CommandParameterInfo> readThreadBorderRouterManagementPendingDatasetTimestampCommandParams = new LinkedHashMap<String, CommandParameterInfo>();
InteractionInfo readThreadBorderRouterManagementPendingDatasetTimestampAttributeInteractionInfo = new InteractionInfo(
(cluster, callback, commandArguments) -> {
((ChipClusters.ThreadBorderRouterManagementCluster) cluster).readPendingDatasetTimestampAttribute(
(ChipClusters.ThreadBorderRouterManagementCluster.PendingDatasetTimestampAttributeCallback) callback
);
},
() -> new ClusterInfoMapping.DelegatedThreadBorderRouterManagementClusterPendingDatasetTimestampAttributeCallback(),
readThreadBorderRouterManagementPendingDatasetTimestampCommandParams
);
result.put("readPendingDatasetTimestampAttribute", readThreadBorderRouterManagementPendingDatasetTimestampAttributeInteractionInfo);
Map<String, CommandParameterInfo> readThreadBorderRouterManagementGeneratedCommandListCommandParams = new LinkedHashMap<String, CommandParameterInfo>();
InteractionInfo readThreadBorderRouterManagementGeneratedCommandListAttributeInteractionInfo = new InteractionInfo(
(cluster, callback, commandArguments) -> {
Expand Down
Loading
Loading