@@ -1131,16 +1131,39 @@ void DeviceCommissioner::OnFailedToExtendedArmFailSafeDeviceAttestation(void * c
1131
1131
commissioner->CommissioningStageComplete (CHIP_ERROR_INTERNAL, report);
1132
1132
}
1133
1133
1134
- void DeviceCommissioner::ExtendArmFailSafe (DeviceProxy * proxy, CommissioningStage step, uint16_t armFailSafeTimeout,
1134
+ bool DeviceCommissioner::ExtendArmFailSafe (DeviceProxy * proxy, CommissioningStage step, uint16_t armFailSafeTimeout,
1135
1135
Optional<System::Clock::Timeout> commandTimeout, OnExtendFailsafeSuccess onSuccess,
1136
1136
OnExtendFailsafeFailure onFailure)
1137
1137
{
1138
+ using namespace System ;
1139
+ using namespace System ::Clock;
1140
+ auto now = SystemClock ().GetMonotonicTimestamp ();
1141
+ auto newFailSafeTimeout = now + Seconds16 (armFailSafeTimeout);
1142
+ if (newFailSafeTimeout < proxy->GetFailSafeExpirationTimestamp ())
1143
+ {
1144
+ ChipLogProgress (
1145
+ Controller, " Skipping arming failsafe: new time (%u seconds from now) before old time (%u seconds from now)" ,
1146
+ armFailSafeTimeout, std::chrono::duration_cast<Seconds16>(proxy->GetFailSafeExpirationTimestamp () - now).count ());
1147
+ return false ;
1148
+ }
1149
+
1138
1150
uint64_t breadcrumb = static_cast <uint64_t >(step);
1139
1151
GeneralCommissioning::Commands::ArmFailSafe::Type request;
1140
1152
request.expiryLengthSeconds = armFailSafeTimeout;
1141
1153
request.breadcrumb = breadcrumb;
1142
1154
ChipLogProgress (Controller, " Arming failsafe (%u seconds)" , request.expiryLengthSeconds );
1143
- SendCommand (proxy, request, onSuccess, onFailure, kRootEndpointId , commandTimeout);
1155
+ CHIP_ERROR err = SendCommand (proxy, request, onSuccess, onFailure, kRootEndpointId , commandTimeout);
1156
+ if (err != CHIP_NO_ERROR)
1157
+ {
1158
+ onFailure (this , err);
1159
+ }
1160
+ else
1161
+ {
1162
+ // TODO: Handle the situation when our command ends up erroring out
1163
+ // asynchronously?
1164
+ proxy->SetFailSafeExpirationTimestamp (newFailSafeTimeout);
1165
+ }
1166
+ return true ;
1144
1167
}
1145
1168
1146
1169
void DeviceCommissioner::ExtendArmFailSafeForDeviceAttestation (const Credentials::DeviceAttestationVerifier::AttestationInfo & info,
@@ -1154,20 +1177,24 @@ void DeviceCommissioner::ExtendArmFailSafeForDeviceAttestation(const Credentials
1154
1177
mAttestationDeviceInfo = Platform::MakeUnique<Credentials::DeviceAttestationVerifier::AttestationDeviceInfo>(info);
1155
1178
1156
1179
auto expiryLengthSeconds = deviceAttestationDelegate->FailSafeExpiryTimeoutSecs ();
1157
- if (expiryLengthSeconds.HasValue ())
1180
+ bool failSafeSkipped = expiryLengthSeconds.HasValue ();
1181
+ if (failSafeSkipped)
1158
1182
{
1159
- GeneralCommissioning::Commands::ArmFailSafe::Type request;
1160
- request.expiryLengthSeconds = expiryLengthSeconds.Value ();
1161
- request.breadcrumb = mCommissioningStage ;
1162
- ChipLogProgress (Controller, " Changing fail-safe timer to %u seconds to handle DA failure" , request.expiryLengthSeconds );
1183
+ ChipLogProgress (Controller, " Changing fail-safe timer to %u seconds to handle DA failure" , expiryLengthSeconds.Value ());
1163
1184
// Per spec, anything we do with the fail-safe armed must not time out
1164
1185
// in less than kMinimumCommissioningStepTimeout.
1165
- SendCommand (mDeviceBeingCommissioned , request, OnArmFailSafeExtendedForDeviceAttestation,
1166
- OnFailedToExtendedArmFailSafeDeviceAttestation, MakeOptional (kMinimumCommissioningStepTimeout ));
1186
+ failSafeSkipped =
1187
+ ExtendArmFailSafe (mDeviceBeingCommissioned , mCommissioningStage , expiryLengthSeconds.Value (),
1188
+ MakeOptional (kMinimumCommissioningStepTimeout ), OnArmFailSafeExtendedForDeviceAttestation,
1189
+ OnFailedToExtendedArmFailSafeDeviceAttestation);
1167
1190
}
1168
1191
else
1169
1192
{
1170
1193
ChipLogProgress (Controller, " Proceeding without changing fail-safe timer value as delegate has not set it" );
1194
+ }
1195
+
1196
+ if (failSafeSkipped)
1197
+ {
1171
1198
// Callee does not use data argument.
1172
1199
const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType data;
1173
1200
OnArmFailSafeExtendedForDeviceAttestation (this , data);
@@ -1782,6 +1809,8 @@ void DeviceCommissioner::OnDeviceConnectionRetryFn(void * context, const ScopedN
1782
1809
{
1783
1810
failsafeTimeout = static_cast <uint16_t >(retryTimeout.count () + kDefaultFailsafeTimeout );
1784
1811
}
1812
+ // A false return from ExtendArmFailSafe is fine; we don't want to make the
1813
+ // fail-safe shorter here.
1785
1814
self->ExtendArmFailSafe (commissioneeDevice, CommissioningStage::kFindOperational , failsafeTimeout,
1786
1815
MakeOptional (kMinimumCommissioningStepTimeout ), OnExtendFailsafeForCASERetrySuccess,
1787
1816
OnExtendFailsafeForCASERetryFailure);
@@ -2168,8 +2197,11 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
2168
2197
{
2169
2198
case CommissioningStage::kArmFailsafe : {
2170
2199
VerifyOrDie (endpoint == kRootEndpointId );
2171
- ExtendArmFailSafe (proxy, step, params.GetFailsafeTimerSeconds ().ValueOr (kDefaultFailsafeTimeout ), timeout, OnArmFailSafe,
2172
- OnBasicFailure);
2200
+ // Make sure the fail-safe value we set here actually ends up being used
2201
+ // no matter what.
2202
+ proxy->SetFailSafeExpirationTimestamp (System::Clock::kZero );
2203
+ VerifyOrDie (ExtendArmFailSafe (proxy, step, params.GetFailsafeTimerSeconds ().ValueOr (kDefaultFailsafeTimeout ), timeout,
2204
+ OnArmFailSafe, OnBasicFailure));
2173
2205
}
2174
2206
break ;
2175
2207
case CommissioningStage::kReadCommissioningInfo : {
@@ -2464,6 +2496,14 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
2464
2496
SendCommand (proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
2465
2497
}
2466
2498
break ;
2499
+ case CommissioningStage::kFailsafeBeforeWiFiEnable :
2500
+ FALLTHROUGH;
2501
+ case CommissioningStage::kFailsafeBeforeThreadEnable :
2502
+ // Before we try to do network enablement, make sure that our fail-safe
2503
+ // is set far enough out that we can later try to do operational
2504
+ // discovery without it timing out.
2505
+ ExtendFailsafeBeforeNetworkEnable (proxy, params, step);
2506
+ break ;
2467
2507
case CommissioningStage::kWiFiNetworkEnable : {
2468
2508
if (!params.GetWiFiCredentials ().HasValue ())
2469
2509
{
@@ -2522,6 +2562,43 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
2522
2562
}
2523
2563
}
2524
2564
2565
+ void DeviceCommissioner::ExtendFailsafeBeforeNetworkEnable (DeviceProxy * device, CommissioningParameters & params,
2566
+ CommissioningStage step)
2567
+ {
2568
+ auto * commissioneeDevice = FindCommissioneeDevice (device->GetDeviceId ());
2569
+ if (device != commissioneeDevice)
2570
+ {
2571
+ // Not a commissionee device; just return.
2572
+ ChipLogError (Controller, " Trying to extend fail-safe for an unknown commissionee with device id " ChipLogFormatX64,
2573
+ ChipLogValueX64 (device->GetDeviceId ()));
2574
+ CommissioningStageComplete (CHIP_ERROR_INCORRECT_STATE, CommissioningDelegate::CommissioningReport ());
2575
+ return ;
2576
+ }
2577
+
2578
+ // Try to make sure we have at least enough time for our expected
2579
+ // commissioning bits plus the MRP retries for a Sigma1.
2580
+ uint16_t failSafeTimeoutSecs = params.GetFailsafeTimerSeconds ().ValueOr (kDefaultFailsafeTimeout );
2581
+ auto sigma1Timeout = CASESession::ComputeSigma1ResponseTimeout (commissioneeDevice->GetPairing ().GetRemoteMRPConfig ());
2582
+ uint16_t sigma1TimeoutSecs = std::chrono::duration_cast<System::Clock::Seconds16>(sigma1Timeout).count ();
2583
+ if (UINT16_MAX - failSafeTimeoutSecs < sigma1TimeoutSecs)
2584
+ {
2585
+ failSafeTimeoutSecs = UINT16_MAX;
2586
+ }
2587
+ else
2588
+ {
2589
+ failSafeTimeoutSecs = static_cast <uint16_t >(failSafeTimeoutSecs + sigma1TimeoutSecs);
2590
+ }
2591
+
2592
+ // A false return from ExtendArmFailSafe is fine; we don't want to make the
2593
+ // fail-safe shorter here.
2594
+ if (!ExtendArmFailSafe (commissioneeDevice, step, failSafeTimeoutSecs, MakeOptional (kMinimumCommissioningStepTimeout ),
2595
+ OnArmFailSafe, OnBasicFailure))
2596
+ {
2597
+ // Just move on to the next step.
2598
+ CommissioningStageComplete (CHIP_NO_ERROR, CommissioningDelegate::CommissioningReport ());
2599
+ }
2600
+ }
2601
+
2525
2602
CHIP_ERROR DeviceController::GetCompressedFabricIdBytes (MutableByteSpan & outBytes) const
2526
2603
{
2527
2604
const auto * fabricInfo = GetFabricInfo ();
0 commit comments