LCOV - code coverage report
Current view: top level - controller - AutoCommissioner.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 0 521 0.0 %
Date: 2024-02-15 08:20:41 Functions: 0 28 0.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : #include <controller/AutoCommissioner.h>
      20             : 
      21             : #include <cstring>
      22             : 
      23             : #include <app/InteractionModelTimeout.h>
      24             : #include <controller/CHIPDeviceController.h>
      25             : #include <credentials/CHIPCert.h>
      26             : #include <lib/support/SafeInt.h>
      27             : 
      28             : namespace chip {
      29             : namespace Controller {
      30             : 
      31             : using namespace chip::app::Clusters;
      32             : using chip::app::DataModel::MakeNullable;
      33             : using chip::app::DataModel::NullNullable;
      34             : 
      35           0 : AutoCommissioner::AutoCommissioner()
      36             : {
      37           0 :     SetCommissioningParameters(CommissioningParameters());
      38           0 : }
      39             : 
      40           0 : AutoCommissioner::~AutoCommissioner()
      41             : {
      42           0 :     ReleaseDAC();
      43           0 :     ReleasePAI();
      44           0 : }
      45             : 
      46           0 : void AutoCommissioner::SetOperationalCredentialsDelegate(OperationalCredentialsDelegate * operationalCredentialsDelegate)
      47             : {
      48           0 :     mOperationalCredentialsDelegate = operationalCredentialsDelegate;
      49           0 : }
      50             : 
      51             : // Returns true if maybeUnsafeSpan is pointing to a buffer that we're not sure
      52             : // will live for long enough.  knownSafeSpan, if it has a value, points to a
      53             : // buffer that we _are_ sure will live for long enough.
      54             : template <typename SpanType>
      55           0 : static bool IsUnsafeSpan(const Optional<SpanType> & maybeUnsafeSpan, const Optional<SpanType> & knownSafeSpan)
      56             : {
      57           0 :     if (!maybeUnsafeSpan.HasValue())
      58             :     {
      59           0 :         return false;
      60             :     }
      61             : 
      62           0 :     if (!knownSafeSpan.HasValue())
      63             :     {
      64           0 :         return true;
      65             :     }
      66             : 
      67           0 :     return maybeUnsafeSpan.Value().data() != knownSafeSpan.Value().data();
      68             : }
      69             : 
      70           0 : CHIP_ERROR AutoCommissioner::VerifyICDRegistrationInfo(const CommissioningParameters & params)
      71             : {
      72           0 :     ChipLogProgress(Controller, "Checking ICD registration parameters");
      73           0 :     if (!params.GetICDSymmetricKey().HasValue())
      74             :     {
      75           0 :         ChipLogError(Controller, "Missing ICD symmetric key!");
      76           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      77             :     }
      78           0 :     if (params.GetICDSymmetricKey().Value().size() != sizeof(mICDSymmetricKey))
      79             :     {
      80           0 :         ChipLogError(Controller, "Invalid ICD symmetric key length!");
      81           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      82             :     }
      83           0 :     if (!params.GetICDCheckInNodeId().HasValue())
      84             :     {
      85           0 :         ChipLogError(Controller, "Missing ICD check-in node id!");
      86           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      87             :     }
      88           0 :     if (!params.GetICDMonitoredSubject().HasValue())
      89             :     {
      90           0 :         ChipLogError(Controller, "Missing ICD monitored subject!");
      91           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      92             :     }
      93           0 :     return CHIP_NO_ERROR;
      94             : }
      95             : 
      96           0 : CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParameters & params)
      97             : {
      98             :     // Make sure any members that point to buffers that we are not pointing to
      99             :     // our own buffers are not going to dangle.  We can skip this step if all
     100             :     // the buffers pointers that we don't plan to re-point to our own buffers
     101             :     // below are already pointing to the same things as our own buffer pointers
     102             :     // (so that we know they have to be safe somehow).
     103             :     //
     104             :     // The checks are a bit painful, because Span does not have a usable
     105             :     // operator==, and in any case, we want to compare for pointer equality, not
     106             :     // data equality.
     107             :     bool haveMaybeDanglingBufferPointers =
     108           0 :         ((params.GetNOCChainGenerationParameters().HasValue() &&
     109           0 :           (!mParams.GetNOCChainGenerationParameters().HasValue() ||
     110           0 :            params.GetNOCChainGenerationParameters().Value().nocsrElements.data() !=
     111           0 :                mParams.GetNOCChainGenerationParameters().Value().nocsrElements.data() ||
     112           0 :            params.GetNOCChainGenerationParameters().Value().signature.data() !=
     113           0 :                mParams.GetNOCChainGenerationParameters().Value().signature.data())) ||
     114           0 :          IsUnsafeSpan(params.GetRootCert(), mParams.GetRootCert()) || IsUnsafeSpan(params.GetNoc(), mParams.GetNoc()) ||
     115           0 :          IsUnsafeSpan(params.GetIcac(), mParams.GetIcac()) || IsUnsafeSpan(params.GetIpk(), mParams.GetIpk()) ||
     116           0 :          IsUnsafeSpan(params.GetAttestationElements(), mParams.GetAttestationElements()) ||
     117           0 :          IsUnsafeSpan(params.GetAttestationSignature(), mParams.GetAttestationSignature()) ||
     118           0 :          IsUnsafeSpan(params.GetPAI(), mParams.GetPAI()) || IsUnsafeSpan(params.GetDAC(), mParams.GetDAC()) ||
     119           0 :          IsUnsafeSpan(params.GetTimeZone(), mParams.GetTimeZone()) ||
     120           0 :          IsUnsafeSpan(params.GetDSTOffsets(), mParams.GetDSTOffsets()) ||
     121           0 :          IsUnsafeSpan(params.GetICDSymmetricKey(), mParams.GetICDSymmetricKey()) ||
     122           0 :          (params.GetDefaultNTP().HasValue() && !params.GetDefaultNTP().Value().IsNull() &&
     123           0 :           params.GetDefaultNTP().Value().Value().data() != mDefaultNtp));
     124             : 
     125           0 :     mParams = params;
     126             : 
     127           0 :     if (haveMaybeDanglingBufferPointers)
     128             :     {
     129           0 :         mParams.ClearExternalBufferDependentValues();
     130             :     }
     131             : 
     132             :     // For members of params that point to some sort of buffer, we have to copy
     133             :     // the data over into our own buffers.
     134             : 
     135           0 :     if (params.GetThreadOperationalDataset().HasValue())
     136             :     {
     137           0 :         ByteSpan dataset = params.GetThreadOperationalDataset().Value();
     138           0 :         if (dataset.size() > CommissioningParameters::kMaxThreadDatasetLen)
     139             :         {
     140           0 :             ChipLogError(Controller, "Thread operational data set is too large");
     141             :             // Make sure our buffer pointers don't dangle.
     142           0 :             mParams.ClearExternalBufferDependentValues();
     143           0 :             return CHIP_ERROR_INVALID_ARGUMENT;
     144             :         }
     145           0 :         memcpy(mThreadOperationalDataset, dataset.data(), dataset.size());
     146           0 :         ChipLogProgress(Controller, "Setting thread operational dataset from parameters");
     147           0 :         mParams.SetThreadOperationalDataset(ByteSpan(mThreadOperationalDataset, dataset.size()));
     148             :     }
     149             : 
     150           0 :     if (params.GetWiFiCredentials().HasValue())
     151             :     {
     152           0 :         WiFiCredentials creds = params.GetWiFiCredentials().Value();
     153           0 :         if (creds.ssid.size() > CommissioningParameters::kMaxSsidLen ||
     154           0 :             creds.credentials.size() > CommissioningParameters::kMaxCredentialsLen)
     155             :         {
     156           0 :             ChipLogError(Controller, "Wifi credentials are too large");
     157             :             // Make sure our buffer pointers don't dangle.
     158           0 :             mParams.ClearExternalBufferDependentValues();
     159           0 :             return CHIP_ERROR_INVALID_ARGUMENT;
     160             :         }
     161           0 :         memcpy(mSsid, creds.ssid.data(), creds.ssid.size());
     162           0 :         memcpy(mCredentials, creds.credentials.data(), creds.credentials.size());
     163           0 :         ChipLogProgress(Controller, "Setting wifi credentials from parameters");
     164           0 :         mParams.SetWiFiCredentials(
     165           0 :             WiFiCredentials(ByteSpan(mSsid, creds.ssid.size()), ByteSpan(mCredentials, creds.credentials.size())));
     166             :     }
     167             : 
     168           0 :     if (params.GetCountryCode().HasValue())
     169             :     {
     170           0 :         auto code = params.GetCountryCode().Value();
     171           0 :         MutableCharSpan copiedCode(mCountryCode);
     172           0 :         if (CopyCharSpanToMutableCharSpan(code, copiedCode) == CHIP_NO_ERROR)
     173             :         {
     174           0 :             mParams.SetCountryCode(copiedCode);
     175             :         }
     176             :         else
     177             :         {
     178           0 :             ChipLogError(Controller, "Country code is too large: %u", static_cast<unsigned>(code.size()));
     179             :             // Make sure our buffer pointers don't dangle.
     180           0 :             mParams.ClearExternalBufferDependentValues();
     181           0 :             return CHIP_ERROR_INVALID_ARGUMENT;
     182             :         }
     183             :     }
     184             : 
     185             :     // If the AttestationNonce is passed in, using that else using a random one..
     186           0 :     if (params.GetAttestationNonce().HasValue())
     187             :     {
     188           0 :         ChipLogProgress(Controller, "Setting attestation nonce from parameters");
     189           0 :         VerifyOrReturnError(params.GetAttestationNonce().Value().size() == sizeof(mAttestationNonce), CHIP_ERROR_INVALID_ARGUMENT);
     190           0 :         memcpy(mAttestationNonce, params.GetAttestationNonce().Value().data(), params.GetAttestationNonce().Value().size());
     191             :     }
     192             :     else
     193             :     {
     194           0 :         ChipLogProgress(Controller, "Setting attestation nonce to random value");
     195           0 :         Crypto::DRBG_get_bytes(mAttestationNonce, sizeof(mAttestationNonce));
     196             :     }
     197           0 :     mParams.SetAttestationNonce(ByteSpan(mAttestationNonce, sizeof(mAttestationNonce)));
     198             : 
     199           0 :     if (params.GetCSRNonce().HasValue())
     200             :     {
     201           0 :         ChipLogProgress(Controller, "Setting CSR nonce from parameters");
     202           0 :         VerifyOrReturnError(params.GetCSRNonce().Value().size() == sizeof(mCSRNonce), CHIP_ERROR_INVALID_ARGUMENT);
     203           0 :         memcpy(mCSRNonce, params.GetCSRNonce().Value().data(), params.GetCSRNonce().Value().size());
     204             :     }
     205             :     else
     206             :     {
     207           0 :         ChipLogProgress(Controller, "Setting CSR nonce to random value");
     208           0 :         Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce));
     209             :     }
     210           0 :     mParams.SetCSRNonce(ByteSpan(mCSRNonce, sizeof(mCSRNonce)));
     211             : 
     212           0 :     if (params.GetDSTOffsets().HasValue())
     213             :     {
     214           0 :         ChipLogProgress(Controller, "Setting DST offsets from parameters");
     215           0 :         size_t size = std::min(params.GetDSTOffsets().Value().size(), kMaxSupportedDstStructs);
     216           0 :         for (size_t i = 0; i < size; ++i)
     217             :         {
     218           0 :             mDstOffsetsBuf[i] = params.GetDSTOffsets().Value()[i];
     219             :         }
     220           0 :         auto list = app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>(mDstOffsetsBuf, size);
     221           0 :         mParams.SetDSTOffsets(list);
     222             :     }
     223           0 :     if (params.GetTimeZone().HasValue())
     224             :     {
     225           0 :         ChipLogProgress(Controller, "Setting Time Zone from parameters");
     226           0 :         size_t size = std::min(params.GetTimeZone().Value().size(), kMaxSupportedTimeZones);
     227           0 :         for (size_t i = 0; i < size; ++i)
     228             :         {
     229           0 :             mTimeZoneBuf[i] = params.GetTimeZone().Value()[i];
     230           0 :             if (params.GetTimeZone().Value()[i].name.HasValue() &&
     231           0 :                 params.GetTimeZone().Value()[i].name.Value().size() <= kMaxTimeZoneNameLen)
     232             :             {
     233           0 :                 auto span = MutableCharSpan(mTimeZoneNames[i], kMaxTimeZoneNameLen);
     234             :                 // The buffer backing "span" is statically allocated and is of size kMaxSupportedTimeZones, so this should never
     235             :                 // fail.
     236           0 :                 CopyCharSpanToMutableCharSpan(params.GetTimeZone().Value()[i].name.Value(), span);
     237           0 :                 mTimeZoneBuf[i].name.SetValue(span);
     238             :             }
     239             :             else
     240             :             {
     241           0 :                 mTimeZoneBuf[i].name.ClearValue();
     242             :             }
     243             :         }
     244           0 :         auto list = app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>(mTimeZoneBuf, size);
     245           0 :         mParams.SetTimeZone(list);
     246             :     }
     247           0 :     if (params.GetDefaultNTP().HasValue())
     248             :     {
     249           0 :         ChipLogProgress(Controller, "Setting Default NTP from parameters");
     250             :         // This parameter is an optional nullable, so we need to go two levels deep here.
     251           0 :         if (!params.GetDefaultNTP().Value().IsNull() && params.GetDefaultNTP().Value().Value().size() <= kMaxDefaultNtpSize)
     252             :         {
     253             :             // The buffer backing "span" is statically allocated and is of size kMaxDefaultNtpSize.
     254           0 :             auto span = MutableCharSpan(mDefaultNtp, kMaxDefaultNtpSize);
     255           0 :             CopyCharSpanToMutableCharSpan(params.GetDefaultNTP().Value().Value(), span);
     256           0 :             auto default_ntp = MakeNullable(CharSpan(mDefaultNtp, params.GetDefaultNTP().Value().Value().size()));
     257           0 :             mParams.SetDefaultNTP(default_ntp);
     258           0 :         }
     259             :     }
     260             : 
     261           0 :     if (params.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore && params.GetICDSymmetricKey().HasValue())
     262             :     {
     263           0 :         ReturnErrorOnFailure(VerifyICDRegistrationInfo(params));
     264             : 
     265             :         // The values must be valid now.
     266           0 :         memcpy(mICDSymmetricKey, params.GetICDSymmetricKey().Value().data(), params.GetICDSymmetricKey().Value().size());
     267           0 :         mParams.SetICDSymmetricKey(ByteSpan(mICDSymmetricKey));
     268           0 :         mParams.SetICDCheckInNodeId(params.GetICDCheckInNodeId().Value());
     269           0 :         mParams.SetICDMonitoredSubject(params.GetICDMonitoredSubject().Value());
     270             :     }
     271             : 
     272           0 :     return CHIP_NO_ERROR;
     273             : }
     274             : 
     275           0 : const CommissioningParameters & AutoCommissioner::GetCommissioningParameters() const
     276             : {
     277           0 :     return mParams;
     278             : }
     279             : 
     280           0 : CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStage currentStage, CHIP_ERROR & lastErr)
     281             : {
     282           0 :     auto nextStage = GetNextCommissioningStageInternal(currentStage, lastErr);
     283           0 :     if (lastErr == CHIP_NO_ERROR)
     284             :     {
     285           0 :         ChipLogProgress(Controller, "Commissioning stage next step: '%s' -> '%s'", StageToString(currentStage),
     286             :                         StageToString(nextStage));
     287             :     }
     288             :     else
     289             :     {
     290           0 :         ChipLogProgress(Controller, "Going from commissioning step '%s' with lastErr = '%s' -> '%s'", StageToString(currentStage),
     291             :                         lastErr.AsString(), StageToString(nextStage));
     292             :     }
     293           0 :     return nextStage;
     294             : }
     295             : 
     296           0 : CommissioningStage AutoCommissioner::GetNextCommissioningStageNetworkSetup(CommissioningStage currentStage, CHIP_ERROR & lastErr)
     297             : {
     298           0 :     if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
     299             :     {
     300           0 :         return CommissioningStage::kWiFiNetworkSetup;
     301             :     }
     302           0 :     if (mParams.GetThreadOperationalDataset().HasValue() && mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
     303             :     {
     304           0 :         return CommissioningStage::kThreadNetworkSetup;
     305             :     }
     306             : 
     307           0 :     ChipLogError(Controller, "Required network information not provided in commissioning parameters");
     308           0 :     ChipLogError(Controller, "Parameters supplied: wifi (%s) thread (%s)", mParams.GetWiFiCredentials().HasValue() ? "yes" : "no",
     309             :                  mParams.GetThreadOperationalDataset().HasValue() ? "yes" : "no");
     310           0 :     ChipLogError(Controller, "Device supports: wifi (%s) thread(%s)",
     311             :                  mDeviceCommissioningInfo.network.wifi.endpoint == kInvalidEndpointId ? "no" : "yes",
     312             :                  mDeviceCommissioningInfo.network.thread.endpoint == kInvalidEndpointId ? "no" : "yes");
     313           0 :     lastErr = CHIP_ERROR_INVALID_ARGUMENT;
     314           0 :     return CommissioningStage::kCleanup;
     315             : }
     316             : 
     317           0 : CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(CommissioningStage currentStage, CHIP_ERROR & lastErr)
     318             : {
     319           0 :     if (mStopCommissioning)
     320             :     {
     321           0 :         return CommissioningStage::kCleanup;
     322             :     }
     323           0 :     if (lastErr != CHIP_NO_ERROR)
     324             :     {
     325           0 :         return CommissioningStage::kCleanup;
     326             :     }
     327             : 
     328           0 :     switch (currentStage)
     329             :     {
     330           0 :     case CommissioningStage::kSecurePairing:
     331           0 :         return CommissioningStage::kReadCommissioningInfo;
     332           0 :     case CommissioningStage::kReadCommissioningInfo:
     333           0 :         if (mDeviceCommissioningInfo.general.breadcrumb > 0)
     334             :         {
     335             :             // If the breadcrumb is 0, the failsafe was disarmed.
     336             :             // We failed on network setup or later, the node failsafe has not been re-armed and the breadcrumb has not been reset.
     337             :             // Per the spec, we restart from after adding the NOC.
     338           0 :             return GetNextCommissioningStage(CommissioningStage::kSendNOC, lastErr);
     339             :         }
     340           0 :         return CommissioningStage::kReadCommissioningInfo2;
     341           0 :     case CommissioningStage::kReadCommissioningInfo2:
     342           0 :         return CommissioningStage::kArmFailsafe;
     343           0 :     case CommissioningStage::kArmFailsafe:
     344           0 :         return CommissioningStage::kConfigRegulatory;
     345           0 :     case CommissioningStage::kConfigRegulatory:
     346           0 :         if (mDeviceCommissioningInfo.requiresUTC)
     347             :         {
     348           0 :             return CommissioningStage::kConfigureUTCTime;
     349             :         }
     350             :         else
     351             :         {
     352             :             // Time cluster is not supported, move right to DA
     353           0 :             return CommissioningStage::kSendPAICertificateRequest;
     354             :         }
     355           0 :     case CommissioningStage::kConfigureUTCTime:
     356           0 :         if (mDeviceCommissioningInfo.requiresTimeZone && mParams.GetTimeZone().HasValue())
     357             :         {
     358           0 :             return kConfigureTimeZone;
     359             :         }
     360             :         else
     361             :         {
     362           0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureTimeZone, lastErr);
     363             :         }
     364           0 :     case CommissioningStage::kConfigureTimeZone:
     365           0 :         if (mNeedsDST && mParams.GetDSTOffsets().HasValue())
     366             :         {
     367           0 :             return CommissioningStage::kConfigureDSTOffset;
     368             :         }
     369             :         else
     370             :         {
     371           0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureDSTOffset, lastErr);
     372             :         }
     373           0 :     case CommissioningStage::kConfigureDSTOffset:
     374           0 :         if (mDeviceCommissioningInfo.requiresDefaultNTP && mParams.GetDefaultNTP().HasValue())
     375             :         {
     376           0 :             return CommissioningStage::kConfigureDefaultNTP;
     377             :         }
     378             :         else
     379             :         {
     380           0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureDefaultNTP, lastErr);
     381             :         }
     382           0 :     case CommissioningStage::kConfigureDefaultNTP:
     383           0 :         return CommissioningStage::kSendPAICertificateRequest;
     384           0 :     case CommissioningStage::kSendPAICertificateRequest:
     385           0 :         return CommissioningStage::kSendDACCertificateRequest;
     386           0 :     case CommissioningStage::kSendDACCertificateRequest:
     387           0 :         return CommissioningStage::kSendAttestationRequest;
     388           0 :     case CommissioningStage::kSendAttestationRequest:
     389           0 :         return CommissioningStage::kAttestationVerification;
     390           0 :     case CommissioningStage::kAttestationVerification:
     391           0 :         return CommissioningStage::kSendOpCertSigningRequest;
     392           0 :     case CommissioningStage::kSendOpCertSigningRequest:
     393           0 :         return CommissioningStage::kValidateCSR;
     394           0 :     case CommissioningStage::kValidateCSR:
     395           0 :         return CommissioningStage::kGenerateNOCChain;
     396           0 :     case CommissioningStage::kGenerateNOCChain:
     397           0 :         return CommissioningStage::kSendTrustedRootCert;
     398           0 :     case CommissioningStage::kSendTrustedRootCert:
     399           0 :         return CommissioningStage::kSendNOC;
     400           0 :     case CommissioningStage::kSendNOC:
     401           0 :         if (mDeviceCommissioningInfo.requiresTrustedTimeSource && mParams.GetTrustedTimeSource().HasValue())
     402             :         {
     403           0 :             return CommissioningStage::kConfigureTrustedTimeSource;
     404             :         }
     405             :         else
     406             :         {
     407           0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureTrustedTimeSource, lastErr);
     408             :         }
     409           0 :     case CommissioningStage::kConfigureTrustedTimeSource:
     410           0 :         if (mNeedIcdRegistration)
     411             :         {
     412           0 :             if (mParams.GetICDCheckInNodeId().HasValue() && mParams.GetICDMonitoredSubject().HasValue() &&
     413           0 :                 mParams.GetICDSymmetricKey().HasValue())
     414             :             {
     415           0 :                 return CommissioningStage::kICDRegistration;
     416             :             }
     417           0 :             return CommissioningStage::kICDGetRegistrationInfo;
     418             :         }
     419           0 :         return GetNextCommissioningStageInternal(CommissioningStage::kICDSendStayActive, lastErr);
     420           0 :     case CommissioningStage::kICDGetRegistrationInfo:
     421           0 :         return CommissioningStage::kICDRegistration;
     422           0 :     case CommissioningStage::kICDRegistration:
     423             :         // TODO(#24259): StayActiveRequest is not supported by server. We may want to SendStayActive after OpDiscovery.
     424           0 :         return CommissioningStage::kICDSendStayActive;
     425           0 :     case CommissioningStage::kICDSendStayActive:
     426             :         // TODO(cecille): device attestation casues operational cert provisioning to happen, This should be a separate stage.
     427             :         // For thread and wifi, this should go to network setup then enable. For on-network we can skip right to finding the
     428             :         // operational network because the provisioning of certificates will trigger the device to start operational advertising.
     429           0 :         if (mNeedsNetworkSetup)
     430             :         {
     431             :             // if there is a WiFi or a Thread endpoint, then perform scan
     432           0 :             if (IsScanNeeded())
     433             :             {
     434             :                 // Perform Scan (kScanNetworks) and collect credentials (kNeedsNetworkCreds) right before configuring network.
     435             :                 // This order of steps allows the workflow to return to collect credentials again if network enablement fails.
     436           0 :                 return CommissioningStage::kScanNetworks;
     437             :             }
     438           0 :             ChipLogProgress(Controller, "No NetworkScan enabled or WiFi/Thread endpoint not specified, skipping ScanNetworks");
     439             : 
     440           0 :             return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
     441             :         }
     442             :         else
     443             :         {
     444           0 :             SetCASEFailsafeTimerIfNeeded();
     445           0 :             if (mParams.GetSkipCommissioningComplete().ValueOr(false))
     446             :             {
     447           0 :                 return CommissioningStage::kCleanup;
     448             :             }
     449           0 :             return CommissioningStage::kFindOperational;
     450             :         }
     451           0 :     case CommissioningStage::kScanNetworks:
     452           0 :         return CommissioningStage::kNeedsNetworkCreds;
     453           0 :     case CommissioningStage::kNeedsNetworkCreds:
     454           0 :         return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
     455           0 :     case CommissioningStage::kWiFiNetworkSetup:
     456           0 :         if (mParams.GetThreadOperationalDataset().HasValue() &&
     457           0 :             mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
     458             :         {
     459           0 :             return CommissioningStage::kThreadNetworkSetup;
     460             :         }
     461             :         else
     462             :         {
     463           0 :             return CommissioningStage::kFailsafeBeforeWiFiEnable;
     464             :         }
     465           0 :     case CommissioningStage::kThreadNetworkSetup:
     466           0 :         if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
     467             :         {
     468           0 :             return CommissioningStage::kFailsafeBeforeWiFiEnable;
     469             :         }
     470             :         else
     471             :         {
     472           0 :             return CommissioningStage::kFailsafeBeforeThreadEnable;
     473             :         }
     474           0 :     case CommissioningStage::kFailsafeBeforeWiFiEnable:
     475           0 :         return CommissioningStage::kWiFiNetworkEnable;
     476           0 :     case CommissioningStage::kFailsafeBeforeThreadEnable:
     477           0 :         return CommissioningStage::kThreadNetworkEnable;
     478           0 :     case CommissioningStage::kWiFiNetworkEnable:
     479           0 :         if (mParams.GetThreadOperationalDataset().HasValue() &&
     480           0 :             mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
     481             :         {
     482           0 :             return CommissioningStage::kThreadNetworkEnable;
     483             :         }
     484           0 :         else if (mParams.GetSkipCommissioningComplete().ValueOr(false))
     485             :         {
     486           0 :             SetCASEFailsafeTimerIfNeeded();
     487           0 :             return CommissioningStage::kCleanup;
     488             :         }
     489             :         else
     490             :         {
     491           0 :             SetCASEFailsafeTimerIfNeeded();
     492           0 :             return CommissioningStage::kFindOperational;
     493             :         }
     494           0 :     case CommissioningStage::kThreadNetworkEnable:
     495           0 :         SetCASEFailsafeTimerIfNeeded();
     496           0 :         if (mParams.GetSkipCommissioningComplete().ValueOr(false))
     497             :         {
     498           0 :             return CommissioningStage::kCleanup;
     499             :         }
     500           0 :         return CommissioningStage::kFindOperational;
     501           0 :     case CommissioningStage::kFindOperational:
     502           0 :         return CommissioningStage::kSendComplete;
     503           0 :     case CommissioningStage::kSendComplete:
     504           0 :         return CommissioningStage::kCleanup;
     505             : 
     506             :     // Neither of these have a next stage so return kError;
     507           0 :     case CommissioningStage::kCleanup:
     508             :     case CommissioningStage::kError:
     509           0 :         return CommissioningStage::kError;
     510             :     }
     511           0 :     return CommissioningStage::kError;
     512             : }
     513             : 
     514             : // No specific actions to take when an error happens since this command can fail and commissioning can still succeed.
     515           0 : static void OnFailsafeFailureForCASE(void * context, CHIP_ERROR error)
     516             : {
     517           0 :     ChipLogProgress(Controller, "ExtendFailsafe received failure response %s\n", chip::ErrorStr(error));
     518           0 : }
     519             : 
     520             : // No specific actions to take upon success.
     521             : static void
     522           0 : OnExtendFailsafeSuccessForCASE(void * context,
     523             :                                const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
     524             : {
     525           0 :     ChipLogProgress(Controller, "ExtendFailsafe received ArmFailSafe response errorCode=%u", to_underlying(data.errorCode));
     526           0 : }
     527             : 
     528           0 : void AutoCommissioner::SetCASEFailsafeTimerIfNeeded()
     529             : {
     530             :     // if there is a final fail-safe timer configured then, send it
     531           0 :     if (mParams.GetCASEFailsafeTimerSeconds().HasValue() && mCommissioneeDeviceProxy != nullptr)
     532             :     {
     533             :         // send the command via the PASE session (mCommissioneeDeviceProxy) since the CASE portion of commissioning
     534             :         // might be done by a different service (ex. PASE is done by a phone app and CASE is done by a Hub).
     535             :         // Also, we want the CASE failsafe timer to apply for the time it takes the Hub to perform operational discovery,
     536             :         // CASE establishment, and receipt of the commissioning complete command.
     537             :         // We know that the mCommissioneeDeviceProxy is still valid at this point since it gets cleared during cleanup
     538             :         // and SetCASEFailsafeTimerIfNeeded is always called before that stage.
     539             :         //
     540             :         // A false return from ExtendArmFailSafe is fine; we don't want to make
     541             :         // the fail-safe shorter here.
     542           0 :         mCommissioner->ExtendArmFailSafe(mCommissioneeDeviceProxy, CommissioningStage::kFindOperational,
     543           0 :                                          mParams.GetCASEFailsafeTimerSeconds().Value(),
     544           0 :                                          GetCommandTimeout(mCommissioneeDeviceProxy, CommissioningStage::kArmFailsafe),
     545             :                                          OnExtendFailsafeSuccessForCASE, OnFailsafeFailureForCASE);
     546             :     }
     547           0 : }
     548             : 
     549           0 : EndpointId AutoCommissioner::GetEndpoint(const CommissioningStage & stage) const
     550             : {
     551           0 :     switch (stage)
     552             :     {
     553           0 :     case CommissioningStage::kWiFiNetworkSetup:
     554             :     case CommissioningStage::kWiFiNetworkEnable:
     555           0 :         return mDeviceCommissioningInfo.network.wifi.endpoint;
     556           0 :     case CommissioningStage::kThreadNetworkSetup:
     557             :     case CommissioningStage::kThreadNetworkEnable:
     558           0 :         return mDeviceCommissioningInfo.network.thread.endpoint;
     559           0 :     default:
     560           0 :         return kRootEndpointId;
     561             :     }
     562             : }
     563             : 
     564           0 : CHIP_ERROR AutoCommissioner::StartCommissioning(DeviceCommissioner * commissioner, CommissioneeDeviceProxy * proxy)
     565             : {
     566           0 :     if (commissioner == nullptr)
     567             :     {
     568           0 :         ChipLogError(Controller, "Invalid DeviceCommissioner");
     569           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     570             :     }
     571             : 
     572           0 :     if (proxy == nullptr || !proxy->GetSecureSession().HasValue())
     573             :     {
     574           0 :         ChipLogError(Controller, "Device proxy secure session error");
     575           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     576             :     }
     577           0 :     mStopCommissioning       = false;
     578           0 :     mCommissioner            = commissioner;
     579           0 :     mCommissioneeDeviceProxy = proxy;
     580           0 :     mNeedsNetworkSetup =
     581           0 :         mCommissioneeDeviceProxy->GetSecureSession().Value()->AsSecureSession()->GetPeerAddress().GetTransportType() ==
     582             :         Transport::Type::kBle;
     583           0 :     CHIP_ERROR err               = CHIP_NO_ERROR;
     584           0 :     CommissioningStage nextStage = GetNextCommissioningStage(CommissioningStage::kSecurePairing, err);
     585           0 :     mCommissioner->PerformCommissioningStep(mCommissioneeDeviceProxy, nextStage, mParams, this, GetEndpoint(nextStage),
     586           0 :                                             GetCommandTimeout(mCommissioneeDeviceProxy, nextStage));
     587           0 :     return CHIP_NO_ERROR;
     588             : }
     589             : 
     590           0 : Optional<System::Clock::Timeout> AutoCommissioner::GetCommandTimeout(DeviceProxy * device, CommissioningStage stage) const
     591             : {
     592             :     // Network clusters can indicate the time required to connect, so if we are
     593             :     // connecting, use that time as our "how long it takes to process server
     594             :     // side" time.  Otherwise pick a time that should be enough for the command
     595             :     // processing: 7s for slow steps that can involve crypto, the default IM
     596             :     // timeout otherwise.
     597             :     // TODO: is this a reasonable estimate for the slow-crypto cases?
     598           0 :     constexpr System::Clock::Timeout kSlowCryptoProcessingTime = System::Clock::Seconds16(7);
     599             : 
     600             :     System::Clock::Timeout timeout;
     601           0 :     switch (stage)
     602             :     {
     603           0 :     case CommissioningStage::kWiFiNetworkEnable:
     604           0 :         ChipLogProgress(Controller, "Setting wifi connection time min = %u",
     605             :                         mDeviceCommissioningInfo.network.wifi.minConnectionTime);
     606           0 :         timeout = System::Clock::Seconds16(mDeviceCommissioningInfo.network.wifi.minConnectionTime);
     607           0 :         break;
     608           0 :     case CommissioningStage::kThreadNetworkEnable:
     609           0 :         timeout = System::Clock::Seconds16(mDeviceCommissioningInfo.network.thread.minConnectionTime);
     610           0 :         break;
     611           0 :     case CommissioningStage::kSendNOC:
     612             :     case CommissioningStage::kSendOpCertSigningRequest:
     613           0 :         timeout = kSlowCryptoProcessingTime;
     614           0 :         break;
     615           0 :     default:
     616           0 :         timeout = app::kExpectedIMProcessingTime;
     617           0 :         break;
     618             :     }
     619             : 
     620             :     // Adjust the timeout for our session transport latency, if we have access
     621             :     // to a session.
     622           0 :     auto sessionHandle = device->GetSecureSession();
     623           0 :     if (sessionHandle.HasValue())
     624             :     {
     625           0 :         timeout = sessionHandle.Value()->ComputeRoundTripTimeout(timeout);
     626             :     }
     627             : 
     628             :     // Enforce the spec minimal timeout.  Maybe this enforcement should live in
     629             :     // the DeviceCommissioner?
     630           0 :     if (timeout < kMinimumCommissioningStepTimeout)
     631             :     {
     632           0 :         timeout = kMinimumCommissioningStepTimeout;
     633             :     }
     634             : 
     635           0 :     return MakeOptional(timeout);
     636           0 : }
     637             : 
     638           0 : CHIP_ERROR AutoCommissioner::NOCChainGenerated(ByteSpan noc, ByteSpan icac, ByteSpan rcac, IdentityProtectionKeySpan ipk,
     639             :                                                NodeId adminSubject)
     640             : {
     641             :     // Reuse ICA Cert buffer for temporary store Root Cert.
     642           0 :     MutableByteSpan rootCert = MutableByteSpan(mICACertBuffer);
     643           0 :     ReturnErrorOnFailure(Credentials::ConvertX509CertToChipCert(rcac, rootCert));
     644           0 :     mParams.SetRootCert(rootCert);
     645             : 
     646           0 :     MutableByteSpan noCert = MutableByteSpan(mNOCertBuffer);
     647           0 :     ReturnErrorOnFailure(Credentials::ConvertX509CertToChipCert(noc, noCert));
     648           0 :     mParams.SetNoc(noCert);
     649             : 
     650           0 :     CommissioningStage nextStage = CommissioningStage::kSendTrustedRootCert;
     651           0 :     mCommissioner->PerformCommissioningStep(mCommissioneeDeviceProxy, nextStage, mParams, this, 0,
     652           0 :                                             GetCommandTimeout(mCommissioneeDeviceProxy, nextStage));
     653             : 
     654             :     // Trusted root cert has been sent, so we can re-use the icac buffer for the icac.
     655           0 :     if (!icac.empty())
     656             :     {
     657           0 :         MutableByteSpan icaCert = MutableByteSpan(mICACertBuffer);
     658           0 :         ReturnErrorOnFailure(Credentials::ConvertX509CertToChipCert(icac, icaCert));
     659           0 :         mParams.SetIcac(icaCert);
     660             :     }
     661             :     else
     662             :     {
     663           0 :         mParams.SetIcac(ByteSpan());
     664             :     }
     665             : 
     666           0 :     mParams.SetIpk(ipk);
     667           0 :     mParams.SetAdminSubject(adminSubject);
     668             : 
     669           0 :     return CHIP_NO_ERROR;
     670             : }
     671             : 
     672           0 : CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, CommissioningDelegate::CommissioningReport report)
     673             : {
     674           0 :     CompletionStatus completionStatus;
     675           0 :     completionStatus.err = err;
     676             : 
     677           0 :     if (err == CHIP_NO_ERROR)
     678             :     {
     679           0 :         ChipLogProgress(Controller, "Successfully finished commissioning step '%s'", StageToString(report.stageCompleted));
     680             :     }
     681             :     else
     682             :     {
     683           0 :         ChipLogProgress(Controller, "Error on commissioning step '%s': '%s'", StageToString(report.stageCompleted), err.AsString());
     684             :     }
     685             : 
     686           0 :     if (err != CHIP_NO_ERROR)
     687             :     {
     688           0 :         completionStatus.failedStage = MakeOptional(report.stageCompleted);
     689           0 :         ChipLogError(Controller, "Failed to perform commissioning step %d", static_cast<int>(report.stageCompleted));
     690           0 :         if (report.Is<AttestationErrorInfo>())
     691             :         {
     692           0 :             completionStatus.attestationResult = MakeOptional(report.Get<AttestationErrorInfo>().attestationResult);
     693           0 :             if ((report.Get<AttestationErrorInfo>().attestationResult ==
     694           0 :                  Credentials::AttestationVerificationResult::kDacProductIdMismatch) ||
     695           0 :                 (report.Get<AttestationErrorInfo>().attestationResult ==
     696             :                  Credentials::AttestationVerificationResult::kDacVendorIdMismatch))
     697             :             {
     698           0 :                 ChipLogError(Controller,
     699             :                              "Failed device attestation. Device vendor and/or product ID do not match the IDs expected. "
     700             :                              "Verify DAC certificate chain and certification declaration to ensure spec rules followed.");
     701             :             }
     702             :         }
     703           0 :         else if (report.Is<CommissioningErrorInfo>())
     704             :         {
     705           0 :             completionStatus.commissioningError = MakeOptional(report.Get<CommissioningErrorInfo>().commissioningError);
     706             :         }
     707           0 :         else if (report.Is<NetworkCommissioningStatusInfo>())
     708             :         {
     709             :             // This report type is used when an error happens in either NetworkConfig or ConnectNetwork commands
     710             :             completionStatus.networkCommissioningStatus =
     711           0 :                 MakeOptional(report.Get<NetworkCommissioningStatusInfo>().networkCommissioningStatus);
     712             : 
     713             :             // If we are configured to scan networks, then don't error out.
     714             :             // Instead, allow the app to try another network.
     715           0 :             if (IsScanNeeded())
     716             :             {
     717           0 :                 if (completionStatus.err == CHIP_NO_ERROR)
     718             :                 {
     719           0 :                     completionStatus.err = err;
     720             :                 }
     721           0 :                 err = CHIP_NO_ERROR;
     722             :                 // Walk back the completed stage to kScanNetworks.
     723             :                 // This will allow the app to try another network.
     724           0 :                 report.stageCompleted = CommissioningStage::kScanNetworks;
     725             :             }
     726             :         }
     727             :     }
     728             :     else
     729             :     {
     730           0 :         switch (report.stageCompleted)
     731             :         {
     732           0 :         case CommissioningStage::kReadCommissioningInfo:
     733           0 :             break;
     734           0 :         case CommissioningStage::kReadCommissioningInfo2: {
     735           0 :             if (!report.Is<ReadCommissioningInfo>())
     736             :             {
     737           0 :                 ChipLogError(Controller,
     738             :                              "[BUG] Should read commissioning info, but report is not ReadCommissioningInfo. THIS IS A BUG.");
     739             :             }
     740           0 :             ReadCommissioningInfo commissioningInfo = report.Get<ReadCommissioningInfo>();
     741             : 
     742           0 :             mDeviceCommissioningInfo = report.Get<ReadCommissioningInfo>();
     743           0 :             if (!mParams.GetFailsafeTimerSeconds().HasValue() && mDeviceCommissioningInfo.general.recommendedFailsafe > 0)
     744             :             {
     745           0 :                 mParams.SetFailsafeTimerSeconds(mDeviceCommissioningInfo.general.recommendedFailsafe);
     746             :             }
     747           0 :             mParams.SetRemoteVendorId(mDeviceCommissioningInfo.basic.vendorId)
     748           0 :                 .SetRemoteProductId(mDeviceCommissioningInfo.basic.productId)
     749           0 :                 .SetDefaultRegulatoryLocation(mDeviceCommissioningInfo.general.currentRegulatoryLocation)
     750           0 :                 .SetLocationCapability(mDeviceCommissioningInfo.general.locationCapability);
     751             :             // Don't send DST unless the device says it needs it
     752           0 :             mNeedsDST = false;
     753             : 
     754           0 :             mParams.SetSupportsConcurrentConnection(commissioningInfo.supportsConcurrentConnection);
     755             : 
     756           0 :             if (mParams.GetCheckForMatchingFabric())
     757             :             {
     758           0 :                 chip::NodeId nodeId = commissioningInfo.remoteNodeId;
     759           0 :                 if (nodeId != kUndefinedNodeId)
     760             :                 {
     761           0 :                     mParams.SetRemoteNodeId(nodeId);
     762             :                 }
     763             :             }
     764             : 
     765           0 :             if (mParams.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore)
     766             :             {
     767           0 :                 if (commissioningInfo.icd.isLIT && commissioningInfo.icd.checkInProtocolSupport)
     768             :                 {
     769           0 :                     mNeedIcdRegistration = true;
     770           0 :                     ChipLogDetail(Controller, "AutoCommissioner: ICD supports the check-in protocol.");
     771             :                 }
     772             :             }
     773           0 :             break;
     774             :         }
     775           0 :         case CommissioningStage::kConfigureTimeZone:
     776           0 :             mNeedsDST = report.Get<TimeZoneResponseInfo>().requiresDSTOffsets;
     777           0 :             break;
     778           0 :         case CommissioningStage::kSendPAICertificateRequest:
     779           0 :             SetPAI(report.Get<RequestedCertificate>().certificate);
     780           0 :             break;
     781           0 :         case CommissioningStage::kSendDACCertificateRequest:
     782           0 :             SetDAC(report.Get<RequestedCertificate>().certificate);
     783           0 :             break;
     784           0 :         case CommissioningStage::kSendAttestationRequest: {
     785           0 :             auto & elements  = report.Get<AttestationResponse>().attestationElements;
     786           0 :             auto & signature = report.Get<AttestationResponse>().signature;
     787           0 :             if (elements.size() > sizeof(mAttestationElements))
     788             :             {
     789           0 :                 ChipLogError(Controller, "AutoCommissioner attestationElements buffer size %u larger than cache size %u",
     790             :                              static_cast<unsigned>(elements.size()), static_cast<unsigned>(sizeof(mAttestationElements)));
     791           0 :                 return CHIP_ERROR_MESSAGE_TOO_LONG;
     792             :             }
     793           0 :             memcpy(mAttestationElements, elements.data(), elements.size());
     794           0 :             mAttestationElementsLen = static_cast<uint16_t>(elements.size());
     795           0 :             mParams.SetAttestationElements(ByteSpan(mAttestationElements, elements.size()));
     796           0 :             ChipLogDetail(Controller, "AutoCommissioner setting attestationElements buffer size %u/%u",
     797             :                           static_cast<unsigned>(elements.size()),
     798             :                           static_cast<unsigned>(mParams.GetAttestationElements().Value().size()));
     799             : 
     800           0 :             if (signature.size() > sizeof(mAttestationSignature))
     801             :             {
     802           0 :                 ChipLogError(Controller,
     803             :                              "AutoCommissioner attestationSignature buffer size %u larger than "
     804             :                              "cache size %u",
     805             :                              static_cast<unsigned>(signature.size()), static_cast<unsigned>(sizeof(mAttestationSignature)));
     806           0 :                 return CHIP_ERROR_MESSAGE_TOO_LONG;
     807             :             }
     808           0 :             memcpy(mAttestationSignature, signature.data(), signature.size());
     809           0 :             mAttestationSignatureLen = static_cast<uint16_t>(signature.size());
     810           0 :             mParams.SetAttestationSignature(ByteSpan(mAttestationSignature, signature.size()));
     811             : 
     812             :             // TODO: Does this need to be done at runtime? Seems like this could be done earlier and we wouldn't need to hold a
     813             :             // reference to the operational credential delegate here
     814           0 :             if (mOperationalCredentialsDelegate != nullptr)
     815             :             {
     816           0 :                 MutableByteSpan nonce(mCSRNonce);
     817           0 :                 ReturnErrorOnFailure(mOperationalCredentialsDelegate->ObtainCsrNonce(nonce));
     818           0 :                 mParams.SetCSRNonce(ByteSpan(mCSRNonce, sizeof(mCSRNonce)));
     819             :             }
     820           0 :             break;
     821             :         }
     822           0 :         case CommissioningStage::kSendOpCertSigningRequest: {
     823           0 :             NOCChainGenerationParameters nocParams;
     824           0 :             nocParams.nocsrElements = report.Get<CSRResponse>().nocsrElements;
     825           0 :             nocParams.signature     = report.Get<CSRResponse>().signature;
     826           0 :             mParams.SetNOCChainGenerationParameters(nocParams);
     827             :         }
     828           0 :         break;
     829           0 :         case CommissioningStage::kGenerateNOCChain:
     830             :             // For NOC chain generation, we re-use the buffers. NOCChainGenerated triggers the next stage before
     831             :             // storing the returned certs, so just return here without triggering the next stage.
     832           0 :             return NOCChainGenerated(report.Get<NocChain>().noc, report.Get<NocChain>().icac, report.Get<NocChain>().rcac,
     833           0 :                                      report.Get<NocChain>().ipk, report.Get<NocChain>().adminSubject);
     834           0 :         case CommissioningStage::kICDGetRegistrationInfo:
     835             :             // Noting to do. The ICD registation info is handled elsewhere.
     836           0 :             break;
     837           0 :         case CommissioningStage::kICDRegistration:
     838             :             // Noting to do. DevicePairingDelegate will handle this.
     839           0 :             break;
     840           0 :         case CommissioningStage::kICDSendStayActive:
     841             :             // Nothing to do.
     842           0 :             break;
     843           0 :         case CommissioningStage::kFindOperational:
     844           0 :             mOperationalDeviceProxy = report.Get<OperationalNodeFoundData>().operationalProxy;
     845           0 :             break;
     846           0 :         case CommissioningStage::kCleanup:
     847           0 :             ReleasePAI();
     848           0 :             ReleaseDAC();
     849           0 :             mCommissioneeDeviceProxy = nullptr;
     850           0 :             mOperationalDeviceProxy  = OperationalDeviceProxy();
     851           0 :             mDeviceCommissioningInfo = ReadCommissioningInfo();
     852           0 :             mNeedsDST                = false;
     853           0 :             return CHIP_NO_ERROR;
     854           0 :         default:
     855           0 :             break;
     856             :         }
     857             :     }
     858             : 
     859           0 :     CommissioningStage nextStage = GetNextCommissioningStage(report.stageCompleted, err);
     860           0 :     if (nextStage == CommissioningStage::kError)
     861             :     {
     862           0 :         return CHIP_ERROR_INCORRECT_STATE;
     863             :     }
     864             : 
     865             :     // If GetNextCommissioningStage indicated a failure, don't lose track of
     866             :     // that.  But don't overwrite any existing failures we had hanging
     867             :     // around.
     868           0 :     if (completionStatus.err == CHIP_NO_ERROR)
     869             :     {
     870           0 :         completionStatus.err = err;
     871             :     }
     872           0 :     mParams.SetCompletionStatus(completionStatus);
     873             : 
     874           0 :     return PerformStep(nextStage);
     875           0 : }
     876             : 
     877           0 : DeviceProxy * AutoCommissioner::GetDeviceProxyForStep(CommissioningStage nextStage)
     878             : {
     879           0 :     if (nextStage == CommissioningStage::kSendComplete ||
     880           0 :         (nextStage == CommissioningStage::kCleanup && mOperationalDeviceProxy.GetDeviceId() != kUndefinedNodeId))
     881             :     {
     882           0 :         return &mOperationalDeviceProxy;
     883             :     }
     884           0 :     return mCommissioneeDeviceProxy;
     885             : }
     886             : 
     887           0 : CHIP_ERROR AutoCommissioner::PerformStep(CommissioningStage nextStage)
     888             : {
     889           0 :     DeviceProxy * proxy = GetDeviceProxyForStep(nextStage);
     890           0 :     if (proxy == nullptr)
     891             :     {
     892           0 :         ChipLogError(Controller, "Invalid device for commissioning");
     893           0 :         return CHIP_ERROR_INCORRECT_STATE;
     894             :     }
     895             :     // Perform any last minute parameter adjustments before calling the commissioner object
     896           0 :     switch (nextStage)
     897             :     {
     898           0 :     case CommissioningStage::kConfigureTimeZone:
     899           0 :         if (mParams.GetTimeZone().Value().size() > mDeviceCommissioningInfo.maxTimeZoneSize)
     900             :         {
     901           0 :             mParams.SetTimeZone(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>(
     902           0 :                 mParams.GetTimeZone().Value().SubSpan(0, mDeviceCommissioningInfo.maxTimeZoneSize)));
     903             :         }
     904           0 :         break;
     905           0 :     case CommissioningStage::kConfigureDSTOffset:
     906           0 :         if (mParams.GetDSTOffsets().Value().size() > mDeviceCommissioningInfo.maxDSTSize)
     907             :         {
     908           0 :             mParams.SetDSTOffsets(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>(
     909           0 :                 mParams.GetDSTOffsets().Value().SubSpan(0, mDeviceCommissioningInfo.maxDSTSize)));
     910             :         }
     911           0 :         break;
     912           0 :     default:
     913           0 :         break;
     914             :     }
     915             : 
     916           0 :     mCommissioner->PerformCommissioningStep(proxy, nextStage, mParams, this, GetEndpoint(nextStage),
     917           0 :                                             GetCommandTimeout(proxy, nextStage));
     918           0 :     return CHIP_NO_ERROR;
     919             : }
     920             : 
     921           0 : void AutoCommissioner::ReleaseDAC()
     922             : {
     923           0 :     if (mDAC != nullptr)
     924             :     {
     925           0 :         Platform::MemoryFree(mDAC);
     926             :     }
     927           0 :     mDACLen = 0;
     928           0 :     mDAC    = nullptr;
     929           0 : }
     930             : 
     931           0 : CHIP_ERROR AutoCommissioner::SetDAC(const ByteSpan & dac)
     932             : {
     933           0 :     if (dac.size() == 0)
     934             :     {
     935           0 :         ReleaseDAC();
     936           0 :         return CHIP_NO_ERROR;
     937             :     }
     938             : 
     939           0 :     VerifyOrReturnError(dac.size() <= Credentials::kMaxDERCertLength, CHIP_ERROR_INVALID_ARGUMENT);
     940           0 :     if (mDACLen != 0)
     941             :     {
     942           0 :         ReleaseDAC();
     943             :     }
     944             : 
     945           0 :     VerifyOrReturnError(CanCastTo<uint16_t>(dac.size()), CHIP_ERROR_INVALID_ARGUMENT);
     946           0 :     if (mDAC == nullptr)
     947             :     {
     948           0 :         mDAC = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(dac.size()));
     949             :     }
     950           0 :     VerifyOrReturnError(mDAC != nullptr, CHIP_ERROR_NO_MEMORY);
     951           0 :     mDACLen = static_cast<uint16_t>(dac.size());
     952           0 :     memcpy(mDAC, dac.data(), mDACLen);
     953           0 :     mParams.SetDAC(ByteSpan(mDAC, mDACLen));
     954             : 
     955           0 :     return CHIP_NO_ERROR;
     956             : }
     957             : 
     958           0 : void AutoCommissioner::ReleasePAI()
     959             : {
     960           0 :     if (mPAI != nullptr)
     961             :     {
     962           0 :         chip::Platform::MemoryFree(mPAI);
     963             :     }
     964           0 :     mPAILen = 0;
     965           0 :     mPAI    = nullptr;
     966           0 : }
     967             : 
     968           0 : CHIP_ERROR AutoCommissioner::SetPAI(const chip::ByteSpan & pai)
     969             : {
     970           0 :     if (pai.size() == 0)
     971             :     {
     972           0 :         ReleasePAI();
     973           0 :         return CHIP_NO_ERROR;
     974             :     }
     975             : 
     976           0 :     VerifyOrReturnError(pai.size() <= Credentials::kMaxDERCertLength, CHIP_ERROR_INVALID_ARGUMENT);
     977           0 :     if (mPAILen != 0)
     978             :     {
     979           0 :         ReleasePAI();
     980             :     }
     981             : 
     982           0 :     VerifyOrReturnError(CanCastTo<uint16_t>(pai.size()), CHIP_ERROR_INVALID_ARGUMENT);
     983           0 :     if (mPAI == nullptr)
     984             :     {
     985           0 :         mPAI = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(pai.size()));
     986             :     }
     987           0 :     VerifyOrReturnError(mPAI != nullptr, CHIP_ERROR_NO_MEMORY);
     988           0 :     mPAILen = static_cast<uint16_t>(pai.size());
     989           0 :     memcpy(mPAI, pai.data(), mPAILen);
     990           0 :     mParams.SetPAI(ByteSpan(mPAI, mPAILen));
     991             : 
     992           0 :     return CHIP_NO_ERROR;
     993             : }
     994             : 
     995             : } // namespace Controller
     996             : } // namespace chip

Generated by: LCOV version 1.14