From 2f74f4bcf46e5d74bc7b8f9d85d9cf0edcdabce5 Mon Sep 17 00:00:00 2001 From: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com> Date: Fri, 10 Mar 2023 09:22:17 -0800 Subject: [PATCH] Reset the wrong code retry attempts if a valid credential is presented (#25536) * Reset the wrong code retry attempts if a valid credential is presented - Provide a ResetWrongCodeEntryAttempts for apps to use to reset the wrong entry attempts - Update DL_LockUnlock.yaml to test resetting the wrong code retry attempts * Update src/app/clusters/door-lock-server/door-lock-server.cpp Co-authored-by: Boris Zbarsky * Update src/app/clusters/door-lock-server/door-lock-server.cpp Co-authored-by: Boris Zbarsky * Update src/app/clusters/door-lock-server/door-lock-server.h Co-authored-by: Boris Zbarsky * Update src/app/clusters/door-lock-server/door-lock-server.h Co-authored-by: Boris Zbarsky * Update src/app/clusters/door-lock-server/door-lock-server.cpp Co-authored-by: Boris Zbarsky * Address review comment - fix YAML to lock door before unlocking again. Restyle changes --------- Co-authored-by: Boris Zbarsky --- .../door-lock-server/door-lock-server.cpp | 28 +- .../door-lock-server/door-lock-server.h | 19 +- src/app/tests/suites/DL_LockUnlock.yaml | 112 ++++++- .../chip-tool/zap-generated/test/Commands.h | 292 ++++++++++++++---- 4 files changed, 381 insertions(+), 70 deletions(-) diff --git a/src/app/clusters/door-lock-server/door-lock-server.cpp b/src/app/clusters/door-lock-server/door-lock-server.cpp index 2b08ec9c128d63..d294803ab60e89 100644 --- a/src/app/clusters/door-lock-server/door-lock-server.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server.cpp @@ -122,6 +122,13 @@ bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLo SendLockOperationEvent(endpointId, opType, opSource, OperationErrorEnum::kUnspecified, userIndex, Nullable(), Nullable(), credentials, success); + // Reset wrong entry attempts (in case there were any incorrect credentials presented before) if lock/unlock was a success + // and a valid credential was presented. + if (success && !credentials.IsNull() && !(credentials.Value().empty())) + { + ResetWrongCodeEntryAttempts(endpointId); + } + // Schedule auto-relocking if (success && LockOperationTypeEnum::kUnlock == opType) { @@ -181,7 +188,7 @@ bool DoorLockServer::SetPrivacyModeButton(chip::EndpointId endpointId, bool isEn return SetAttribute(endpointId, Attributes::EnablePrivacyModeButton::Id, Attributes::EnablePrivacyModeButton::Set, isEnabled); } -bool DoorLockServer::TrackWrongCodeEntry(chip::EndpointId endpointId) +bool DoorLockServer::HandleWrongCodeEntry(chip::EndpointId endpointId) { auto endpointContext = getContext(endpointId); if (nullptr == endpointContext) @@ -209,6 +216,17 @@ bool DoorLockServer::TrackWrongCodeEntry(chip::EndpointId endpointId) return true; } +void DoorLockServer::ResetWrongCodeEntryAttempts(chip::EndpointId endpointId) +{ + auto endpointContext = getContext(endpointId); + if (nullptr == endpointContext) + { + ChipLogError(Zcl, "Failed to reset wrong code entry attempts. No context for endpoint %d", endpointId); + return; + } + endpointContext->wrongCodeEntryAttempts = 0; +} + bool DoorLockServer::engageLockout(chip::EndpointId endpointId) { uint8_t lockoutTimeout; @@ -3352,7 +3370,13 @@ bool DoorLockServer::HandleRemoteLockOperation(chip::app::CommandHandler * comma exit: if (!success && reason == OperationErrorEnum::kInvalidCredential) { - TrackWrongCodeEntry(endpoint); + HandleWrongCodeEntry(endpoint); + } + + // Reset the wrong code retry attempts if a valid credential is presented during lock/unlock + if (success && pinCode.HasValue()) + { + ResetWrongCodeEntryAttempts(endpoint); } // Send command response diff --git a/src/app/clusters/door-lock-server/door-lock-server.h b/src/app/clusters/door-lock-server/door-lock-server.h index 2d0fa45318890f..2fca20ddfdc628 100644 --- a/src/app/clusters/door-lock-server/door-lock-server.h +++ b/src/app/clusters/door-lock-server/door-lock-server.h @@ -121,7 +121,15 @@ class DoorLockServer bool SetOneTouchLocking(chip::EndpointId endpointId, bool isEnabled); bool SetPrivacyModeButton(chip::EndpointId endpointId, bool isEnabled); - bool TrackWrongCodeEntry(chip::EndpointId endpointId); + /** + * @brief Handles a wrong code entry attempt for the endpoint. If the number of wrong entry attempts exceeds the max limit, + * engage lockout. Otherwise increment the number of incorrect attempts by 1. This is handled automatically for + * remote operations - lock and unlock. Applications are responsible for calling it for non-remote incorrect credential + * presentation attempts. + * + * @param endpointId + */ + bool HandleWrongCodeEntry(chip::EndpointId endpointId); bool GetAutoRelockTime(chip::EndpointId endpointId, uint32_t & autoRelockTime); bool GetNumberOfUserSupported(chip::EndpointId endpointId, uint16_t & numberOfUsersSupported); @@ -183,6 +191,15 @@ class DoorLockServer bool OnFabricRemoved(chip::EndpointId endpointId, chip::FabricIndex fabricIndex); static void DoorLockOnAutoRelockCallback(chip::System::Layer *, void * callbackContext); + /** + * @brief Resets the wrong code entry attempts to 0 for the endpoint. This is done automatically when a + * remote lock operation with credentials succeeds, or when SetLockState is called with a non-empty credentials list. + * Applications that call the two-argument version of SetLockState and handle sending the relevant operation events + * themselves or via SendLockOperationEvent are responsible for calling this API when a valid credential is presented. + * + * @param endpointId + */ + void ResetWrongCodeEntryAttempts(chip::EndpointId endpointId); private: chip::FabricIndex getFabricIndex(const chip::app::CommandHandler * commandObj); diff --git a/src/app/tests/suites/DL_LockUnlock.yaml b/src/app/tests/suites/DL_LockUnlock.yaml index d9b4f4a300e4b6..7eab03dbc63e44 100644 --- a/src/app/tests/suites/DL_LockUnlock.yaml +++ b/src/app/tests/suites/DL_LockUnlock.yaml @@ -238,11 +238,11 @@ tests: arguments: value: 0 - - label: "Read the lockout timeout" - command: "readAttribute" - attribute: "UserCodeTemporaryDisableTime" - response: - value: 10 + # Test resetting wrong code entry retry attempts + # Set the retry limit to 3. Try to unlock with incorrect PIN 2 times followed by a third time + # with correct PIN code. The retry attempts should be reset to 0. Try to unock with incorrect + # PIN 2 times followed by a third time with correct PIN code. We should be able to unlock since + # the count has been reset and we are not in lockout. - label: "Set the WrongCodeEntryLimit to small value so we can test lockout" command: "writeAttribute" @@ -270,6 +270,108 @@ tests: response: error: FAILURE + - label: "Try to unlock the door with valid PIN for the third time" + command: "UnlockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "123456" + + - label: "Verify that lock state attribute value is set to Unlocked" + command: "readAttribute" + attribute: "LockState" + response: + value: 2 + + - label: "Lock the door back prior to next tests" + command: "LockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "123456" + + - label: "Verify that lock state attribute value is set to Locked" + command: "readAttribute" + attribute: "LockState" + response: + value: 1 + + - label: "Try to unlock the door with invalid PIN for the first time" + command: "UnlockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "000000" + response: + error: FAILURE + + - label: "Try to unlock the door with invalid PIN for the second time" + command: "UnlockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "000000" + response: + error: FAILURE + + - label: "Try to unlock the door with valid PIN for the third time" + command: "UnlockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "123456" + + - label: "Verify that lock state attribute value is set to Unlocked" + command: "readAttribute" + attribute: "LockState" + response: + value: 2 + + - label: "Lock the door back prior to next tests" + command: "LockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "123456" + + - label: "Verify that lock state attribute value is set to Locked" + command: "readAttribute" + attribute: "LockState" + response: + value: 1 + + - label: "Read the lockout timeout" + command: "readAttribute" + attribute: "UserCodeTemporaryDisableTime" + response: + value: 10 + + - label: "Try to unlock the door with invalid PIN for the first time" + command: "UnlockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "000000" + response: + error: FAILURE + + - label: "Try to unlock the door with invalid PIN for the second time" + command: "UnlockDoor" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "PINCode" + value: "000000" + response: + error: FAILURE + - label: "Try to unlock the door with invalid PIN for the third time" command: "UnlockDoor" timedInteractionTimeoutMs: 10000 diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index c8b5d75ba7ac0e..8e396b0c1ca79b 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -78376,7 +78376,7 @@ class DL_UsersAndCredentialsSuite : public TestCommand class DL_LockUnlockSuite : public TestCommand { public: - DL_LockUnlockSuite(CredentialIssuerCommands * credsIssuerConfig) : TestCommand("DL_LockUnlock", 41, credsIssuerConfig) + DL_LockUnlockSuite(CredentialIssuerCommands * credsIssuerConfig) : TestCommand("DL_LockUnlock", 53, credsIssuerConfig) { AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); AddArgument("cluster", &mCluster); @@ -78604,36 +78604,96 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; case 21: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 22: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); + break; + case 23: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); + break; + case 24: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 25: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { - uint8_t value; + chip::app::DataModel::Nullable value; VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); - VerifyOrReturn(CheckValue("userCodeTemporaryDisableTime", value, 10U)); + VerifyOrReturn(CheckValueNonNull("lockState", value)); + VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 2U)); } break; - case 22: + case 26: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; - case 23: + case 27: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNonNull("lockState", value)); + VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 1U)); + } + break; + case 28: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); break; - case 24: + case 29: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); break; - case 25: + case 30: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 31: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNonNull("lockState", value)); + VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 2U)); + } + break; + case 32: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 33: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNonNull("lockState", value)); + VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 1U)); + } + break; + case 34: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + uint8_t value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValue("userCodeTemporaryDisableTime", value, 10U)); + } + break; + case 35: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); break; - case 26: + case 36: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); break; - case 27: + case 37: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); + break; + case 38: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); + break; + case 39: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); shouldContinue = true; break; - case 28: + case 40: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; - case 29: + case 41: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { chip::app::DataModel::Nullable value; @@ -78642,10 +78702,10 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 2U)); } break; - case 30: + case 42: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; - case 31: + case 43: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { chip::app::Clusters::DoorLock::Commands::SetCredentialResponse::DecodableType value; @@ -78657,10 +78717,10 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("nextCredentialIndex.Value()", value.nextCredentialIndex.Value(), 4U)); } break; - case 32: + case 44: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); break; - case 33: + case 45: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { chip::app::DataModel::Nullable value; @@ -78669,10 +78729,10 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 1U)); } break; - case 34: + case 46: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; - case 35: + case 47: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { chip::app::DataModel::Nullable value; @@ -78681,10 +78741,10 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 2U)); } break; - case 36: + case 48: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_FAILURE)); break; - case 37: + case 49: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { chip::app::DataModel::Nullable value; @@ -78693,10 +78753,10 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 2U)); } break; - case 38: + case 50: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; - case 39: + case 51: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); { chip::app::DataModel::Nullable value; @@ -78705,7 +78765,7 @@ class DL_LockUnlockSuite : public TestCommand VerifyOrReturn(CheckValue("lockState.Value()", value.Value(), 1U)); } break; - case 40: + case 52: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; default: @@ -78908,20 +78968,26 @@ class DL_LockUnlockSuite : public TestCommand chip::NullOptional, chip::NullOptional); } case 21: { - LogStep(21, "Read the lockout timeout"); - return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, - DoorLock::Attributes::UserCodeTemporaryDisableTime::Id, true, chip::NullOptional); - } - case 22: { - LogStep(22, "Set the WrongCodeEntryLimit to small value so we can test lockout"); + LogStep(21, "Set the WrongCodeEntryLimit to small value so we can test lockout"); ListFreer listFreer; uint8_t value; value = 3U; return WriteAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::WrongCodeEntryLimit::Id, value, chip::NullOptional, chip::NullOptional); } + case 22: { + LogStep(22, "Try to unlock the door with invalid PIN for the first time"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("000000garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } case 23: { - LogStep(23, "Try to unlock the door with invalid PIN for the first time"); + LogStep(23, "Try to unlock the door with invalid PIN for the second time"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); @@ -78932,18 +78998,39 @@ class DL_LockUnlockSuite : public TestCommand ); } case 24: { - LogStep(24, "Try to unlock the door with invalid PIN for the second time"); + LogStep(24, "Try to unlock the door with valid PIN for the third time"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); - value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("000000garbage: not in length on purpose"), 6); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("123456garbage: not in length on purpose"), 6); return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, chip::Optional(10000), chip::NullOptional ); } case 25: { - LogStep(25, "Try to unlock the door with invalid PIN for the third time"); + LogStep(25, "Verify that lock state attribute value is set to Unlocked"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, + chip::NullOptional); + } + case 26: { + LogStep(26, "Lock the door back prior to next tests"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::LockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("123456garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::LockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 27: { + LogStep(27, "Verify that lock state attribute value is set to Locked"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, + chip::NullOptional); + } + case 28: { + LogStep(28, "Try to unlock the door with invalid PIN for the first time"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); @@ -78953,8 +79040,19 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 26: { - LogStep(26, "Try to unlock the door with valid PIN and make sure it fails due to lockout"); + case 29: { + LogStep(29, "Try to unlock the door with invalid PIN for the second time"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("000000garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 30: { + LogStep(30, "Try to unlock the door with valid PIN for the third time"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); @@ -78964,15 +79062,85 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 27: { - LogStep(27, "Wait for the lockout to end"); + case 31: { + LogStep(31, "Verify that lock state attribute value is set to Unlocked"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, + chip::NullOptional); + } + case 32: { + LogStep(32, "Lock the door back prior to next tests"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::LockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("123456garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::LockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 33: { + LogStep(33, "Verify that lock state attribute value is set to Locked"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, + chip::NullOptional); + } + case 34: { + LogStep(34, "Read the lockout timeout"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, + DoorLock::Attributes::UserCodeTemporaryDisableTime::Id, true, chip::NullOptional); + } + case 35: { + LogStep(35, "Try to unlock the door with invalid PIN for the first time"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("000000garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 36: { + LogStep(36, "Try to unlock the door with invalid PIN for the second time"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("000000garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 37: { + LogStep(37, "Try to unlock the door with invalid PIN for the third time"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("000000garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 38: { + LogStep(38, "Try to unlock the door with valid PIN and make sure it fails due to lockout"); + ListFreer listFreer; + chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; + value.PINCode.Emplace(); + value.PINCode.Value() = chip::ByteSpan(chip::Uint8::from_const_char("123456garbage: not in length on purpose"), 6); + return SendCommand(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Commands::UnlockDoor::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 39: { + LogStep(39, "Wait for the lockout to end"); ListFreer listFreer; chip::app::Clusters::DelayCommands::Commands::WaitForMs::Type value; value.ms = 10000UL; return WaitForMs(kIdentityAlpha, value); } - case 28: { - LogStep(28, "Try to unlock the door with valid PIN and make sure it succeeds"); + case 40: { + LogStep(40, "Try to unlock the door with valid PIN and make sure it succeeds"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); @@ -78982,13 +79150,13 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 29: { - LogStep(29, "Verify that lock state attribute value is set to Unlocked"); + case 41: { + LogStep(41, "Verify that lock state attribute value is set to Unlocked"); return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, chip::NullOptional); } - case 30: { - LogStep(30, "Lock the door back prior to next tests"); + case 42: { + LogStep(42, "Lock the door back prior to next tests"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::LockDoor::Type value; value.PINCode.Emplace(); @@ -78998,8 +79166,8 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 31: { - LogStep(31, "Create a disabled user and credential"); + case 43: { + LogStep(43, "Create a disabled user and credential"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::SetCredential::Type value; value.operationType = static_cast(0); @@ -79017,8 +79185,8 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 32: { - LogStep(32, "Try to unlock the door with disabled user PIN"); + case 44: { + LogStep(44, "Try to unlock the door with disabled user PIN"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); @@ -79028,13 +79196,13 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 33: { - LogStep(33, "Verify that lock state attribute value is set to Locked"); + case 45: { + LogStep(45, "Verify that lock state attribute value is set to Locked"); return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, chip::NullOptional); } - case 34: { - LogStep(34, "Unlock the door with enabled user PIN"); + case 46: { + LogStep(46, "Unlock the door with enabled user PIN"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::UnlockDoor::Type value; value.PINCode.Emplace(); @@ -79044,13 +79212,13 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 35: { - LogStep(35, "Verify that lock state attribute value is set to Unlocked"); + case 47: { + LogStep(47, "Verify that lock state attribute value is set to Unlocked"); return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, chip::NullOptional); } - case 36: { - LogStep(36, "Try to lock the door with disabled user PIN"); + case 48: { + LogStep(48, "Try to lock the door with disabled user PIN"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::LockDoor::Type value; value.PINCode.Emplace(); @@ -79060,13 +79228,13 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 37: { - LogStep(37, "Verify that lock state attribute value stays Unlocked"); + case 49: { + LogStep(49, "Verify that lock state attribute value stays Unlocked"); return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, chip::NullOptional); } - case 38: { - LogStep(38, "Lock the door with enabled user PIN"); + case 50: { + LogStep(50, "Lock the door with enabled user PIN"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::LockDoor::Type value; value.PINCode.Emplace(); @@ -79076,13 +79244,13 @@ class DL_LockUnlockSuite : public TestCommand ); } - case 39: { - LogStep(39, "Verify that lock state attribute value is set to Locked"); + case 51: { + LogStep(51, "Verify that lock state attribute value is set to Locked"); return ReadAttribute(kIdentityAlpha, GetEndpoint(1), DoorLock::Id, DoorLock::Attributes::LockState::Id, true, chip::NullOptional); } - case 40: { - LogStep(40, "Clean all the users and credentials"); + case 52: { + LogStep(52, "Clean all the users and credentials"); ListFreer listFreer; chip::app::Clusters::DoorLock::Commands::ClearUser::Type value; value.userIndex = 65534U;