Matter SDK Coverage Report
Current view: top level - controller - CHIPDeviceController.cpp (source / functions) Coverage Total Hit
Test: SHA:6c8f029dd2432dc900f1c9245c324e69bd79e40a Lines: 4.4 % 1883 82
Test Date: 2026-08-08 07:40:09 Functions: 4.5 % 198 9

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2024 Project CHIP Authors
       4              :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5              :  *    All rights reserved.
       6              :  *
       7              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8              :  *    you may not use this file except in compliance with the License.
       9              :  *    You may obtain a copy of the License at
      10              :  *
      11              :  *        http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  *    Unless required by applicable law or agreed to in writing, software
      14              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  *    See the License for the specific language governing permissions and
      17              :  *    limitations under the License.
      18              :  */
      19              : 
      20              : /**
      21              :  *    @file
      22              :  *      Implementation of CHIP Device Controller, a common class
      23              :  *      that implements discovery, pairing and provisioning of CHIP
      24              :  *      devices.
      25              :  *
      26              :  */
      27              : 
      28              : // module header, comes first
      29              : #include <controller/CHIPDeviceController.h>
      30              : 
      31              : #include <app-common/zap-generated/ids/Attributes.h>
      32              : #include <app-common/zap-generated/ids/Clusters.h>
      33              : 
      34              : #include <app/InteractionModelEngine.h>
      35              : #include <app/OperationalSessionSetup.h>
      36              : #include <app/server/Dnssd.h>
      37              : #include <controller/CurrentFabricRemover.h>
      38              : #include <controller/InvokeInteraction.h>
      39              : #include <controller/WriteInteraction.h>
      40              : #include <credentials/CHIPCert.h>
      41              : #include <credentials/DeviceAttestationCredsProvider.h>
      42              : #include <crypto/CHIPCryptoPAL.h>
      43              : #include <lib/address_resolve/AddressResolve.h>
      44              : #include <lib/core/CHIPCore.h>
      45              : #include <lib/core/CHIPEncoding.h>
      46              : #include <lib/core/CHIPSafeCasts.h>
      47              : #include <lib/core/ErrorStr.h>
      48              : #include <lib/core/NodeId.h>
      49              : #include <lib/support/Base64.h>
      50              : #include <lib/support/CHIPMem.h>
      51              : #include <lib/support/CHIPMemString.h>
      52              : #include <lib/support/CodeUtils.h>
      53              : #include <lib/support/PersistentStorageMacros.h>
      54              : #include <lib/support/SafeInt.h>
      55              : #include <lib/support/ScopedMemoryBuffer.h>
      56              : #include <lib/support/ThreadOperationalDataset.h>
      57              : #include <lib/support/TimeUtils.h>
      58              : #include <lib/support/logging/CHIPLogging.h>
      59              : #include <messaging/ExchangeContext.h>
      60              : #include <platform/LockTracker.h>
      61              : #include <protocols/secure_channel/MessageCounterManager.h>
      62              : #include <setup_payload/QRCodeSetupPayloadParser.h>
      63              : #include <tracing/macros.h>
      64              : #include <tracing/metric_event.h>
      65              : 
      66              : #if CONFIG_NETWORK_LAYER_BLE
      67              : #include <ble/Ble.h>
      68              : #include <transport/raw/BLE.h>
      69              : #endif
      70              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
      71              : #include <transport/raw/WiFiPAF.h>
      72              : #endif
      73              : 
      74              : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
      75              : #include <platform/internal/NFCCommissioningManager.h>
      76              : #endif
      77              : 
      78              : #include <algorithm>
      79              : #include <array>
      80              : #include <errno.h>
      81              : #include <inttypes.h>
      82              : #include <limits>
      83              : #include <memory>
      84              : #include <stdint.h>
      85              : #include <stdlib.h>
      86              : #include <string>
      87              : #include <time.h>
      88              : 
      89              : using namespace chip::app;
      90              : using namespace chip::app::Clusters;
      91              : using namespace chip::Inet;
      92              : using namespace chip::System;
      93              : using namespace chip::Transport;
      94              : using namespace chip::Credentials;
      95              : using namespace chip::Crypto;
      96              : using namespace chip::Tracing;
      97              : 
      98              : namespace chip {
      99              : namespace Controller {
     100              : 
     101              : using namespace chip::Encoding;
     102              : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
     103              : using namespace chip::Protocols::UserDirectedCommissioning;
     104              : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
     105              : 
     106              : using chip::AddressResolve::Resolver;
     107              : using chip::AddressResolve::ResolveResult;
     108              : 
     109          440 : DeviceController::DeviceController()
     110              : {
     111           40 :     mState = State::NotInitialized;
     112           40 : }
     113              : 
     114            0 : CHIP_ERROR DeviceController::Init(ControllerInitParams params)
     115              : {
     116            0 :     assertChipStackLockedByCurrentThread();
     117              : 
     118            0 :     VerifyOrReturnError(mState == State::NotInitialized, CHIP_ERROR_INCORRECT_STATE);
     119            0 :     VerifyOrReturnError(params.systemState != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     120              : 
     121            0 :     VerifyOrReturnError(params.systemState->SystemLayer() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     122            0 :     VerifyOrReturnError(params.systemState->UDPEndPointManager() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     123              : 
     124              : #if CONFIG_NETWORK_LAYER_BLE
     125            0 :     VerifyOrReturnError(params.systemState->BleLayer() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     126              : #endif
     127              : 
     128            0 :     VerifyOrReturnError(params.systemState->TransportMgr() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     129              : 
     130            0 :     ReturnErrorOnFailure(mDNSResolver.Init(params.systemState->UDPEndPointManager()));
     131            0 :     mDNSResolver.SetDiscoveryDelegate(this);
     132            0 :     RegisterDeviceDiscoveryDelegate(params.deviceDiscoveryDelegate);
     133              : 
     134            0 :     mVendorId = params.controllerVendorId;
     135            0 :     if (params.operationalKeypair != nullptr || !params.controllerNOC.empty() || !params.controllerRCAC.empty())
     136              :     {
     137            0 :         ReturnErrorOnFailure(InitControllerNOCChain(params));
     138              :     }
     139            0 :     else if (params.fabricIndex.HasValue())
     140              :     {
     141            0 :         VerifyOrReturnError(params.systemState->Fabrics()->FabricCount() > 0, CHIP_ERROR_INVALID_ARGUMENT);
     142            0 :         if (params.systemState->Fabrics()->FindFabricWithIndex(params.fabricIndex.Value()) != nullptr)
     143              :         {
     144            0 :             mFabricIndex = params.fabricIndex.Value();
     145              :         }
     146              :         else
     147              :         {
     148            0 :             ChipLogError(Controller, "There is no fabric corresponding to the given fabricIndex");
     149            0 :             return CHIP_ERROR_INVALID_ARGUMENT;
     150              :         }
     151              :     }
     152              : 
     153            0 :     mSystemState = params.systemState->Retain();
     154            0 :     mState       = State::Initialized;
     155              : 
     156            0 :     mRemoveFromFabricTableOnShutdown = params.removeFromFabricTableOnShutdown;
     157            0 :     mDeleteFromFabricTableOnShutdown = params.deleteFromFabricTableOnShutdown;
     158              : 
     159            0 :     if (GetFabricIndex() != kUndefinedFabricIndex)
     160              :     {
     161            0 :         ChipLogProgress(Controller,
     162              :                         "Joined the fabric at index %d. Fabric ID is 0x" ChipLogFormatX64
     163              :                         " (Compressed Fabric ID: " ChipLogFormatX64 ")",
     164              :                         GetFabricIndex(), ChipLogValueX64(GetFabricId()), ChipLogValueX64(GetCompressedFabricId()));
     165              :     }
     166              : 
     167            0 :     return CHIP_NO_ERROR;
     168              : }
     169              : 
     170            0 : CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams & params)
     171              : {
     172            0 :     FabricInfo newFabric;
     173            0 :     constexpr uint32_t chipCertAllocatedLen = kMaxCHIPCertLength;
     174            0 :     chip::Platform::ScopedMemoryBuffer<uint8_t> rcacBuf;
     175            0 :     chip::Platform::ScopedMemoryBuffer<uint8_t> icacBuf;
     176            0 :     chip::Platform::ScopedMemoryBuffer<uint8_t> nocBuf;
     177            0 :     Credentials::P256PublicKeySpan rootPublicKeySpan;
     178              :     FabricId fabricId;
     179              :     NodeId nodeId;
     180            0 :     bool hasExternallyOwnedKeypair                   = false;
     181            0 :     Crypto::P256Keypair * externalOperationalKeypair = nullptr;
     182            0 :     VendorId newFabricVendorId                       = params.controllerVendorId;
     183              : 
     184              :     // There are three possibilities here in terms of what happens with our
     185              :     // operational key:
     186              :     // 1) We have an externally owned operational keypair.
     187              :     // 2) We have an operational keypair that the fabric table should clone via
     188              :     //    serialize/deserialize.
     189              :     // 3) We have no keypair at all, and the fabric table has been initialized
     190              :     //    with a key store.
     191            0 :     if (params.operationalKeypair != nullptr)
     192              :     {
     193            0 :         hasExternallyOwnedKeypair  = params.hasExternallyOwnedOperationalKeypair;
     194            0 :         externalOperationalKeypair = params.operationalKeypair;
     195              :     }
     196              : 
     197            0 :     VerifyOrReturnError(rcacBuf.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY);
     198            0 :     VerifyOrReturnError(icacBuf.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY);
     199            0 :     VerifyOrReturnError(nocBuf.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY);
     200              : 
     201            0 :     MutableByteSpan rcacSpan(rcacBuf.Get(), chipCertAllocatedLen);
     202              : 
     203            0 :     ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerRCAC, rcacSpan));
     204            0 :     ReturnErrorOnFailure(Credentials::ExtractPublicKeyFromChipCert(rcacSpan, rootPublicKeySpan));
     205            0 :     Crypto::P256PublicKey rootPublicKey{ rootPublicKeySpan };
     206              : 
     207            0 :     MutableByteSpan icacSpan;
     208            0 :     if (params.controllerICAC.empty())
     209              :     {
     210            0 :         ChipLogProgress(Controller, "Intermediate CA is not needed");
     211              :     }
     212              :     else
     213              :     {
     214            0 :         icacSpan = MutableByteSpan(icacBuf.Get(), chipCertAllocatedLen);
     215            0 :         ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerICAC, icacSpan));
     216              :     }
     217              : 
     218            0 :     MutableByteSpan nocSpan = MutableByteSpan(nocBuf.Get(), chipCertAllocatedLen);
     219              : 
     220            0 :     ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerNOC, nocSpan));
     221            0 :     ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(nocSpan, &nodeId, &fabricId));
     222              : 
     223            0 :     auto * fabricTable            = params.systemState->Fabrics();
     224            0 :     const FabricInfo * fabricInfo = nullptr;
     225              : 
     226              :     //
     227              :     // When multiple controllers are permitted on the same fabric, we need to find fabrics with
     228              :     // nodeId as an extra discriminant since we can have multiple FabricInfo objects that all
     229              :     // collide on the same fabric. Not doing so may result in a match with an existing FabricInfo
     230              :     // instance that matches the fabric in the provided NOC but is associated with a different NodeId
     231              :     // that is already in use by another active controller instance. That will effectively cause it
     232              :     // to change its identity inadvertently, which is not acceptable.
     233              :     //
     234              :     // TODO: Figure out how to clean up unreclaimed FabricInfos restored from persistent
     235              :     //       storage that are not in use by active DeviceController instances. Also, figure out
     236              :     //       how to reclaim FabricInfo slots when a DeviceController instance is deleted.
     237              :     //
     238            0 :     if (params.permitMultiControllerFabrics)
     239              :     {
     240            0 :         fabricInfo = fabricTable->FindIdentity(rootPublicKey, fabricId, nodeId);
     241              :     }
     242              :     else
     243              :     {
     244            0 :         fabricInfo = fabricTable->FindFabric(rootPublicKey, fabricId);
     245              :     }
     246              : 
     247            0 :     bool fabricFoundInTable = (fabricInfo != nullptr);
     248              : 
     249            0 :     FabricIndex fabricIndex = fabricFoundInTable ? fabricInfo->GetFabricIndex() : kUndefinedFabricIndex;
     250              : 
     251            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
     252              : 
     253            0 :     auto advertiseOperational =
     254            0 :         params.enableServerInteractions ? FabricTable::AdvertiseIdentity::Yes : FabricTable::AdvertiseIdentity::No;
     255              : 
     256              :     //
     257              :     // We permit colliding fabrics when multiple controllers are present on the same logical fabric
     258              :     // since each controller is associated with a unique FabricInfo 'identity' object and consequently,
     259              :     // a unique FabricIndex.
     260              :     //
     261              :     // This sets a flag that will be cleared automatically when the fabric is committed/reverted later
     262              :     // in this function.
     263              :     //
     264            0 :     if (params.permitMultiControllerFabrics)
     265              :     {
     266            0 :         fabricTable->PermitCollidingFabrics();
     267              :     }
     268              : 
     269              :     // We have 4 cases to handle legacy usage of direct operational key injection
     270            0 :     if (externalOperationalKeypair)
     271              :     {
     272              :         // Cases 1 and 2: Injected operational keys
     273              : 
     274              :         // CASE 1: Fabric update with injected key
     275            0 :         if (fabricFoundInTable)
     276              :         {
     277            0 :             err = fabricTable->UpdatePendingFabricWithProvidedOpKey(fabricIndex, nocSpan, icacSpan, externalOperationalKeypair,
     278              :                                                                     hasExternallyOwnedKeypair, advertiseOperational);
     279              :         }
     280              :         else
     281              :         // CASE 2: New fabric with injected key
     282              :         {
     283            0 :             err = fabricTable->AddNewPendingTrustedRootCert(rcacSpan);
     284            0 :             if (err == CHIP_NO_ERROR)
     285              :             {
     286            0 :                 err = fabricTable->AddNewPendingFabricWithProvidedOpKey(nocSpan, icacSpan, newFabricVendorId,
     287              :                                                                         externalOperationalKeypair, hasExternallyOwnedKeypair,
     288              :                                                                         &fabricIndex, advertiseOperational);
     289              :             }
     290              :         }
     291              :     }
     292              :     else
     293              :     {
     294              :         // Cases 3 and 4: OperationalKeystore has the keys
     295              : 
     296              :         // CASE 3: Fabric update with operational keystore
     297            0 :         if (fabricFoundInTable)
     298              :         {
     299            0 :             VerifyOrReturnError(fabricTable->HasOperationalKeyForFabric(fabricIndex), CHIP_ERROR_KEY_NOT_FOUND);
     300              : 
     301            0 :             err = fabricTable->UpdatePendingFabricWithOperationalKeystore(fabricIndex, nocSpan, icacSpan, advertiseOperational);
     302              :         }
     303              :         else
     304              :         // CASE 4: New fabric with operational keystore
     305              :         {
     306            0 :             err = fabricTable->AddNewPendingTrustedRootCert(rcacSpan);
     307            0 :             if (err == CHIP_NO_ERROR)
     308              :             {
     309            0 :                 err = fabricTable->AddNewPendingFabricWithOperationalKeystore(nocSpan, icacSpan, newFabricVendorId, &fabricIndex,
     310              :                                                                               advertiseOperational);
     311              :             }
     312              : 
     313            0 :             if (err == CHIP_NO_ERROR)
     314              :             {
     315              :                 // Now that we know our planned fabric index, verify that the
     316              :                 // keystore has a key for it.
     317            0 :                 if (!fabricTable->HasOperationalKeyForFabric(fabricIndex))
     318              :                 {
     319            0 :                     err = CHIP_ERROR_KEY_NOT_FOUND;
     320              :                 }
     321              :             }
     322              :         }
     323              :     }
     324              : 
     325              :     // Commit after setup, error-out on failure.
     326            0 :     if (err == CHIP_NO_ERROR)
     327              :     {
     328              :         // No need to revert on error: CommitPendingFabricData reverts internally on *any* error.
     329            0 :         err = fabricTable->CommitPendingFabricData();
     330              :     }
     331              :     else
     332              :     {
     333            0 :         fabricTable->RevertPendingFabricData();
     334              :     }
     335              : 
     336            0 :     ReturnErrorOnFailure(err);
     337            0 :     VerifyOrReturnError(fabricIndex != kUndefinedFabricIndex, CHIP_ERROR_INTERNAL);
     338              : 
     339            0 :     mFabricIndex       = fabricIndex;
     340            0 :     mAdvertiseIdentity = advertiseOperational;
     341            0 :     return CHIP_NO_ERROR;
     342            0 : }
     343              : 
     344            0 : CHIP_ERROR DeviceController::UpdateControllerNOCChain(const ByteSpan & noc, const ByteSpan & icac,
     345              :                                                       Crypto::P256Keypair * operationalKeypair,
     346              :                                                       bool operationalKeypairExternalOwned)
     347              : {
     348            0 :     VerifyOrReturnError(mFabricIndex != kUndefinedFabricIndex, CHIP_ERROR_INTERNAL);
     349            0 :     VerifyOrReturnError(mSystemState != nullptr, CHIP_ERROR_INTERNAL);
     350            0 :     FabricTable * fabricTable = mSystemState->Fabrics();
     351            0 :     CHIP_ERROR err            = CHIP_NO_ERROR;
     352              :     FabricId fabricId;
     353              :     NodeId nodeId;
     354            0 :     CATValues oldCats;
     355            0 :     CATValues newCats;
     356            0 :     ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(noc, &nodeId, &fabricId));
     357            0 :     ReturnErrorOnFailure(fabricTable->FetchCATs(mFabricIndex, oldCats));
     358            0 :     ReturnErrorOnFailure(ExtractCATsFromOpCert(noc, newCats));
     359              : 
     360            0 :     bool needCloseSession = true;
     361            0 :     if (GetFabricInfo()->GetNodeId() == nodeId && oldCats == newCats)
     362              :     {
     363            0 :         needCloseSession = false;
     364              :     }
     365              : 
     366            0 :     if (operationalKeypair != nullptr)
     367              :     {
     368            0 :         err = fabricTable->UpdatePendingFabricWithProvidedOpKey(mFabricIndex, noc, icac, operationalKeypair,
     369              :                                                                 operationalKeypairExternalOwned, mAdvertiseIdentity);
     370              :     }
     371              :     else
     372              :     {
     373            0 :         VerifyOrReturnError(fabricTable->HasOperationalKeyForFabric(mFabricIndex), CHIP_ERROR_KEY_NOT_FOUND);
     374            0 :         err = fabricTable->UpdatePendingFabricWithOperationalKeystore(mFabricIndex, noc, icac, mAdvertiseIdentity);
     375              :     }
     376              : 
     377            0 :     if (err == CHIP_NO_ERROR)
     378              :     {
     379            0 :         err = fabricTable->CommitPendingFabricData();
     380              :     }
     381              :     else
     382              :     {
     383            0 :         fabricTable->RevertPendingFabricData();
     384              :     }
     385              : 
     386            0 :     ReturnErrorOnFailure(err);
     387            0 :     if (needCloseSession)
     388              :     {
     389              :         // If the node id or CATs have changed, our existing CASE sessions are no longer valid,
     390              :         // because the other side will think anything coming over those sessions comes from our
     391              :         // old node ID, and the new CATs might not satisfy the ACL requirements of the other side.
     392            0 :         mSystemState->SessionMgr()->ExpireAllSessionsForFabric(mFabricIndex);
     393              :     }
     394            0 :     ChipLogProgress(Controller, "Controller NOC chain has updated");
     395            0 :     return CHIP_NO_ERROR;
     396              : }
     397              : 
     398            0 : void DeviceController::Shutdown()
     399              : {
     400            0 :     assertChipStackLockedByCurrentThread();
     401              : 
     402            0 :     VerifyOrReturn(mState != State::NotInitialized);
     403              : 
     404              :     // If our state is initialialized it means mSystemState is valid,
     405              :     // and we can use it below before we release our reference to it.
     406            0 :     ChipLogDetail(Controller, "Shutting down the controller");
     407            0 :     mState = State::NotInitialized;
     408              : 
     409            0 :     if (mFabricIndex != kUndefinedFabricIndex)
     410              :     {
     411              :         // Shut down any subscription clients for this fabric.
     412            0 :         app::InteractionModelEngine::GetInstance()->ShutdownSubscriptions(mFabricIndex);
     413              : 
     414              :         // Shut down any ongoing CASE session activity we have.  We're going to
     415              :         // assume that all sessions for our fabric belong to us here.
     416            0 :         mSystemState->CASESessionMgr()->ReleaseSessionsForFabric(mFabricIndex);
     417              : 
     418              :         // Shut down any bdx transfers we're acting as the server for.
     419            0 :         mSystemState->BDXTransferServer()->AbortTransfersForFabric(mFabricIndex);
     420              : 
     421              :         // TODO: The CASE session manager does not shut down existing CASE
     422              :         // sessions.  It just shuts down any ongoing CASE session establishment
     423              :         // we're in the middle of as initiator.  Maybe it should shut down
     424              :         // existing sessions too?
     425            0 :         mSystemState->SessionMgr()->ExpireAllSessionsForFabric(mFabricIndex);
     426              : 
     427            0 :         if (mDeleteFromFabricTableOnShutdown)
     428              :         {
     429            0 :             TEMPORARY_RETURN_IGNORED mSystemState->Fabrics()->Delete(mFabricIndex);
     430              :         }
     431            0 :         else if (mRemoveFromFabricTableOnShutdown)
     432              :         {
     433            0 :             mSystemState->Fabrics()->Forget(mFabricIndex);
     434              :         }
     435              :     }
     436              : 
     437            0 :     mSystemState->Release();
     438            0 :     mSystemState = nullptr;
     439              : 
     440            0 :     mDNSResolver.Shutdown();
     441            0 :     mDeviceDiscoveryDelegate = nullptr;
     442              : }
     443              : 
     444            0 : CHIP_ERROR DeviceController::GetPeerAddressAndPort(NodeId peerId, Inet::IPAddress & addr, uint16_t & port)
     445              : {
     446            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
     447            0 :     Transport::PeerAddress peerAddr;
     448            0 :     ReturnErrorOnFailure(mSystemState->CASESessionMgr()->GetPeerAddress(GetPeerScopedId(peerId), peerAddr));
     449            0 :     addr = peerAddr.GetIPAddress();
     450            0 :     port = peerAddr.GetPort();
     451            0 :     return CHIP_NO_ERROR;
     452              : }
     453              : 
     454            0 : CHIP_ERROR DeviceController::GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr)
     455              : {
     456            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
     457            0 :     ReturnErrorOnFailure(mSystemState->CASESessionMgr()->GetPeerAddress(GetPeerScopedId(nodeId), addr));
     458              : 
     459            0 :     return CHIP_NO_ERROR;
     460              : }
     461              : 
     462            0 : CHIP_ERROR DeviceController::ComputePASEVerifier(uint32_t iterations, uint32_t setupPincode, const ByteSpan & salt,
     463              :                                                  Spake2pVerifier & outVerifier)
     464              : {
     465            0 :     ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(outVerifier, iterations, salt, /* useRandomPIN= */ false, setupPincode));
     466              : 
     467            0 :     return CHIP_NO_ERROR;
     468              : }
     469              : 
     470            0 : ControllerDeviceInitParams DeviceController::GetControllerDeviceInitParams()
     471              : {
     472              :     return ControllerDeviceInitParams{
     473            0 :         .sessionManager = mSystemState->SessionMgr(),
     474            0 :         .exchangeMgr    = mSystemState->ExchangeMgr(),
     475            0 :     };
     476              : }
     477              : 
     478           28 : DeviceCommissioner::DeviceCommissioner() :
     479           28 :     mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this),
     480              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     481           28 :     mOnDeviceConnectionRetryCallback(OnDeviceConnectionRetryFn, this),
     482              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     483           28 :     mDeviceAttestationInformationVerificationCallback(OnDeviceAttestationInformationVerification, this),
     484           56 :     mDeviceNOCChainCallback(OnDeviceNOCChainGeneration, this), mSetUpCodePairer(this)
     485              : {
     486              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     487              :     (void) mPeerAdminJFAdminClusterEndpointId;
     488              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     489           28 : }
     490              : 
     491            0 : CHIP_ERROR DeviceCommissioner::Init(CommissionerInitParams params)
     492              : {
     493            0 :     VerifyOrReturnError(params.operationalCredentialsDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     494            0 :     mOperationalCredentialsDelegate = params.operationalCredentialsDelegate;
     495            0 :     ReturnErrorOnFailure(DeviceController::Init(params));
     496              : 
     497            0 :     mPairingDelegate = params.pairingDelegate;
     498              : 
     499              :     // Configure device attestation validation
     500            0 :     mDeviceAttestationVerifier = params.deviceAttestationVerifier;
     501            0 :     if (mDeviceAttestationVerifier == nullptr)
     502              :     {
     503            0 :         mDeviceAttestationVerifier = Credentials::GetDeviceAttestationVerifier();
     504            0 :         if (mDeviceAttestationVerifier == nullptr)
     505              :         {
     506            0 :             ChipLogError(Controller,
     507              :                          "Missing DeviceAttestationVerifier configuration at DeviceCommissioner init and none set with "
     508              :                          "Credentials::SetDeviceAttestationVerifier()!");
     509            0 :             return CHIP_ERROR_INVALID_ARGUMENT;
     510              :         }
     511              : 
     512              :         // We fell back on a default from singleton accessor.
     513            0 :         ChipLogProgress(Controller,
     514              :                         "*** Missing DeviceAttestationVerifier configuration at DeviceCommissioner init: using global default, "
     515              :                         "consider passing one in CommissionerInitParams.");
     516              :     }
     517              : 
     518            0 :     if (params.defaultCommissioner != nullptr)
     519              :     {
     520            0 :         mDefaultCommissioner = params.defaultCommissioner;
     521              :     }
     522              :     // Otherwise leave it pointing to mAutoCommissioner.
     523              : 
     524              : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
     525              :     mUdcTransportMgr = chip::Platform::New<UdcTransportMgr>();
     526              :     ReturnErrorOnFailure(mUdcTransportMgr->Init(Transport::UdpListenParameters(mSystemState->UDPEndPointManager())
     527              :                                                     .SetAddressType(Inet::IPAddressType::kIPv6)
     528              :                                                     .SetListenPort(static_cast<uint16_t>(mUdcListenPort))
     529              : #if INET_CONFIG_ENABLE_IPV4
     530              :                                                     ,
     531              :                                                 Transport::UdpListenParameters(mSystemState->UDPEndPointManager())
     532              :                                                     .SetAddressType(Inet::IPAddressType::kIPv4)
     533              :                                                     .SetListenPort(static_cast<uint16_t>(mUdcListenPort))
     534              : #endif // INET_CONFIG_ENABLE_IPV4
     535              :                                                     ));
     536              : 
     537              :     mUdcServer = chip::Platform::New<UserDirectedCommissioningServer>();
     538              :     mUdcTransportMgr->SetSessionManager(mUdcServer);
     539              :     mUdcServer->SetTransportManager(mUdcTransportMgr);
     540              : 
     541              :     mUdcServer->SetInstanceNameResolver(this);
     542              : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
     543              : 
     544            0 :     mSetUpCodePairer.SetSystemLayer(mSystemState->SystemLayer());
     545              : #if CONFIG_NETWORK_LAYER_BLE
     546            0 :     mSetUpCodePairer.SetBleLayer(mSystemState->BleLayer());
     547              : #endif // CONFIG_NETWORK_LAYER_BLE
     548              : 
     549            0 :     return CHIP_NO_ERROR;
     550              : }
     551              : 
     552            0 : void DeviceCommissioner::Shutdown()
     553              : {
     554            0 :     VerifyOrReturn(mState != State::NotInitialized);
     555              : 
     556            0 :     ChipLogDetail(Controller, "Shutting down the commissioner");
     557              : 
     558            0 :     mSetUpCodePairer.StopPairing();
     559              : 
     560              :     // Check to see if pairing in progress before shutting down
     561            0 :     CommissioneeDeviceProxy * device = mDeviceInPASEEstablishment;
     562            0 :     if (device != nullptr && device->IsSessionSetupInProgress())
     563              :     {
     564            0 :         ChipLogDetail(Controller, "Setup in progress, stopping setup before shutting down");
     565            0 :         OnSessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
     566              :     }
     567              : 
     568            0 :     CancelCommissioningInteractions();
     569              : 
     570              : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
     571              :     if (mUdcTransportMgr != nullptr)
     572              :     {
     573              :         chip::Platform::Delete(mUdcTransportMgr);
     574              :         mUdcTransportMgr = nullptr;
     575              :     }
     576              :     if (mUdcServer != nullptr)
     577              :     {
     578              :         mUdcServer->SetInstanceNameResolver(nullptr);
     579              :         chip::Platform::Delete(mUdcServer);
     580              :         mUdcServer = nullptr;
     581              :     }
     582              : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
     583              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
     584            0 :     WiFiPAF::WiFiPAFLayer::GetWiFiPAFLayer().Shutdown();
     585              : #endif
     586              : 
     587              :     // Release everything from the commissionee device pool here.
     588              :     // Make sure to use ReleaseCommissioneeDevice so we don't keep dangling
     589              :     // pointers to the device objects.
     590            0 :     mCommissioneeDevicePool.ForEachActiveObject([this](auto * commissioneeDevice) {
     591            0 :         ReleaseCommissioneeDevice(commissioneeDevice);
     592            0 :         return Loop::Continue;
     593              :     });
     594              : 
     595            0 :     DeviceController::Shutdown();
     596              : }
     597              : 
     598            0 : CommissioneeDeviceProxy * DeviceCommissioner::FindCommissioneeDevice(NodeId id)
     599              : {
     600              :     MATTER_TRACE_SCOPE("FindCommissioneeDevice", "DeviceCommissioner");
     601            0 :     CommissioneeDeviceProxy * foundDevice = nullptr;
     602            0 :     mCommissioneeDevicePool.ForEachActiveObject([&](auto * deviceProxy) {
     603            0 :         if (deviceProxy->GetDeviceId() == id || deviceProxy->GetTemporaryCommissioningId() == id)
     604              :         {
     605            0 :             foundDevice = deviceProxy;
     606            0 :             return Loop::Break;
     607              :         }
     608            0 :         return Loop::Continue;
     609              :     });
     610              : 
     611            0 :     return foundDevice;
     612              : }
     613              : 
     614            0 : CommissioneeDeviceProxy * DeviceCommissioner::FindCommissioneeDevice(const Transport::PeerAddress & peerAddress)
     615              : {
     616            0 :     CommissioneeDeviceProxy * foundDevice = nullptr;
     617            0 :     mCommissioneeDevicePool.ForEachActiveObject([&](auto * deviceProxy) {
     618            0 :         if (deviceProxy->GetPeerAddress() == peerAddress)
     619              :         {
     620            0 :             foundDevice = deviceProxy;
     621            0 :             return Loop::Break;
     622              :         }
     623            0 :         return Loop::Continue;
     624              :     });
     625              : 
     626            0 :     return foundDevice;
     627              : }
     628              : 
     629            0 : void DeviceCommissioner::ReleaseCommissioneeDevice(CommissioneeDeviceProxy * device)
     630              : {
     631              : #if CONFIG_NETWORK_LAYER_BLE
     632            0 :     if (mSystemState->BleLayer() != nullptr && device->GetDeviceTransportType() == Transport::Type::kBle)
     633              :     {
     634              :         // We only support one BLE connection, so if this is BLE, close it
     635            0 :         ChipLogProgress(Discovery, "Closing all BLE connections");
     636            0 :         mSystemState->BleLayer()->CloseAllBleConnections();
     637              :     }
     638              : #endif
     639              : 
     640              : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
     641              :     Nfc::NFCReaderTransport * readerTransport = DeviceLayer::Internal::NFCCommissioningMgr().GetNFCReaderTransport();
     642              :     if (readerTransport)
     643              :     {
     644              :         ChipLogProgress(Controller, "Stopping discovery of all NFC tags");
     645              :         TEMPORARY_RETURN_IGNORED readerTransport->StopDiscoveringTags();
     646              :     }
     647              : #endif
     648              : 
     649              :     // Make sure that there will be no dangling pointer
     650            0 :     if (mDeviceInPASEEstablishment == device)
     651              :     {
     652            0 :         mDeviceInPASEEstablishment = nullptr;
     653              :     }
     654            0 :     if (mDeviceBeingCommissioned == device)
     655              :     {
     656            0 :         mDeviceBeingCommissioned = nullptr;
     657              :     }
     658              : 
     659              :     // Release the commissionee device after we have nulled out our pointers,
     660              :     // because that can call back in to us with error notifications as the
     661              :     // session is released.
     662            0 :     mCommissioneeDevicePool.ReleaseObject(device);
     663            0 : }
     664              : 
     665            0 : CHIP_ERROR DeviceCommissioner::GetDeviceBeingCommissioned(NodeId deviceId, CommissioneeDeviceProxy ** out_device)
     666              : {
     667            0 :     VerifyOrReturnError(out_device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     668            0 :     CommissioneeDeviceProxy * device = FindCommissioneeDevice(deviceId);
     669              : 
     670            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     671              : 
     672            0 :     *out_device = device;
     673              : 
     674            0 :     return CHIP_NO_ERROR;
     675              : }
     676              : 
     677            0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * setUpCode, const CommissioningParameters & params,
     678              :                                           DiscoveryType discoveryType, Optional<Dnssd::CommonResolutionData> resolutionData,
     679              :                                           Optional<SetUpCodePairer::ThreadMeshcopCommissionParameters> meshcopCommissionParams)
     680              : {
     681              :     MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
     682              : #if CHIP_SUPPORT_THREAD_MESHCOP
     683            0 :     if (meshcopCommissionParams.HasValue())
     684              :     {
     685            0 :         mSetUpCodePairer.SetThreadMeshcopCommissionParamsAndProxy(meshcopCommissionParams.Value(), &mThreadMeshcopCommissionProxy);
     686              :     }
     687              : #endif
     688            0 :     ReturnErrorOnFailure(mDefaultCommissioner->SetCommissioningParameters(params));
     689              : 
     690            0 :     return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode, SetupCodePairerBehaviour::kCommission, discoveryType,
     691            0 :                                        resolutionData);
     692              : }
     693              : 
     694            0 : CHIP_ERROR DeviceCommissioner::GetLastThreadMeshcopDiscoveryDiagnosticJson(char * buffer, size_t bufferSize)
     695              : {
     696              : #if CHIP_SUPPORT_THREAD_MESHCOP
     697            0 :     VerifyOrReturnError(buffer != nullptr && bufferSize > 0, CHIP_ERROR_INVALID_ARGUMENT);
     698              : 
     699            0 :     const std::string json = mThreadMeshcopCommissionProxy.GetLastDiscoveryDiagnosticJson();
     700            0 :     VerifyOrReturnError(json.size() < bufferSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     701            0 :     Platform::CopyString(buffer, bufferSize, json.c_str());
     702            0 :     return CHIP_NO_ERROR;
     703              : #else
     704              :     return CHIP_ERROR_NOT_IMPLEMENTED;
     705              : #endif // CHIP_SUPPORT_THREAD_MESHCOP
     706            0 : }
     707              : 
     708            0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * setUpCode, DiscoveryType discoveryType,
     709              :                                           Optional<Dnssd::CommonResolutionData> resolutionData)
     710              : {
     711              :     MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
     712            0 :     return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode, SetupCodePairerBehaviour::kCommission, discoveryType,
     713            0 :                                        resolutionData);
     714              : }
     715              : 
     716            0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & params)
     717              : {
     718              :     MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
     719            0 :     ReturnErrorOnFailureWithMetric(kMetricDeviceCommissionerCommission, EstablishPASEConnection(remoteDeviceId, params));
     720            0 :     auto errorCode = Commission(remoteDeviceId);
     721            0 :     VerifyOrDoWithMetric(kMetricDeviceCommissionerCommission, CHIP_NO_ERROR == errorCode, errorCode);
     722            0 :     return errorCode;
     723              : }
     724              : 
     725              : #if CHIP_SUPPORT_THREAD_MESHCOP
     726            0 : CHIP_ERROR DeviceCommissioner::PairThreadMeshcop(RendezvousParameters & rendezvousParams,
     727              :                                                  CommissioningParameters & commissioningParams)
     728              : {
     729            0 :     VerifyOrReturnError(rendezvousParams.GetSetupDiscriminator().has_value(), CHIP_ERROR_INVALID_ARGUMENT);
     730            0 :     VerifyOrReturnError(commissioningParams.GetThreadOperationalDataset().HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
     731            0 :     auto discriminator = rendezvousParams.GetSetupDiscriminator().value();
     732            0 :     Thread::DiscoveryCode code;
     733            0 :     if (rendezvousParams.GetSetupDiscriminator().value().IsShortDiscriminator())
     734              :     {
     735            0 :         code = Thread::DiscoveryCode(discriminator.GetShortValue());
     736            0 :         ChipLogProgress(Controller, "Discovery code from short discriminator: 0x%" PRIx64, code.AsUInt64());
     737              :     }
     738              :     else
     739              :     {
     740            0 :         code = Thread::DiscoveryCode(discriminator.GetLongValue());
     741            0 :         ChipLogProgress(Controller, "Discovery code from long discriminator: 0x%" PRIx64, code.AsUInt64());
     742              :     }
     743              : 
     744              :     uint8_t pskcBuffer[Thread::kSizePSKc];
     745            0 :     ByteSpan pskc(pskcBuffer);
     746              :     {
     747            0 :         Thread::OperationalDatasetView dataset;
     748            0 :         ReturnErrorOnFailure(dataset.Init(commissioningParams.GetThreadOperationalDataset().Value()));
     749              : 
     750            0 :         ReturnErrorOnFailure(dataset.GetPSKc(pskcBuffer));
     751              :     }
     752              : 
     753              :     {
     754            0 :         Dnssd::DiscoveredNodeData discoveredNodeData;
     755            0 :         ReturnErrorOnFailure(mThreadMeshcopCommissionProxy.Discover(pskc, rendezvousParams.GetPeerAddress(), code, discriminator,
     756              :                                                                     discoveredNodeData, 30));
     757              : 
     758            0 :         ChipLogProgress(Controller, "Joiner discovered");
     759            0 :         OnNodeDiscovered(discoveredNodeData);
     760            0 :     }
     761            0 :     return CHIP_NO_ERROR;
     762              : }
     763              : #endif // CHIP_SUPPORT_THREAD_MESHCOP
     764              : 
     765            0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams,
     766              :                                           CommissioningParameters & commissioningParams)
     767              : {
     768              :     MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
     769              : #if CHIP_SUPPORT_THREAD_MESHCOP
     770            0 :     if (rendezvousParams.GetPeerAddress().GetTransportType() == Transport::Type::kThreadMeshcop)
     771              :     {
     772            0 :         return PairThreadMeshcop(rendezvousParams, commissioningParams);
     773              :     }
     774              : #endif
     775            0 :     ReturnErrorOnFailureWithMetric(kMetricDeviceCommissionerCommission, EstablishPASEConnection(remoteDeviceId, rendezvousParams));
     776            0 :     auto errorCode = Commission(remoteDeviceId, commissioningParams);
     777            0 :     VerifyOrDoWithMetric(kMetricDeviceCommissionerCommission, CHIP_NO_ERROR == errorCode, errorCode);
     778            0 :     return errorCode;
     779              : }
     780              : 
     781              : CHIP_ERROR
     782            0 : DeviceCommissioner::EstablishPASEConnection(NodeId remoteDeviceId, const char * setUpCode, DiscoveryType discoveryType,
     783              :                                             Optional<Dnssd::CommonResolutionData> resolutionData,
     784              :                                             Optional<SetUpCodePairer::ThreadMeshcopCommissionParameters> meshcopCommissionParams)
     785              : {
     786              :     MATTER_TRACE_SCOPE("EstablishPASEConnection", "DeviceCommissioner");
     787              : #if CHIP_SUPPORT_THREAD_MESHCOP
     788            0 :     if (meshcopCommissionParams.HasValue())
     789              :     {
     790            0 :         mSetUpCodePairer.SetThreadMeshcopCommissionParamsAndProxy(meshcopCommissionParams.Value(), &mThreadMeshcopCommissionProxy);
     791              :     }
     792              : #endif
     793            0 :     return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode, SetupCodePairerBehaviour::kPaseOnly, discoveryType,
     794            0 :                                        resolutionData);
     795              : }
     796              : 
     797            0 : CHIP_ERROR DeviceCommissioner::EstablishPASEConnection(NodeId remoteDeviceId, RendezvousParameters & params)
     798              : {
     799              :     MATTER_TRACE_SCOPE("EstablishPASEConnection", "DeviceCommissioner");
     800              :     MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissionerPASESession);
     801              : 
     802            0 :     CHIP_ERROR err                     = CHIP_NO_ERROR;
     803            0 :     CommissioneeDeviceProxy * device   = nullptr;
     804            0 :     CommissioneeDeviceProxy * current  = nullptr;
     805            0 :     Transport::PeerAddress peerAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
     806              : 
     807            0 :     Messaging::ExchangeContext * exchangeCtxt = nullptr;
     808            0 :     Optional<SessionHandle> session;
     809              : 
     810            0 :     VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE);
     811            0 :     VerifyOrExit(mDeviceInPASEEstablishment == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
     812              : 
     813              :     // TODO(#13940): We need to specify the peer address for BLE transport in bindings.
     814            0 :     if (params.GetPeerAddress().GetTransportType() == Transport::Type::kBle ||
     815            0 :         params.GetPeerAddress().GetTransportType() == Transport::Type::kUndefined)
     816              :     {
     817              : #if CONFIG_NETWORK_LAYER_BLE
     818              : #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
     819              :         ConnectBleTransportToSelf();
     820              : #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
     821            0 :         if (!params.HasBleLayer())
     822              :         {
     823            0 :             params.SetPeerAddress(Transport::PeerAddress::BLE());
     824              :         }
     825            0 :         peerAddress = Transport::PeerAddress::BLE();
     826              : #endif // CONFIG_NETWORK_LAYER_BLE
     827              :     }
     828            0 :     else if (params.GetPeerAddress().GetTransportType() == Transport::Type::kTcp ||
     829            0 :              params.GetPeerAddress().GetTransportType() == Transport::Type::kUdp)
     830              :     {
     831            0 :         peerAddress = Transport::PeerAddress::UDP(params.GetPeerAddress().GetIPAddress(), params.GetPeerAddress().GetPort(),
     832            0 :                                                   params.GetPeerAddress().GetInterface());
     833              :     }
     834              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
     835            0 :     else if (params.GetPeerAddress().GetTransportType() == Transport::Type::kWiFiPAF)
     836              :     {
     837            0 :         peerAddress = Transport::PeerAddress::WiFiPAF(remoteDeviceId);
     838              :     }
     839              : #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
     840              : 
     841            0 :     current = FindCommissioneeDevice(peerAddress);
     842            0 :     if (current != nullptr)
     843              :     {
     844            0 :         if (current->GetDeviceId() == remoteDeviceId)
     845              :         {
     846              :             // We might be able to just reuse its connection if it has one or is
     847              :             // working on one.
     848            0 :             if (current->IsSecureConnected())
     849              :             {
     850            0 :                 if (mPairingDelegate)
     851              :                 {
     852              :                     // We already have an open secure session to this device, call the callback immediately and early return.
     853              :                     // We don't know what the right RendezvousParameters are here.
     854            0 :                     mPairingDelegate->OnPairingComplete(CHIP_NO_ERROR, std::nullopt, std::nullopt);
     855              :                 }
     856              :                 MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, CHIP_NO_ERROR);
     857            0 :                 return CHIP_NO_ERROR;
     858              :             }
     859            0 :             if (current->IsSessionSetupInProgress())
     860              :             {
     861              :                 // We're not connected yet, but we're in the process of connecting. Pairing delegate will get a callback when
     862              :                 // connection completes
     863            0 :                 return CHIP_NO_ERROR;
     864              :             }
     865              :         }
     866              : 
     867              :         // Either the consumer wants to assign a different device id to this
     868              :         // peer address now (so we can't reuse the commissionee device we have
     869              :         // already) or something has gone strange. Delete the old device, try
     870              :         // again.
     871            0 :         ChipLogError(Controller, "Found unconnected device, removing");
     872            0 :         ReleaseCommissioneeDevice(current);
     873              :     }
     874              : 
     875            0 :     device = mCommissioneeDevicePool.CreateObject();
     876            0 :     VerifyOrExit(device != nullptr, err = CHIP_ERROR_NO_MEMORY);
     877              : 
     878            0 :     mDeviceInPASEEstablishment = device;
     879            0 :     device->Init(GetControllerDeviceInitParams(), remoteDeviceId, peerAddress);
     880            0 :     device->UpdateDeviceData(params.GetPeerAddress(), params.GetMRPConfig());
     881              : 
     882              : #if CONFIG_NETWORK_LAYER_BLE
     883            0 :     if (params.GetPeerAddress().GetTransportType() == Transport::Type::kBle)
     884              :     {
     885            0 :         if (params.HasConnectionObject())
     886              :         {
     887            0 :             SuccessOrExit(err = mSystemState->BleLayer()->NewBleConnectionByObject(params.GetConnectionObject()));
     888              :         }
     889            0 :         else if (params.HasDiscoveredObject())
     890              :         {
     891              :             // The RendezvousParameters argument needs to be recovered if the search succeed, so save them
     892              :             // for later.
     893            0 :             mRendezvousParametersForDeviceDiscoveredOverBle = params;
     894            0 :             ExitNow(err = mSystemState->BleLayer()->NewBleConnectionByObject(
     895              :                         params.GetDiscoveredObject(), this, OnDiscoveredDeviceOverBleSuccess, OnDiscoveredDeviceOverBleError));
     896              :         }
     897            0 :         else if (params.GetSetupDiscriminator().has_value())
     898              :         {
     899              :             // The RendezvousParameters argument needs to be recovered if the search succeed, so save them
     900              :             // for later.
     901            0 :             mRendezvousParametersForDeviceDiscoveredOverBle = params;
     902            0 :             auto setupDiscriminator                         = params.GetSetupDiscriminator();
     903            0 :             VerifyOrExit(setupDiscriminator.has_value(), err = CHIP_ERROR_INVALID_ARGUMENT);
     904            0 :             ExitNow(err = mSystemState->BleLayer()->NewBleConnectionByDiscriminator(
     905              :                         setupDiscriminator.value(), this, OnDiscoveredDeviceOverBleSuccess, OnDiscoveredDeviceOverBleError));
     906              :         }
     907              :         else
     908              :         {
     909            0 :             ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
     910              :         }
     911              :     }
     912              : #endif
     913              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
     914            0 :     if (params.GetPeerAddress().GetTransportType() == Transport::Type::kWiFiPAF)
     915              :     {
     916            0 :         if (DeviceLayer::ConnectivityMgr().GetWiFiPAF()->GetWiFiPAFState() != WiFiPAF::State::kConnected)
     917              :         {
     918            0 :             ChipLogProgress(Controller, "WiFi-PAF: Subscribing to the NAN-USD devices, nodeId: %" PRIu64,
     919              :                             params.GetPeerAddress().GetRemoteId());
     920            0 :             mRendezvousParametersForDeviceDiscoveredOverWiFiPAF = params;
     921            0 :             auto nodeId                                         = params.GetPeerAddress().GetRemoteId();
     922            0 :             auto setupDiscriminator                             = params.GetSetupDiscriminator();
     923            0 :             VerifyOrExit(setupDiscriminator.has_value(), ChipLogError(Controller, "WiFi-PAF: Missing setup discriminator");
     924              :                          err = CHIP_ERROR_INVALID_ARGUMENT);
     925            0 :             const SetupDiscriminator connDiscriminator(setupDiscriminator.value());
     926            0 :             VerifyOrExit(!connDiscriminator.IsShortDiscriminator(),
     927              :                          ChipLogError(Controller, "Error, Long discriminator is required");
     928              :                          err = CHIP_ERROR_INVALID_ARGUMENT);
     929            0 :             uint16_t discriminator              = connDiscriminator.GetLongValue();
     930            0 :             WiFiPAF::WiFiPAFSession sessionInfo = { .role          = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber,
     931              :                                                     .nodeId        = nodeId,
     932            0 :                                                     .discriminator = discriminator };
     933            0 :             SuccessOrExit(err = DeviceLayer::ConnectivityMgr().GetWiFiPAF()->AddPafSession(WiFiPAF::PafInfoAccess::kAccNodeInfo,
     934              :                                                                                            sessionInfo));
     935            0 :             ExitNow(err = DeviceLayer::ConnectivityMgr().WiFiPAFSubscribe(discriminator, reinterpret_cast<void *>(this),
     936              :                                                                           OnWiFiPAFSubscribeComplete, OnWiFiPAFSubscribeError));
     937              :         }
     938              :     }
     939              : #endif
     940            0 :     session = mSystemState->SessionMgr()->CreateUnauthenticatedSession(params.GetPeerAddress(), params.GetMRPConfig());
     941            0 :     VerifyOrExit(session.HasValue(), err = CHIP_ERROR_NO_MEMORY);
     942              : 
     943              :     // Allocate the exchange immediately before calling PASESession::Pair.
     944              :     //
     945              :     // PASESession::Pair takes ownership of the exchange and will free it on
     946              :     // error, but can only do this if it is actually called.  Allocating the
     947              :     // exchange context right before calling Pair ensures that if allocation
     948              :     // succeeds, PASESession has taken ownership.
     949            0 :     exchangeCtxt = mSystemState->ExchangeMgr()->NewContext(session.Value(), &device->GetPairing());
     950            0 :     VerifyOrExit(exchangeCtxt != nullptr, err = CHIP_ERROR_INTERNAL);
     951              : 
     952            0 :     err = device->GetPairing().Pair(*mSystemState->SessionMgr(), params.GetSetupPINCode(), GetLocalMRPConfig(), exchangeCtxt, this);
     953            0 :     SuccessOrExit(err);
     954              : 
     955            0 :     mRendezvousParametersForPASEEstablishment = params;
     956              : 
     957            0 : exit:
     958            0 :     if (err != CHIP_NO_ERROR)
     959              :     {
     960            0 :         if (device != nullptr)
     961              :         {
     962            0 :             ReleaseCommissioneeDevice(device);
     963              :         }
     964              :         MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, err);
     965              :     }
     966              : 
     967            0 :     return err;
     968            0 : }
     969              : 
     970              : #if CONFIG_NETWORK_LAYER_BLE
     971            0 : void DeviceCommissioner::OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj)
     972              : {
     973            0 :     auto self   = static_cast<DeviceCommissioner *>(appState);
     974            0 :     auto device = self->mDeviceInPASEEstablishment;
     975              : 
     976            0 :     if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kBle)
     977              :     {
     978            0 :         auto remoteId = device->GetDeviceId();
     979              : 
     980            0 :         auto params = self->mRendezvousParametersForDeviceDiscoveredOverBle;
     981            0 :         params.SetConnectionObject(connObj);
     982            0 :         self->mRendezvousParametersForDeviceDiscoveredOverBle = RendezvousParameters();
     983              : 
     984            0 :         self->ReleaseCommissioneeDevice(device);
     985            0 :         LogErrorOnFailure(self->EstablishPASEConnection(remoteId, params));
     986              :     }
     987            0 : }
     988              : 
     989            0 : void DeviceCommissioner::OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err)
     990              : {
     991            0 :     auto self   = static_cast<DeviceCommissioner *>(appState);
     992            0 :     auto device = self->mDeviceInPASEEstablishment;
     993              : 
     994            0 :     if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kBle)
     995              :     {
     996            0 :         self->ReleaseCommissioneeDevice(device);
     997            0 :         self->mRendezvousParametersForDeviceDiscoveredOverBle = RendezvousParameters();
     998              : 
     999              :         // Callback is required when BLE discovery fails, otherwise the caller will always be in a suspended state
    1000              :         // A better way to handle it should define a new error code
    1001            0 :         if (self->mPairingDelegate != nullptr)
    1002              :         {
    1003            0 :             self->mPairingDelegate->OnPairingComplete(err, std::nullopt, std::nullopt);
    1004              :         }
    1005              :     }
    1006            0 : }
    1007              : #endif // CONFIG_NETWORK_LAYER_BLE
    1008              : 
    1009              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
    1010            0 : void DeviceCommissioner::OnWiFiPAFSubscribeComplete(void * appState)
    1011              : {
    1012            0 :     auto self   = reinterpret_cast<DeviceCommissioner *>(appState);
    1013            0 :     auto device = self->mDeviceInPASEEstablishment;
    1014              : 
    1015            0 :     if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kWiFiPAF)
    1016              :     {
    1017            0 :         ChipLogProgress(Controller, "WiFi-PAF: Subscription Completed, dev_id = %" PRIu64, device->GetDeviceId());
    1018            0 :         auto remoteId = device->GetDeviceId();
    1019            0 :         auto params   = self->mRendezvousParametersForDeviceDiscoveredOverWiFiPAF;
    1020              : 
    1021            0 :         self->mRendezvousParametersForDeviceDiscoveredOverWiFiPAF = RendezvousParameters();
    1022            0 :         self->ReleaseCommissioneeDevice(device);
    1023            0 :         LogErrorOnFailure(self->EstablishPASEConnection(remoteId, params));
    1024              :     }
    1025            0 : }
    1026              : 
    1027            0 : void DeviceCommissioner::OnWiFiPAFSubscribeError(void * appState, CHIP_ERROR err)
    1028              : {
    1029            0 :     auto self   = (DeviceCommissioner *) appState;
    1030            0 :     auto device = self->mDeviceInPASEEstablishment;
    1031              : 
    1032            0 :     if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kWiFiPAF)
    1033              :     {
    1034            0 :         ChipLogError(Controller, "WiFi-PAF: Subscription Error, id = %" PRIu64 ", err = %" CHIP_ERROR_FORMAT, device->GetDeviceId(),
    1035              :                      err.Format());
    1036            0 :         self->ReleaseCommissioneeDevice(device);
    1037            0 :         self->mRendezvousParametersForDeviceDiscoveredOverWiFiPAF = RendezvousParameters();
    1038            0 :         if (self->mPairingDelegate != nullptr)
    1039              :         {
    1040            0 :             self->mPairingDelegate->OnPairingComplete(err, std::nullopt, std::nullopt);
    1041              :         }
    1042              :     }
    1043            0 : }
    1044              : #endif
    1045              : 
    1046            0 : CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId, CommissioningParameters & params)
    1047              : {
    1048            0 :     ReturnErrorOnFailureWithMetric(kMetricDeviceCommissionerCommission, mDefaultCommissioner->SetCommissioningParameters(params));
    1049            0 :     auto errorCode = Commission(remoteDeviceId);
    1050            0 :     VerifyOrDoWithMetric(kMetricDeviceCommissionerCommission, CHIP_NO_ERROR == errorCode, errorCode);
    1051            0 :     return errorCode;
    1052              : }
    1053              : 
    1054            0 : CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId)
    1055              : {
    1056              :     MATTER_TRACE_SCOPE("Commission", "DeviceCommissioner");
    1057              : 
    1058              : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
    1059              :     // Reset fallback from any previous commissioning session
    1060              :     mFallbackOperationalResolveResult.ClearValue();
    1061              : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
    1062              : 
    1063            0 :     CommissioneeDeviceProxy * device = FindCommissioneeDevice(remoteDeviceId);
    1064            0 :     if (device == nullptr || (!device->IsSecureConnected() && !device->IsSessionSetupInProgress()))
    1065              :     {
    1066            0 :         ChipLogError(Controller, "Invalid device for commissioning " ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
    1067            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1068              :     }
    1069            0 :     if (!device->IsSecureConnected() && device != mDeviceInPASEEstablishment)
    1070              :     {
    1071              :         // We should not end up in this state because we won't attempt to establish more than one connection at a time.
    1072            0 :         ChipLogError(Controller, "Device is not connected and not being paired " ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
    1073            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1074              :     }
    1075              : 
    1076            0 :     if (mCommissioningStage != CommissioningStage::kSecurePairing)
    1077              :     {
    1078            0 :         ChipLogError(Controller, "Commissioning already in progress (stage '%s') - not restarting",
    1079              :                      StageToString(mCommissioningStage));
    1080            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1081              :     }
    1082              : 
    1083            0 :     ChipLogProgress(Controller, "Commission called for node ID 0x" ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
    1084              : 
    1085            0 :     mDefaultCommissioner->SetOperationalCredentialsDelegate(mOperationalCredentialsDelegate);
    1086            0 :     if (device->IsSecureConnected())
    1087              :     {
    1088              :         MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissionerCommission);
    1089            0 :         ReturnErrorOnFailure(mDefaultCommissioner->StartCommissioning(this, device));
    1090              :     }
    1091              :     else
    1092              :     {
    1093            0 :         mRunCommissioningAfterConnection = true;
    1094              :     }
    1095            0 :     return CHIP_NO_ERROR;
    1096              : }
    1097              : 
    1098              : CHIP_ERROR
    1099            0 : DeviceCommissioner::ContinueCommissioningAfterDeviceAttestation(DeviceProxy * device,
    1100              :                                                                 Credentials::AttestationVerificationResult attestationResult)
    1101              : {
    1102              :     MATTER_TRACE_SCOPE("continueCommissioningDevice", "DeviceCommissioner");
    1103              : 
    1104            0 :     if (device == nullptr || device != mDeviceBeingCommissioned)
    1105              :     {
    1106            0 :         ChipLogError(Controller, "Invalid device for commissioning %p", device);
    1107            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1108              :     }
    1109            0 :     CommissioneeDeviceProxy * commissioneeDevice = FindCommissioneeDevice(device->GetDeviceId());
    1110            0 :     if (commissioneeDevice == nullptr)
    1111              :     {
    1112            0 :         ChipLogError(Controller, "Couldn't find commissionee device");
    1113            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1114              :     }
    1115            0 :     if (!commissioneeDevice->IsSecureConnected() || commissioneeDevice != mDeviceBeingCommissioned)
    1116              :     {
    1117            0 :         ChipLogError(Controller, "Invalid device for commissioning after attestation failure: 0x" ChipLogFormatX64,
    1118              :                      ChipLogValueX64(commissioneeDevice->GetDeviceId()));
    1119            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1120              :     }
    1121              : 
    1122            0 :     if (mCommissioningStage != CommissioningStage::kAttestationRevocationCheck)
    1123              :     {
    1124            0 :         ChipLogError(Controller, "Commissioning is not attestation verification phase");
    1125            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1126              :     }
    1127              : 
    1128            0 :     ChipLogProgress(Controller, "Continuing commissioning after attestation failure for device ID 0x" ChipLogFormatX64,
    1129              :                     ChipLogValueX64(commissioneeDevice->GetDeviceId()));
    1130              : 
    1131            0 :     if (attestationResult != AttestationVerificationResult::kSuccess)
    1132              :     {
    1133            0 :         ChipLogError(Controller, "Client selected error: %u for failed 'Attestation Information' for device",
    1134              :                      to_underlying(attestationResult));
    1135              : 
    1136            0 :         CommissioningDelegate::CommissioningReport report;
    1137            0 :         report.Set<AttestationErrorInfo>(attestationResult);
    1138            0 :         CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
    1139            0 :     }
    1140              :     else
    1141              :     {
    1142            0 :         ChipLogProgress(Controller, "Overriding attestation failure per client and continuing commissioning");
    1143            0 :         CommissioningStageComplete(CHIP_NO_ERROR);
    1144              :     }
    1145            0 :     return CHIP_NO_ERROR;
    1146              : }
    1147              : 
    1148              : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
    1149              : CHIP_ERROR DeviceCommissioner::ContinueCommissioningAfterConnectNetworkRequest(NodeId remoteDeviceId)
    1150              : {
    1151              :     MATTER_TRACE_SCOPE("continueCommissioningAfterConnectNetworkRequest", "DeviceCommissioner");
    1152              : 
    1153              :     // Move to kEvictPreviousCaseSessions stage since the next stage will be to find the device
    1154              :     // on the operational network
    1155              :     mCommissioningStage = CommissioningStage::kEvictPreviousCaseSessions;
    1156              : 
    1157              :     // Setup device being commissioned
    1158              :     CommissioneeDeviceProxy * device = nullptr;
    1159              :     if (!mDeviceBeingCommissioned)
    1160              :     {
    1161              :         device = mCommissioneeDevicePool.CreateObject();
    1162              :         if (!device)
    1163              :             return CHIP_ERROR_NO_MEMORY;
    1164              : 
    1165              :         Transport::PeerAddress peerAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
    1166              :         device->Init(GetControllerDeviceInitParams(), remoteDeviceId, peerAddress);
    1167              :         mDeviceBeingCommissioned = device;
    1168              :     }
    1169              : 
    1170              :     mDefaultCommissioner->SetOperationalCredentialsDelegate(mOperationalCredentialsDelegate);
    1171              : 
    1172              :     ChipLogProgress(Controller, "Continuing commissioning after connect to network complete for device ID 0x" ChipLogFormatX64,
    1173              :                     ChipLogValueX64(remoteDeviceId));
    1174              : 
    1175              :     MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissioningOperationalSetup);
    1176              :     CHIP_ERROR err = mDefaultCommissioner->StartCommissioning(this, device);
    1177              :     if (err != CHIP_NO_ERROR)
    1178              :     {
    1179              :         MATTER_LOG_METRIC_END(kMetricDeviceCommissioningOperationalSetup, err);
    1180              :     }
    1181              :     return err;
    1182              : }
    1183              : #endif
    1184              : 
    1185            0 : CHIP_ERROR DeviceCommissioner::StopPairing(NodeId remoteDeviceId)
    1186              : {
    1187            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1188            0 :     VerifyOrReturnError(remoteDeviceId != kUndefinedNodeId, CHIP_ERROR_INVALID_ARGUMENT);
    1189              : 
    1190            0 :     ChipLogProgress(Controller, "StopPairing called for node ID 0x" ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
    1191              : 
    1192              :     // If we're still in the process of discovering the device, just stop the SetUpCodePairer
    1193            0 :     if (mSetUpCodePairer.StopPairing(remoteDeviceId))
    1194              :     {
    1195            0 :         mRunCommissioningAfterConnection = false;
    1196            0 :         OnSessionEstablishmentError(CHIP_ERROR_CANCELLED);
    1197            0 :         return CHIP_NO_ERROR;
    1198              :     }
    1199              : 
    1200              :     // Otherwise we might be pairing and / or commissioning it.
    1201            0 :     CommissioneeDeviceProxy * device = FindCommissioneeDevice(remoteDeviceId);
    1202            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR);
    1203              : 
    1204            0 :     if (mDeviceBeingCommissioned == device)
    1205              :     {
    1206            0 :         CancelCommissioningInteractions();
    1207            0 :         CommissioningStageComplete(CHIP_ERROR_CANCELLED);
    1208              :     }
    1209              :     else
    1210              :     {
    1211            0 :         ReleaseCommissioneeDevice(device);
    1212              :     }
    1213            0 :     return CHIP_NO_ERROR;
    1214              : }
    1215              : 
    1216            0 : void DeviceCommissioner::CancelCommissioningInteractions()
    1217              : {
    1218            0 :     if (mReadClient)
    1219              :     {
    1220            0 :         ChipLogDetail(Controller, "Cancelling read request for step '%s'", StageToString(mCommissioningStage));
    1221            0 :         mReadClient.reset(); // destructor cancels
    1222            0 :         mAttributeCache.reset();
    1223              :     }
    1224            0 :     if (mInvokeCancelFn)
    1225              :     {
    1226            0 :         ChipLogDetail(Controller, "Cancelling command invocation for step '%s'", StageToString(mCommissioningStage));
    1227            0 :         mInvokeCancelFn();
    1228            0 :         mInvokeCancelFn = nullptr;
    1229              :     }
    1230            0 :     if (mWriteCancelFn)
    1231              :     {
    1232            0 :         ChipLogDetail(Controller, "Cancelling write request for step '%s'", StageToString(mCommissioningStage));
    1233            0 :         mWriteCancelFn();
    1234            0 :         mWriteCancelFn = nullptr;
    1235              :     }
    1236            0 :     if (mOnDeviceConnectedCallback.IsRegistered())
    1237              :     {
    1238            0 :         ChipLogDetail(Controller, "Cancelling CASE setup for step '%s'", StageToString(mCommissioningStage));
    1239            0 :         CancelCASECallbacks();
    1240              :     }
    1241            0 : }
    1242              : 
    1243            0 : void DeviceCommissioner::CancelCASECallbacks()
    1244              : {
    1245            0 :     mOnDeviceConnectedCallback.Cancel();
    1246            0 :     mOnDeviceConnectionFailureCallback.Cancel();
    1247              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
    1248            0 :     mOnDeviceConnectionRetryCallback.Cancel();
    1249              : #endif
    1250            0 : }
    1251              : 
    1252            0 : CHIP_ERROR DeviceCommissioner::UnpairDevice(NodeId remoteDeviceId)
    1253              : {
    1254              :     MATTER_TRACE_SCOPE("UnpairDevice", "DeviceCommissioner");
    1255            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1256              : 
    1257            0 :     return AutoCurrentFabricRemover::RemoveCurrentFabric(this, remoteDeviceId);
    1258              : }
    1259              : 
    1260            1 : void DeviceCommissioner::RendezvousCleanup(CHIP_ERROR status)
    1261              : {
    1262            1 :     if (mDeviceInPASEEstablishment != nullptr)
    1263              :     {
    1264              :         // Release the commissionee device. For BLE, this is stored,
    1265              :         // for IP commissioning, we have taken a reference to the
    1266              :         // operational node to send the completion command.
    1267            0 :         ReleaseCommissioneeDevice(mDeviceInPASEEstablishment);
    1268              : 
    1269            0 :         if (mPairingDelegate != nullptr)
    1270              :         {
    1271            0 :             mPairingDelegate->OnPairingComplete(status, std::nullopt, std::nullopt);
    1272              :         }
    1273              :     }
    1274            1 : }
    1275              : 
    1276            1 : void DeviceCommissioner::OnSessionEstablishmentError(CHIP_ERROR err)
    1277              : {
    1278              :     MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, err);
    1279              : 
    1280            1 :     mRendezvousParametersForPASEEstablishment.reset();
    1281              : 
    1282            1 :     if (mPairingDelegate != nullptr)
    1283              :     {
    1284            0 :         mPairingDelegate->OnStatusUpdate(DevicePairingDelegate::SecurePairingFailed);
    1285              :     }
    1286              : 
    1287            1 :     RendezvousCleanup(err);
    1288            1 : }
    1289              : 
    1290            0 : void DeviceCommissioner::OnSessionEstablished(const SessionHandle & session)
    1291              : {
    1292              :     // PASE session established.
    1293            0 :     CommissioneeDeviceProxy * device = mDeviceInPASEEstablishment;
    1294              : 
    1295              :     // We are in the callback for this pairing. Reset so we can pair another device.
    1296            0 :     mDeviceInPASEEstablishment = nullptr;
    1297              : 
    1298              :     // Make sure to clear out mRendezvousParametersForPASEEstablishment no
    1299              :     // matter what.
    1300            0 :     std::optional<RendezvousParameters> paseParameters;
    1301            0 :     paseParameters.swap(mRendezvousParametersForPASEEstablishment);
    1302              : 
    1303            0 :     VerifyOrReturn(device != nullptr, OnSessionEstablishmentError(CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR));
    1304              : 
    1305            0 :     CHIP_ERROR err = device->SetConnected(session);
    1306            0 :     if (err != CHIP_NO_ERROR)
    1307              :     {
    1308            0 :         ChipLogError(Controller, "Failed in setting up secure channel: %" CHIP_ERROR_FORMAT, err.Format());
    1309            0 :         OnSessionEstablishmentError(err);
    1310            0 :         return;
    1311              :     }
    1312              : 
    1313            0 :     ChipLogDetail(Controller, "Remote device completed SPAKE2+ handshake");
    1314              : 
    1315              :     MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, CHIP_NO_ERROR);
    1316            0 :     if (mPairingDelegate != nullptr)
    1317              :     {
    1318              :         // If we started with a string payload, then at this point mPairingDelegate is
    1319              :         // mSetUpCodePairer, and it will provide the right SetupPayload argument to
    1320              :         // OnPairingComplete as needed.  If mPairingDelegate is not
    1321              :         // mSetUpCodePairer, then we don't have a SetupPayload to provide.
    1322            0 :         mPairingDelegate->OnPairingComplete(CHIP_NO_ERROR, paseParameters, std::nullopt);
    1323              :     }
    1324              : 
    1325            0 :     if (mRunCommissioningAfterConnection)
    1326              :     {
    1327            0 :         mRunCommissioningAfterConnection = false;
    1328              :         MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissionerCommission);
    1329            0 :         ReturnAndLogOnFailure(mDefaultCommissioner->StartCommissioning(this, device), Controller, "Failed to start commissioning");
    1330              :     }
    1331              : }
    1332              : 
    1333            0 : CHIP_ERROR DeviceCommissioner::SendCertificateChainRequestCommand(DeviceProxy * device,
    1334              :                                                                   Credentials::CertificateType certificateType,
    1335              :                                                                   Optional<System::Clock::Timeout> timeout)
    1336              : {
    1337              :     MATTER_TRACE_SCOPE("SendCertificateChainRequestCommand", "DeviceCommissioner");
    1338            0 :     ChipLogDetail(Controller, "Sending Certificate Chain request to %p device", device);
    1339            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1340              : 
    1341            0 :     OperationalCredentials::Commands::CertificateChainRequest::Type request;
    1342            0 :     request.certificateType = static_cast<OperationalCredentials::CertificateChainTypeEnum>(certificateType);
    1343            0 :     return SendCommissioningCommand(device, request, OnCertificateChainResponse, OnCertificateChainFailureResponse, kRootEndpointId,
    1344            0 :                                     timeout);
    1345              : }
    1346              : 
    1347            0 : void DeviceCommissioner::OnCertificateChainFailureResponse(void * context, CHIP_ERROR error)
    1348              : {
    1349              :     MATTER_TRACE_SCOPE("OnCertificateChainFailureResponse", "DeviceCommissioner");
    1350            0 :     ChipLogProgress(Controller, "Device failed to receive the Certificate Chain request Response: %" CHIP_ERROR_FORMAT,
    1351              :                     error.Format());
    1352            0 :     DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
    1353            0 :     commissioner->CommissioningStageComplete(error);
    1354            0 : }
    1355              : 
    1356            0 : void DeviceCommissioner::OnCertificateChainResponse(
    1357              :     void * context, const chip::app::Clusters::OperationalCredentials::Commands::CertificateChainResponse::DecodableType & response)
    1358              : {
    1359              :     MATTER_TRACE_SCOPE("OnCertificateChainResponse", "DeviceCommissioner");
    1360            0 :     ChipLogProgress(Controller, "Received certificate chain from the device");
    1361            0 :     DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
    1362              : 
    1363            0 :     CommissioningDelegate::CommissioningReport report;
    1364            0 :     report.Set<RequestedCertificate>(RequestedCertificate(response.certificate));
    1365              : 
    1366            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
    1367            0 : }
    1368              : 
    1369            0 : CHIP_ERROR DeviceCommissioner::SendAttestationRequestCommand(DeviceProxy * device, const ByteSpan & attestationNonce,
    1370              :                                                              Optional<System::Clock::Timeout> timeout)
    1371              : {
    1372              :     MATTER_TRACE_SCOPE("SendAttestationRequestCommand", "DeviceCommissioner");
    1373            0 :     ChipLogDetail(Controller, "Sending Attestation request to %p device", device);
    1374            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1375              : 
    1376            0 :     OperationalCredentials::Commands::AttestationRequest::Type request;
    1377            0 :     request.attestationNonce = attestationNonce;
    1378              : 
    1379            0 :     ReturnErrorOnFailure(
    1380              :         SendCommissioningCommand(device, request, OnAttestationResponse, OnAttestationFailureResponse, kRootEndpointId, timeout));
    1381            0 :     ChipLogDetail(Controller, "Sent Attestation request, waiting for the Attestation Information");
    1382            0 :     return CHIP_NO_ERROR;
    1383              : }
    1384              : 
    1385            0 : void DeviceCommissioner::OnAttestationFailureResponse(void * context, CHIP_ERROR error)
    1386              : {
    1387              :     MATTER_TRACE_SCOPE("OnAttestationFailureResponse", "DeviceCommissioner");
    1388            0 :     ChipLogProgress(Controller, "Device failed to receive the Attestation Information Response: %" CHIP_ERROR_FORMAT,
    1389              :                     error.Format());
    1390            0 :     DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
    1391            0 :     commissioner->CommissioningStageComplete(error);
    1392            0 : }
    1393              : 
    1394            0 : void DeviceCommissioner::OnAttestationResponse(void * context,
    1395              :                                                const OperationalCredentials::Commands::AttestationResponse::DecodableType & data)
    1396              : {
    1397              :     MATTER_TRACE_SCOPE("OnAttestationResponse", "DeviceCommissioner");
    1398            0 :     ChipLogProgress(Controller, "Received Attestation Information from the device");
    1399            0 :     DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
    1400              : 
    1401            0 :     CommissioningDelegate::CommissioningReport report;
    1402            0 :     report.Set<AttestationResponse>(AttestationResponse(data.attestationElements, data.attestationSignature));
    1403            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
    1404            0 : }
    1405              : 
    1406            0 : void DeviceCommissioner::OnDeviceAttestationInformationVerification(
    1407              :     void * context, const Credentials::DeviceAttestationVerifier::AttestationInfo & info, AttestationVerificationResult result)
    1408              : {
    1409              :     MATTER_TRACE_SCOPE("OnDeviceAttestationInformationVerification", "DeviceCommissioner");
    1410            0 :     DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
    1411              : 
    1412            0 :     if (commissioner->mCommissioningStage == CommissioningStage::kAttestationVerification)
    1413              :     {
    1414              :         // Check for revoked DAC Chain before calling delegate. Enter next stage.
    1415              : 
    1416            0 :         CommissioningDelegate::CommissioningReport report;
    1417            0 :         report.Set<AttestationErrorInfo>(result);
    1418              : 
    1419            0 :         return commissioner->CommissioningStageComplete(
    1420            0 :             result == AttestationVerificationResult::kSuccess ? CHIP_NO_ERROR : CHIP_ERROR_FAILED_DEVICE_ATTESTATION, report);
    1421            0 :     }
    1422              : 
    1423            0 :     if (!commissioner->mDeviceBeingCommissioned)
    1424              :     {
    1425            0 :         ChipLogError(Controller, "Device attestation verification result received when we're not commissioning a device");
    1426            0 :         return;
    1427              :     }
    1428              : 
    1429            0 :     auto & params = commissioner->mDefaultCommissioner->GetCommissioningParameters();
    1430            0 :     Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
    1431              : 
    1432            0 :     if (params.GetCompletionStatus().attestationResult.HasValue())
    1433              :     {
    1434            0 :         auto previousResult = params.GetCompletionStatus().attestationResult.Value();
    1435            0 :         if (previousResult != AttestationVerificationResult::kSuccess)
    1436              :         {
    1437            0 :             result = previousResult;
    1438              :         }
    1439              :     }
    1440              : 
    1441            0 :     if (result != AttestationVerificationResult::kSuccess)
    1442              :     {
    1443            0 :         CommissioningDelegate::CommissioningReport report;
    1444            0 :         report.Set<AttestationErrorInfo>(result);
    1445            0 :         if (result == AttestationVerificationResult::kNotImplemented)
    1446              :         {
    1447            0 :             ChipLogError(Controller,
    1448              :                          "Failed in verifying 'Attestation Information' command received from the device due to default "
    1449              :                          "DeviceAttestationVerifier Class not being overridden by a real implementation.");
    1450            0 :             commissioner->CommissioningStageComplete(CHIP_ERROR_NOT_IMPLEMENTED, report);
    1451            0 :             return;
    1452              :         }
    1453              : 
    1454            0 :         ChipLogError(Controller, "Failed in verifying 'Attestation Information' command received from the device: err %hu (%s)",
    1455              :                      static_cast<uint16_t>(result), GetAttestationResultDescription(result));
    1456              :         // Go look at AttestationVerificationResult enum in src/credentials/attestation_verifier/DeviceAttestationVerifier.h to
    1457              :         // understand the errors.
    1458              : 
    1459              :         // If a device attestation status delegate is installed, delegate handling of failure to the client and let them
    1460              :         // decide on whether to proceed further or not.
    1461            0 :         if (deviceAttestationDelegate)
    1462              :         {
    1463            0 :             commissioner->ExtendArmFailSafeForDeviceAttestation(info, result);
    1464              :         }
    1465              :         else
    1466              :         {
    1467            0 :             commissioner->CommissioningStageComplete(CHIP_ERROR_FAILED_DEVICE_ATTESTATION, report);
    1468              :         }
    1469            0 :     }
    1470              :     else
    1471              :     {
    1472            0 :         if (deviceAttestationDelegate && deviceAttestationDelegate->ShouldWaitAfterDeviceAttestation())
    1473              :         {
    1474            0 :             commissioner->ExtendArmFailSafeForDeviceAttestation(info, result);
    1475              :         }
    1476              :         else
    1477              :         {
    1478            0 :             ChipLogProgress(Controller, "Successfully validated 'Attestation Information' command received from the device.");
    1479            0 :             commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
    1480              :         }
    1481              :     }
    1482              : }
    1483              : 
    1484            0 : void DeviceCommissioner::OnArmFailSafeExtendedForDeviceAttestation(
    1485              :     void * context, const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType &)
    1486              : {
    1487            0 :     ChipLogProgress(Controller, "Successfully extended fail-safe timer to handle DA failure");
    1488            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1489              : 
    1490              :     // We have completed our command invoke, but we're not going to finish the
    1491              :     // commissioning step until our client examines the attestation
    1492              :     // information.  Clear out mInvokeCancelFn (which points at the
    1493              :     // CommandSender we just finished using) now, so it's not dangling.
    1494            0 :     commissioner->mInvokeCancelFn = nullptr;
    1495              : 
    1496            0 :     commissioner->HandleDeviceAttestationCompleted();
    1497            0 : }
    1498              : 
    1499            0 : void DeviceCommissioner::HandleDeviceAttestationCompleted()
    1500              : {
    1501            0 :     if (!mDeviceBeingCommissioned)
    1502              :     {
    1503            0 :         return;
    1504              :     }
    1505              : 
    1506            0 :     auto & params                                                      = mDefaultCommissioner->GetCommissioningParameters();
    1507            0 :     Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
    1508            0 :     if (deviceAttestationDelegate)
    1509              :     {
    1510            0 :         ChipLogProgress(Controller, "Device attestation completed, delegating continuation to client");
    1511            0 :         deviceAttestationDelegate->OnDeviceAttestationCompleted(this, mDeviceBeingCommissioned, *mAttestationDeviceInfo,
    1512              :                                                                 mAttestationResult);
    1513              :     }
    1514              :     else
    1515              :     {
    1516            0 :         ChipLogError(Controller, "Need to wait for device attestation delegate, but no delegate available. Failing commissioning");
    1517            0 :         CommissioningDelegate::CommissioningReport report;
    1518            0 :         report.Set<AttestationErrorInfo>(mAttestationResult);
    1519            0 :         CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
    1520            0 :     }
    1521              : }
    1522              : 
    1523            0 : void DeviceCommissioner::OnFailedToExtendedArmFailSafeDeviceAttestation(void * context, CHIP_ERROR error)
    1524              : {
    1525            0 :     ChipLogProgress(Controller, "Failed to extend fail-safe timer to handle attestation failure: %" CHIP_ERROR_FORMAT,
    1526              :                     error.Format());
    1527            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1528              : 
    1529            0 :     CommissioningDelegate::CommissioningReport report;
    1530            0 :     report.Set<AttestationErrorInfo>(commissioner->mAttestationResult);
    1531            0 :     commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
    1532            0 : }
    1533              : 
    1534            4 : void DeviceCommissioner::OnICDManagementRegisterClientResponse(
    1535              :     void * context, const app::Clusters::IcdManagement::Commands::RegisterClientResponse::DecodableType & data)
    1536              : {
    1537            4 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1538              :     // On any failed check, log and return: this response says nothing about the stage actually in progress.
    1539            6 :     VerifyOrReturn(commissioner != nullptr, ChipLogError(Controller, "RegisterClientResponse received with null context"));
    1540            3 :     VerifyOrReturn(commissioner->mCommissioningStage == CommissioningStage::kICDRegistration,
    1541              :                    ChipLogError(Controller, "RegisterClientResponse received in incorrect stage '%s'",
    1542              :                                 StageToString(commissioner->mCommissioningStage)));
    1543            2 :     VerifyOrReturn(commissioner->mDeviceBeingCommissioned != nullptr,
    1544              :                    ChipLogError(Controller, "RegisterClientResponse received while no device is being commissioned"));
    1545              : 
    1546            1 :     if (commissioner->mPairingDelegate != nullptr)
    1547              :     {
    1548            1 :         commissioner->mPairingDelegate->OnICDRegistrationComplete(
    1549            1 :             ScopedNodeId(commissioner->mDeviceBeingCommissioned->GetDeviceId(), commissioner->GetFabricIndex()), data.ICDCounter);
    1550              :     }
    1551              : 
    1552              :     // All checks passed: the kICDRegistration stage is complete.
    1553            1 :     CommissioningDelegate::CommissioningReport report;
    1554            1 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
    1555            1 : }
    1556              : 
    1557            4 : void DeviceCommissioner::OnICDManagementStayActiveResponse(
    1558              :     void * context, const app::Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType & data)
    1559              : {
    1560            4 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1561              :     // On any failed check, log and return: this response says nothing about the stage actually in progress.
    1562            6 :     VerifyOrReturn(commissioner != nullptr, ChipLogError(Controller, "StayActiveResponse received with null context"));
    1563            3 :     VerifyOrReturn(commissioner->mCommissioningStage == CommissioningStage::kICDSendStayActive,
    1564              :                    ChipLogError(Controller, "StayActiveResponse received in incorrect stage '%s'",
    1565              :                                 StageToString(commissioner->mCommissioningStage)));
    1566            2 :     VerifyOrReturn(commissioner->mDeviceBeingCommissioned != nullptr,
    1567              :                    ChipLogError(Controller, "StayActiveResponse received while no device is being commissioned"));
    1568              : 
    1569            1 :     if (commissioner->mPairingDelegate != nullptr)
    1570              :     {
    1571            1 :         commissioner->mPairingDelegate->OnICDStayActiveComplete(
    1572            1 :             ScopedNodeId(commissioner->mDeviceBeingCommissioned->GetDeviceId(), commissioner->GetFabricIndex()),
    1573            1 :             data.promisedActiveDuration);
    1574              :     }
    1575              : 
    1576              :     // All checks passed: the kICDSendStayActive stage is complete.
    1577            1 :     CommissioningDelegate::CommissioningReport report;
    1578            1 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
    1579            1 : }
    1580              : 
    1581            0 : bool DeviceCommissioner::ExtendArmFailSafeInternal(DeviceProxy * proxy, CommissioningStage step, uint16_t armFailSafeTimeout,
    1582              :                                                    Optional<System::Clock::Timeout> commandTimeout,
    1583              :                                                    OnExtendFailsafeSuccess onSuccess, OnExtendFailsafeFailure onFailure,
    1584              :                                                    bool fireAndForget)
    1585              : {
    1586              :     using namespace System;
    1587              :     using namespace System::Clock;
    1588            0 :     auto now                = SystemClock().GetMonotonicTimestamp();
    1589            0 :     auto newFailSafeTimeout = now + Seconds16(armFailSafeTimeout);
    1590            0 :     if (newFailSafeTimeout < proxy->GetFailSafeExpirationTimestamp())
    1591              :     {
    1592            0 :         ChipLogProgress(
    1593              :             Controller, "Skipping arming failsafe: new time (%u seconds from now) before old time (%u seconds from now)",
    1594              :             armFailSafeTimeout, std::chrono::duration_cast<Seconds16>(proxy->GetFailSafeExpirationTimestamp() - now).count());
    1595            0 :         return false;
    1596              :     }
    1597              : 
    1598            0 :     uint64_t breadcrumb = static_cast<uint64_t>(step);
    1599            0 :     GeneralCommissioning::Commands::ArmFailSafe::Type request;
    1600            0 :     request.expiryLengthSeconds = armFailSafeTimeout;
    1601            0 :     request.breadcrumb          = breadcrumb;
    1602            0 :     ChipLogProgress(Controller, "Arming failsafe (%u seconds)", request.expiryLengthSeconds);
    1603            0 :     CHIP_ERROR err = SendCommissioningCommand(proxy, request, onSuccess, onFailure, kRootEndpointId, commandTimeout, fireAndForget);
    1604            0 :     if (err != CHIP_NO_ERROR)
    1605              :     {
    1606            0 :         onFailure((!fireAndForget) ? this : nullptr, err);
    1607            0 :         return true; // we have called onFailure already
    1608              :     }
    1609              : 
    1610              :     // Note: The stored timestamp may become invalid if we fail asynchronously
    1611            0 :     proxy->SetFailSafeExpirationTimestamp(newFailSafeTimeout);
    1612            0 :     return true;
    1613              : }
    1614              : 
    1615            0 : void DeviceCommissioner::ExtendArmFailSafeForDeviceAttestation(const Credentials::DeviceAttestationVerifier::AttestationInfo & info,
    1616              :                                                                Credentials::AttestationVerificationResult result)
    1617              : {
    1618            0 :     mAttestationResult = result;
    1619              : 
    1620            0 :     auto & params                                                      = mDefaultCommissioner->GetCommissioningParameters();
    1621            0 :     Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
    1622              : 
    1623            0 :     mAttestationDeviceInfo = Platform::MakeUnique<Credentials::DeviceAttestationVerifier::AttestationDeviceInfo>(info);
    1624              : 
    1625            0 :     auto expiryLengthSeconds      = deviceAttestationDelegate->FailSafeExpiryTimeoutSecs();
    1626            0 :     bool waitForFailsafeExtension = expiryLengthSeconds.HasValue();
    1627            0 :     if (waitForFailsafeExtension)
    1628              :     {
    1629            0 :         ChipLogProgress(Controller, "Changing fail-safe timer to %u seconds to handle DA failure", expiryLengthSeconds.Value());
    1630              :         // Per spec, anything we do with the fail-safe armed must not time out
    1631              :         // in less than kMinimumCommissioningStepTimeout.
    1632              :         waitForFailsafeExtension =
    1633            0 :             ExtendArmFailSafeInternal(mDeviceBeingCommissioned, mCommissioningStage, expiryLengthSeconds.Value(),
    1634            0 :                                       MakeOptional(kMinimumCommissioningStepTimeout), OnArmFailSafeExtendedForDeviceAttestation,
    1635              :                                       OnFailedToExtendedArmFailSafeDeviceAttestation, /* fireAndForget = */ false);
    1636              :     }
    1637              :     else
    1638              :     {
    1639            0 :         ChipLogProgress(Controller, "Proceeding without changing fail-safe timer value as delegate has not set it");
    1640              :     }
    1641              : 
    1642            0 :     if (!waitForFailsafeExtension)
    1643              :     {
    1644            0 :         HandleDeviceAttestationCompleted();
    1645              :     }
    1646            0 : }
    1647              : 
    1648            0 : CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const Credentials::DeviceAttestationVerifier::AttestationInfo & info)
    1649              : {
    1650              :     MATTER_TRACE_SCOPE("ValidateAttestationInfo", "DeviceCommissioner");
    1651            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1652            0 :     VerifyOrReturnError(mDeviceAttestationVerifier != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1653              : 
    1654            0 :     mDeviceAttestationVerifier->VerifyAttestationInformation(info, &mDeviceAttestationInformationVerificationCallback);
    1655              : 
    1656              :     // TODO: Validate Firmware Information
    1657              : 
    1658            0 :     return CHIP_NO_ERROR;
    1659              : }
    1660              : 
    1661              : CHIP_ERROR
    1662            0 : DeviceCommissioner::CheckForRevokedDACChain(const Credentials::DeviceAttestationVerifier::AttestationInfo & info)
    1663              : {
    1664              :     MATTER_TRACE_SCOPE("CheckForRevokedDACChain", "DeviceCommissioner");
    1665            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1666            0 :     VerifyOrReturnError(mDeviceAttestationVerifier != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1667              : 
    1668            0 :     mDeviceAttestationVerifier->CheckForRevokedDACChain(info, &mDeviceAttestationInformationVerificationCallback);
    1669              : 
    1670            0 :     return CHIP_NO_ERROR;
    1671              : }
    1672              : 
    1673            0 : CHIP_ERROR DeviceCommissioner::ValidateCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
    1674              :                                            const ByteSpan & AttestationSignature, const ByteSpan & dac, const ByteSpan & csrNonce)
    1675              : {
    1676              :     MATTER_TRACE_SCOPE("ValidateCSR", "DeviceCommissioner");
    1677            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1678            0 :     VerifyOrReturnError(mDeviceAttestationVerifier != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1679              : 
    1680            0 :     P256PublicKey dacPubkey;
    1681            0 :     ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(dac, dacPubkey));
    1682              : 
    1683              :     // Retrieve attestation challenge
    1684              :     ByteSpan attestationChallenge =
    1685            0 :         proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();
    1686              : 
    1687              :     // The operational CA should also verify this on its end during NOC generation, if end-to-end attestation is desired.
    1688            0 :     return mDeviceAttestationVerifier->VerifyNodeOperationalCSRInformation(NOCSRElements, attestationChallenge,
    1689            0 :                                                                            AttestationSignature, dacPubkey, csrNonce);
    1690            0 : }
    1691              : 
    1692            0 : CHIP_ERROR DeviceCommissioner::SendOperationalCertificateSigningRequestCommand(DeviceProxy * device, const ByteSpan & csrNonce,
    1693              :                                                                                Optional<System::Clock::Timeout> timeout)
    1694              : {
    1695              :     MATTER_TRACE_SCOPE("SendOperationalCertificateSigningRequestCommand", "DeviceCommissioner");
    1696            0 :     ChipLogDetail(Controller, "Sending CSR request to %p device", device);
    1697            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1698              : 
    1699            0 :     OperationalCredentials::Commands::CSRRequest::Type request;
    1700            0 :     request.CSRNonce = csrNonce;
    1701              : 
    1702            0 :     ReturnErrorOnFailure(SendCommissioningCommand(device, request, OnOperationalCertificateSigningRequest, OnCSRFailureResponse,
    1703              :                                                   kRootEndpointId, timeout));
    1704            0 :     ChipLogDetail(Controller, "Sent CSR request, waiting for the CSR");
    1705            0 :     return CHIP_NO_ERROR;
    1706              : }
    1707              : 
    1708            0 : void DeviceCommissioner::OnCSRFailureResponse(void * context, CHIP_ERROR error)
    1709              : {
    1710              :     MATTER_TRACE_SCOPE("OnCSRFailureResponse", "DeviceCommissioner");
    1711            0 :     ChipLogProgress(Controller, "Device failed to receive the CSR request Response: %" CHIP_ERROR_FORMAT, error.Format());
    1712            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1713            0 :     commissioner->CommissioningStageComplete(error);
    1714            0 : }
    1715              : 
    1716            0 : void DeviceCommissioner::OnOperationalCertificateSigningRequest(
    1717              :     void * context, const OperationalCredentials::Commands::CSRResponse::DecodableType & data)
    1718              : {
    1719              :     MATTER_TRACE_SCOPE("OnOperationalCertificateSigningRequest", "DeviceCommissioner");
    1720            0 :     ChipLogProgress(Controller, "Received certificate signing request from the device");
    1721            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1722              : 
    1723            0 :     CommissioningDelegate::CommissioningReport report;
    1724            0 :     report.Set<CSRResponse>(CSRResponse(data.NOCSRElements, data.attestationSignature));
    1725            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
    1726            0 : }
    1727              : 
    1728            0 : void DeviceCommissioner::OnDeviceNOCChainGeneration(void * context, CHIP_ERROR status, const ByteSpan & noc, const ByteSpan & icac,
    1729              :                                                     const ByteSpan & rcac, Optional<IdentityProtectionKeySpan> ipk,
    1730              :                                                     Optional<NodeId> adminSubject)
    1731              : {
    1732              :     MATTER_TRACE_SCOPE("OnDeviceNOCChainGeneration", "DeviceCommissioner");
    1733            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1734              : 
    1735              :     // The placeholder IPK is not satisfactory, but is there to fill the NocChain struct on error. It will still fail.
    1736            0 :     const uint8_t placeHolderIpk[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1737              :                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    1738            0 :     if (status == CHIP_NO_ERROR && !ipk.HasValue())
    1739              :     {
    1740            0 :         ChipLogError(Controller, "Did not have an IPK from the OperationalCredentialsIssuer! Cannot commission.");
    1741            0 :         status = CHIP_ERROR_INVALID_ARGUMENT;
    1742              :     }
    1743              : 
    1744            0 :     ChipLogProgress(Controller, "Received callback from the CA for NOC Chain generation. Status: %" CHIP_ERROR_FORMAT,
    1745              :                     status.Format());
    1746            0 :     if (status == CHIP_NO_ERROR && commissioner->mState != State::Initialized)
    1747              :     {
    1748            0 :         status = CHIP_ERROR_INCORRECT_STATE;
    1749              :     }
    1750            0 :     if (status != CHIP_NO_ERROR)
    1751              :     {
    1752            0 :         ChipLogError(Controller, "Failed in generating device's operational credentials. Error: %" CHIP_ERROR_FORMAT,
    1753              :                      status.Format());
    1754              :     }
    1755              : 
    1756              :     // TODO - Verify that the generated root cert matches with commissioner's root cert
    1757            0 :     CommissioningDelegate::CommissioningReport report;
    1758            0 :     report.Set<NocChain>(NocChain(noc, icac, rcac, ipk.HasValue() ? ipk.Value() : IdentityProtectionKeySpan(placeHolderIpk),
    1759            0 :                                   adminSubject.HasValue() ? adminSubject.Value() : commissioner->GetNodeId()));
    1760            0 :     commissioner->CommissioningStageComplete(status, report);
    1761            0 : }
    1762              : 
    1763            0 : CHIP_ERROR DeviceCommissioner::IssueNOCChain(const ByteSpan & NOCSRElements, NodeId nodeId,
    1764              :                                              chip::Callback::Callback<OnNOCChainGeneration> * callback)
    1765              : {
    1766              :     MATTER_TRACE_SCOPE("IssueNOCChain", "DeviceCommissioner");
    1767            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1768              : 
    1769            0 :     ChipLogProgress(Controller, "Getting certificate chain for the device on fabric idx %u", static_cast<unsigned>(mFabricIndex));
    1770              : 
    1771            0 :     mOperationalCredentialsDelegate->SetNodeIdForNextNOCRequest(nodeId);
    1772              : 
    1773            0 :     if (mFabricIndex != kUndefinedFabricIndex)
    1774              :     {
    1775            0 :         mOperationalCredentialsDelegate->SetFabricIdForNextNOCRequest(GetFabricId());
    1776              :     }
    1777              : 
    1778              :     // Note: we don't have attestationSignature, attestationChallenge, DAC, PAI so we are just providing an empty ByteSpan
    1779              :     // for those arguments.
    1780            0 :     return mOperationalCredentialsDelegate->GenerateNOCChain(NOCSRElements, ByteSpan(), ByteSpan(), ByteSpan(), ByteSpan(),
    1781            0 :                                                              ByteSpan(), callback);
    1782              : }
    1783              : 
    1784            0 : CHIP_ERROR DeviceCommissioner::ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
    1785              :                                           const ByteSpan & AttestationSignature, const ByteSpan & dac, const ByteSpan & pai,
    1786              :                                           const ByteSpan & csrNonce)
    1787              : {
    1788              :     MATTER_TRACE_SCOPE("ProcessOpCSR", "DeviceCommissioner");
    1789            0 :     VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
    1790              : 
    1791            0 :     ChipLogProgress(Controller, "Getting certificate chain for the device from the issuer");
    1792              : 
    1793            0 :     P256PublicKey dacPubkey;
    1794            0 :     ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(dac, dacPubkey));
    1795              : 
    1796              :     // Retrieve attestation challenge
    1797              :     ByteSpan attestationChallenge =
    1798            0 :         proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();
    1799              : 
    1800            0 :     mOperationalCredentialsDelegate->SetNodeIdForNextNOCRequest(proxy->GetDeviceId());
    1801              : 
    1802            0 :     if (mFabricIndex != kUndefinedFabricIndex)
    1803              :     {
    1804            0 :         mOperationalCredentialsDelegate->SetFabricIdForNextNOCRequest(GetFabricId());
    1805              :     }
    1806              : 
    1807            0 :     return mOperationalCredentialsDelegate->GenerateNOCChain(NOCSRElements, csrNonce, AttestationSignature, attestationChallenge,
    1808            0 :                                                              dac, pai, &mDeviceNOCChainCallback);
    1809            0 : }
    1810              : 
    1811            0 : CHIP_ERROR DeviceCommissioner::SendOperationalCertificate(DeviceProxy * device, const ByteSpan & nocCertBuf,
    1812              :                                                           const Optional<ByteSpan> & icaCertBuf,
    1813              :                                                           const IdentityProtectionKeySpan ipk, const NodeId adminSubject,
    1814              :                                                           Optional<System::Clock::Timeout> timeout)
    1815              : {
    1816              :     MATTER_TRACE_SCOPE("SendOperationalCertificate", "DeviceCommissioner");
    1817              : 
    1818            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1819              : 
    1820            0 :     OperationalCredentials::Commands::AddNOC::Type request;
    1821            0 :     request.NOCValue         = nocCertBuf;
    1822            0 :     request.ICACValue        = icaCertBuf;
    1823            0 :     request.IPKValue         = ipk;
    1824            0 :     request.caseAdminSubject = adminSubject;
    1825            0 :     request.adminVendorId    = mVendorId;
    1826              : 
    1827            0 :     ReturnErrorOnFailure(SendCommissioningCommand(device, request, OnOperationalCertificateAddResponse, OnAddNOCFailureResponse,
    1828              :                                                   kRootEndpointId, timeout));
    1829              : 
    1830            0 :     ChipLogProgress(Controller, "Sent operational certificate to the device");
    1831              : 
    1832            0 :     return CHIP_NO_ERROR;
    1833              : }
    1834              : 
    1835            0 : CHIP_ERROR DeviceCommissioner::ConvertFromOperationalCertStatus(OperationalCredentials::NodeOperationalCertStatusEnum err)
    1836              : {
    1837              :     using OperationalCredentials::NodeOperationalCertStatusEnum;
    1838            0 :     switch (err)
    1839              :     {
    1840            0 :     case NodeOperationalCertStatusEnum::kOk:
    1841            0 :         return CHIP_NO_ERROR;
    1842            0 :     case NodeOperationalCertStatusEnum::kInvalidPublicKey:
    1843            0 :         return CHIP_ERROR_INVALID_PUBLIC_KEY;
    1844            0 :     case NodeOperationalCertStatusEnum::kInvalidNodeOpId:
    1845            0 :         return CHIP_ERROR_WRONG_NODE_ID;
    1846            0 :     case NodeOperationalCertStatusEnum::kInvalidNOC:
    1847            0 :         return CHIP_ERROR_UNSUPPORTED_CERT_FORMAT;
    1848            0 :     case NodeOperationalCertStatusEnum::kMissingCsr:
    1849            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1850            0 :     case NodeOperationalCertStatusEnum::kTableFull:
    1851            0 :         return CHIP_ERROR_NO_MEMORY;
    1852            0 :     case NodeOperationalCertStatusEnum::kInvalidAdminSubject:
    1853            0 :         return CHIP_ERROR_INVALID_ADMIN_SUBJECT;
    1854            0 :     case NodeOperationalCertStatusEnum::kFabricConflict:
    1855            0 :         return CHIP_ERROR_FABRIC_EXISTS;
    1856            0 :     case NodeOperationalCertStatusEnum::kLabelConflict:
    1857            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
    1858            0 :     case NodeOperationalCertStatusEnum::kInvalidFabricIndex:
    1859            0 :         return CHIP_ERROR_INVALID_FABRIC_INDEX;
    1860            0 :     case NodeOperationalCertStatusEnum::kUnknownEnumValue:
    1861              :         // Is this a reasonable value?
    1862            0 :         return CHIP_ERROR_CERT_LOAD_FAILED;
    1863              :     }
    1864              : 
    1865            0 :     return CHIP_ERROR_CERT_LOAD_FAILED;
    1866              : }
    1867              : 
    1868            0 : void DeviceCommissioner::OnAddNOCFailureResponse(void * context, CHIP_ERROR error)
    1869              : {
    1870              :     MATTER_TRACE_SCOPE("OnAddNOCFailureResponse", "DeviceCommissioner");
    1871            0 :     ChipLogProgress(Controller, "Device failed to receive the operational certificate Response: %" CHIP_ERROR_FORMAT,
    1872              :                     error.Format());
    1873            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1874            0 :     commissioner->CommissioningStageComplete(error);
    1875            0 : }
    1876              : 
    1877            0 : void DeviceCommissioner::OnOperationalCertificateAddResponse(
    1878              :     void * context, const OperationalCredentials::Commands::NOCResponse::DecodableType & data)
    1879              : {
    1880              :     MATTER_TRACE_SCOPE("OnOperationalCertificateAddResponse", "DeviceCommissioner");
    1881            0 :     ChipLogProgress(Controller, "Device returned status %d on receiving the NOC", to_underlying(data.statusCode));
    1882            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1883              : 
    1884            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1885              : 
    1886            0 :     VerifyOrExit(commissioner->mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE);
    1887              : 
    1888            0 :     VerifyOrExit(commissioner->mDeviceBeingCommissioned != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    1889              : 
    1890            0 :     err = ConvertFromOperationalCertStatus(data.statusCode);
    1891            0 :     SuccessOrExit(err);
    1892              : 
    1893            0 :     err = commissioner->OnOperationalCredentialsProvisioningCompletion(commissioner->mDeviceBeingCommissioned);
    1894              : 
    1895            0 : exit:
    1896            0 :     if (err != CHIP_NO_ERROR)
    1897              :     {
    1898            0 :         ChipLogProgress(Controller, "Add NOC failed with error: %" CHIP_ERROR_FORMAT, err.Format());
    1899              :         // Preserve the device-reported NodeOperationalCertStatusEnum (kInvalidPublicKey,
    1900              :         // kInvalidNodeOpId, kInvalidNOC, kFabricConflict, kLabelConflict, kInvalidFabricIndex,
    1901              :         // kTableFull, etc.) in the report so OnCommissioningFailure consumers can distinguish
    1902              :         // these without losing fidelity to the generic CHIP_ERROR returned by
    1903              :         // ConvertFromOperationalCertStatus.
    1904            0 :         CommissioningDelegate::CommissioningReport report;
    1905              :         // ConvertFromOperationalCertStatus succeeds on kOk and returns a non-success CHIP_ERROR
    1906              :         // for any other value, but `err` at this point can also be a downstream local failure
    1907              :         // (e.g. from OnOperationalCredentialsProvisioningCompletion) while data.statusCode is
    1908              :         // still kOk. Guard so we never publish a "success enum" alongside a non-success err to
    1909              :         // OnCommissioningFailure consumers.
    1910            0 :         if (data.statusCode != OperationalCredentials::NodeOperationalCertStatusEnum::kOk)
    1911              :         {
    1912            0 :             report.Set<OperationalCertErrorInfo>(data.statusCode);
    1913              :         }
    1914            0 :         commissioner->CommissioningStageComplete(err, report);
    1915            0 :     }
    1916            0 : }
    1917              : 
    1918            0 : CHIP_ERROR DeviceCommissioner::SendTrustedRootCertificate(DeviceProxy * device, const ByteSpan & rcac,
    1919              :                                                           Optional<System::Clock::Timeout> timeout)
    1920              : {
    1921              :     MATTER_TRACE_SCOPE("SendTrustedRootCertificate", "DeviceCommissioner");
    1922            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1923              : 
    1924            0 :     ChipLogProgress(Controller, "Sending root certificate to the device");
    1925              : 
    1926            0 :     OperationalCredentials::Commands::AddTrustedRootCertificate::Type request;
    1927            0 :     request.rootCACertificate = rcac;
    1928            0 :     ReturnErrorOnFailure(
    1929              :         SendCommissioningCommand(device, request, OnRootCertSuccessResponse, OnRootCertFailureResponse, kRootEndpointId, timeout));
    1930              : 
    1931            0 :     ChipLogProgress(Controller, "Sent root certificate to the device");
    1932              : 
    1933            0 :     return CHIP_NO_ERROR;
    1934              : }
    1935              : 
    1936            0 : void DeviceCommissioner::OnRootCertSuccessResponse(void * context, const chip::app::DataModel::NullObjectType &)
    1937              : {
    1938              :     MATTER_TRACE_SCOPE("OnRootCertSuccessResponse", "DeviceCommissioner");
    1939            0 :     ChipLogProgress(Controller, "Device confirmed that it has received the root certificate");
    1940            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1941            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
    1942            0 : }
    1943              : 
    1944            0 : void DeviceCommissioner::OnRootCertFailureResponse(void * context, CHIP_ERROR error)
    1945              : {
    1946              :     MATTER_TRACE_SCOPE("OnRootCertFailureResponse", "DeviceCommissioner");
    1947            0 :     ChipLogProgress(Controller, "Device failed to receive the root certificate Response: %" CHIP_ERROR_FORMAT, error.Format());
    1948            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    1949            0 :     commissioner->CommissioningStageComplete(error);
    1950            0 : }
    1951              : 
    1952            0 : CHIP_ERROR DeviceCommissioner::OnOperationalCredentialsProvisioningCompletion(DeviceProxy * device)
    1953              : {
    1954              :     MATTER_TRACE_SCOPE("OnOperationalCredentialsProvisioningCompletion", "DeviceCommissioner");
    1955            0 :     ChipLogProgress(Controller, "Operational credentials provisioned on device %p", device);
    1956            0 :     VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1957              : 
    1958            0 :     if (mPairingDelegate != nullptr)
    1959              :     {
    1960            0 :         mPairingDelegate->OnStatusUpdate(DevicePairingDelegate::SecurePairingSuccess);
    1961              :     }
    1962            0 :     CommissioningStageComplete(CHIP_NO_ERROR);
    1963              : 
    1964            0 :     return CHIP_NO_ERROR;
    1965              : }
    1966              : 
    1967              : #if CONFIG_NETWORK_LAYER_BLE
    1968              : #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
    1969              : void DeviceCommissioner::ConnectBleTransportToSelf()
    1970              : {
    1971              :     Transport::BLEBase & transport = std::get<Transport::BLE<1>>(mSystemState->TransportMgr()->GetTransport().GetTransports());
    1972              :     if (!transport.IsBleLayerTransportSetToSelf())
    1973              :     {
    1974              :         transport.SetBleLayerTransportToSelf();
    1975              :     }
    1976              : }
    1977              : #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
    1978              : 
    1979            0 : void DeviceCommissioner::CloseBleConnection()
    1980              : {
    1981              :     // It is fine since we can only commission one device at the same time.
    1982              :     // We should be able to distinguish different BLE connections if we want
    1983              :     // to commission multiple devices at the same time over BLE.
    1984            0 :     mSystemState->BleLayer()->CloseAllBleConnections();
    1985            0 : }
    1986              : #endif
    1987              : 
    1988            0 : CHIP_ERROR DeviceCommissioner::DiscoverCommissionableNodes(Dnssd::DiscoveryFilter filter)
    1989              : {
    1990            0 :     ReturnErrorOnFailure(SetUpNodeDiscovery());
    1991            0 :     return mDNSResolver.DiscoverCommissionableNodes(filter);
    1992              : }
    1993              : 
    1994            2 : CHIP_ERROR DeviceCommissioner::StopCommissionableDiscovery()
    1995              : {
    1996            2 :     return mDNSResolver.StopDiscovery();
    1997              : }
    1998              : 
    1999            0 : const Dnssd::CommissionNodeData * DeviceCommissioner::GetDiscoveredDevice(int idx)
    2000              : {
    2001            0 :     return GetDiscoveredNode(idx);
    2002              : }
    2003              : 
    2004              : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
    2005              : 
    2006              : CHIP_ERROR DeviceCommissioner::SetUdcListenPort(uint16_t listenPort)
    2007              : {
    2008              :     if (mState == State::Initialized)
    2009              :     {
    2010              :         return CHIP_ERROR_INCORRECT_STATE;
    2011              :     }
    2012              : 
    2013              :     mUdcListenPort = listenPort;
    2014              :     return CHIP_NO_ERROR;
    2015              : }
    2016              : 
    2017              : void DeviceCommissioner::FindCommissionableNode(const char * instanceName)
    2018              : {
    2019              :     Dnssd::DiscoveryFilter filter(Dnssd::DiscoveryFilterType::kInstanceName, instanceName);
    2020              :     TEMPORARY_RETURN_IGNORED DiscoverCommissionableNodes(filter);
    2021              : }
    2022              : 
    2023              : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
    2024              : 
    2025            0 : void DeviceCommissioner::OnNodeDiscovered(const chip::Dnssd::DiscoveredNodeData & nodeData)
    2026              : {
    2027              : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
    2028              :     if (mUdcServer != nullptr)
    2029              :     {
    2030              :         mUdcServer->OnCommissionableNodeFound(nodeData);
    2031              :     }
    2032              : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
    2033            0 :     if (nodeData.Get<Dnssd::CommissionNodeData>().threadMeshcop)
    2034              :     {
    2035            0 :         mAutoCommissioner.SetNetworkSetupNeeded(true);
    2036              :     }
    2037            0 :     AbstractDnssdDiscoveryController::OnNodeDiscovered(nodeData);
    2038            0 :     mSetUpCodePairer.NotifyCommissionableDeviceDiscovered(nodeData);
    2039            0 : }
    2040              : 
    2041            0 : void DeviceCommissioner::OnBasicSuccess(void * context, const chip::app::DataModel::NullObjectType &)
    2042              : {
    2043            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    2044            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
    2045            0 : }
    2046              : 
    2047            0 : void DeviceCommissioner::OnBasicFailure(void * context, CHIP_ERROR error)
    2048              : {
    2049            0 :     ChipLogProgress(Controller, "Received failure response: %" CHIP_ERROR_FORMAT, error.Format());
    2050            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    2051            0 :     commissioner->CommissioningStageComplete(error);
    2052            0 : }
    2053              : 
    2054            0 : static GeneralCommissioning::Commands::ArmFailSafe::Type DisarmFailsafeRequest()
    2055              : {
    2056            0 :     GeneralCommissioning::Commands::ArmFailSafe::Type request;
    2057            0 :     request.expiryLengthSeconds = 0; // Expire immediately.
    2058            0 :     request.breadcrumb          = 0;
    2059            0 :     return request;
    2060              : }
    2061              : 
    2062            0 : static void MarkForEviction(const Optional<SessionHandle> & session)
    2063              : {
    2064            0 :     if (session.HasValue())
    2065              :     {
    2066            0 :         session.Value()->AsSecureSession()->MarkForEviction();
    2067              :     }
    2068            0 : }
    2069              : 
    2070            0 : void DeviceCommissioner::CleanupCommissioning(DeviceProxy * proxy, NodeId nodeId, const CompletionStatus & completionStatus)
    2071              : {
    2072              :     // At this point, proxy == mDeviceBeingCommissioned, nodeId == mDeviceBeingCommissioned->GetDeviceId()
    2073              : 
    2074            0 :     mCommissioningCompletionStatus = completionStatus;
    2075              : 
    2076            0 :     if (completionStatus.err == CHIP_NO_ERROR)
    2077              :     {
    2078              :         // CommissioningStageComplete uses mDeviceBeingCommissioned, which can
    2079              :         // be commissionee if we are cleaning up before we've gone operational.  Normally
    2080              :         // that would not happen in this non-error case, _except_ if we were told to skip sending
    2081              :         // CommissioningComplete: in that case we do not have an operational DeviceProxy, so
    2082              :         // we're using our CommissioneeDeviceProxy to do a successful cleanup.
    2083              :         //
    2084              :         // This means we have to call CommissioningStageComplete() before we destroy commissionee.
    2085              :         //
    2086              :         // This should be safe, because CommissioningStageComplete() does not call CleanupCommissioning
    2087              :         // when called in the cleanup stage (which is where we are), and StopPairing does not directly release
    2088              :         // mDeviceBeingCommissioned.
    2089            0 :         CommissioningStageComplete(CHIP_NO_ERROR);
    2090              : 
    2091            0 :         CommissioneeDeviceProxy * commissionee = FindCommissioneeDevice(nodeId);
    2092            0 :         if (commissionee != nullptr)
    2093              :         {
    2094            0 :             ReleaseCommissioneeDevice(commissionee);
    2095              :         }
    2096              :         // Send the callbacks, we're done.
    2097            0 :         SendCommissioningCompleteCallbacks(nodeId, mCommissioningCompletionStatus);
    2098              :     }
    2099            0 :     else if (completionStatus.err == CHIP_ERROR_CANCELLED)
    2100              :     {
    2101              :         // If we're cleaning up because cancellation has been requested via StopPairing(), expire the failsafe
    2102              :         // in the background and reset our state synchronously, so a new commissioning attempt can be started.
    2103            0 :         CommissioneeDeviceProxy * commissionee = FindCommissioneeDevice(nodeId);
    2104            0 :         SessionHolder session((commissionee == proxy) ? commissionee->DetachSecureSession().Value()
    2105            0 :                                                       : proxy->GetSecureSession().Value());
    2106              : 
    2107            0 :         auto request     = DisarmFailsafeRequest();
    2108            0 :         auto onSuccessCb = [session](const app::ConcreteCommandPath & aPath, const app::StatusIB & aStatus,
    2109              :                                      const decltype(request)::ResponseType & responseData) {
    2110            0 :             ChipLogProgress(Controller, "Failsafe disarmed");
    2111            0 :             MarkForEviction(session.Get());
    2112            0 :         };
    2113            0 :         auto onFailureCb = [session](CHIP_ERROR aError) {
    2114            0 :             ChipLogProgress(Controller, "Ignoring failure to disarm failsafe: %" CHIP_ERROR_FORMAT, aError.Format());
    2115            0 :             MarkForEviction(session.Get());
    2116            0 :         };
    2117              : 
    2118            0 :         ChipLogProgress(Controller, "Disarming failsafe on device %p in background", proxy);
    2119            0 :         CHIP_ERROR err = InvokeCommandRequest(proxy->GetExchangeManager(), session.Get().Value(), kRootEndpointId, request,
    2120              :                                               onSuccessCb, onFailureCb);
    2121            0 :         if (err != CHIP_NO_ERROR)
    2122              :         {
    2123            0 :             ChipLogError(Controller, "Failed to send command to disarm fail-safe: %" CHIP_ERROR_FORMAT, err.Format());
    2124              :         }
    2125              : 
    2126            0 :         CleanupDoneAfterError();
    2127            0 :     }
    2128            0 :     else if (completionStatus.failedStage.HasValue() && completionStatus.failedStage.Value() >= kWiFiNetworkSetup)
    2129              :     {
    2130              :         // If we were already doing network setup, we need to retain the pase session and start again from network setup stage.
    2131              :         // We do not need to reset the failsafe here because we want to keep everything on the device up to this point, so just
    2132              :         // send the completion callbacks (see "Commissioning Flows Error Handling" in the spec).
    2133            0 :         CommissioningStageComplete(CHIP_NO_ERROR);
    2134            0 :         SendCommissioningCompleteCallbacks(nodeId, mCommissioningCompletionStatus);
    2135              :     }
    2136              :     else
    2137              :     {
    2138              :         // If we've failed somewhere in the early stages (or we don't have a failedStage specified), we need to start from the
    2139              :         // beginning. However, because some of the commands can only be sent once per arm-failsafe, we also need to force a reset on
    2140              :         // the failsafe so we can start fresh on the next attempt.
    2141            0 :         ChipLogProgress(Controller, "Disarming failsafe on device %p", proxy);
    2142            0 :         auto request   = DisarmFailsafeRequest();
    2143            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnDisarmFailsafe, OnDisarmFailsafeFailure, kRootEndpointId);
    2144            0 :         if (err != CHIP_NO_ERROR)
    2145              :         {
    2146              :             // We won't get any async callbacks here, so just pretend like the command errored out async.
    2147            0 :             ChipLogError(Controller, "Failed to send command to disarm fail-safe: %" CHIP_ERROR_FORMAT, err.Format());
    2148            0 :             CleanupDoneAfterError();
    2149              :         }
    2150              :     }
    2151            0 : }
    2152              : 
    2153            0 : void DeviceCommissioner::OnDisarmFailsafe(void * context,
    2154              :                                           const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
    2155              : {
    2156            0 :     ChipLogProgress(Controller, "Failsafe disarmed");
    2157            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    2158            0 :     commissioner->CleanupDoneAfterError();
    2159            0 : }
    2160              : 
    2161            0 : void DeviceCommissioner::OnDisarmFailsafeFailure(void * context, CHIP_ERROR error)
    2162              : {
    2163            0 :     ChipLogProgress(Controller, "Ignoring failure to disarm failsafe: %" CHIP_ERROR_FORMAT, error.Format());
    2164            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    2165            0 :     commissioner->CleanupDoneAfterError();
    2166            0 : }
    2167              : 
    2168            0 : void DeviceCommissioner::CleanupDoneAfterError()
    2169              : {
    2170              :     // If someone nulled out our mDeviceBeingCommissioned, there's nothing else
    2171              :     // to do here.
    2172            0 :     VerifyOrReturn(mDeviceBeingCommissioned != nullptr);
    2173              : 
    2174            0 :     NodeId nodeId = mDeviceBeingCommissioned->GetDeviceId();
    2175              : 
    2176              :     // Signal completion - this will reset mDeviceBeingCommissioned.
    2177            0 :     CommissioningStageComplete(CHIP_NO_ERROR);
    2178              : 
    2179              :     // At this point, we also want to close off the pase session so we need to re-establish
    2180            0 :     CommissioneeDeviceProxy * commissionee = FindCommissioneeDevice(nodeId);
    2181              : 
    2182              :     // If we've disarmed the failsafe, it's because we're starting again, so kill the pase connection.
    2183            0 :     if (commissionee != nullptr)
    2184              :     {
    2185            0 :         ReleaseCommissioneeDevice(commissionee);
    2186              :     }
    2187              : 
    2188              :     // Invoke callbacks last, after we have cleared up all state.
    2189            0 :     SendCommissioningCompleteCallbacks(nodeId, mCommissioningCompletionStatus);
    2190              : }
    2191              : 
    2192            0 : void DeviceCommissioner::SendCommissioningCompleteCallbacks(NodeId nodeId, const CompletionStatus & completionStatus)
    2193              : {
    2194              :     MATTER_LOG_METRIC_END(kMetricDeviceCommissionerCommission, completionStatus.err);
    2195              : 
    2196            0 :     ChipLogProgress(Controller, "Commissioning complete for node ID 0x" ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId),
    2197              :                     (completionStatus.err == CHIP_NO_ERROR ? "success" : completionStatus.err.AsString()));
    2198            0 :     mCommissioningStage = CommissioningStage::kSecurePairing;
    2199              : 
    2200            0 :     if (mPairingDelegate == nullptr)
    2201              :     {
    2202            0 :         return;
    2203              :     }
    2204              : 
    2205            0 :     mPairingDelegate->OnCommissioningComplete(nodeId, completionStatus.err);
    2206              : 
    2207            0 :     PeerId peerId(GetCompressedFabricId(), nodeId);
    2208            0 :     if (completionStatus.err == CHIP_NO_ERROR)
    2209              :     {
    2210            0 :         mPairingDelegate->OnCommissioningSuccess(peerId);
    2211              :     }
    2212              :     else
    2213              :     {
    2214            0 :         mPairingDelegate->OnCommissioningFailure(peerId, completionStatus);
    2215              :     }
    2216              : }
    2217              : 
    2218            2 : void DeviceCommissioner::CommissioningStageComplete(CHIP_ERROR err, CommissioningDelegate::CommissioningReport report)
    2219              : {
    2220              :     // Once this stage is complete, reset mDeviceBeingCommissioned - this will be reset when the delegate calls the next step.
    2221              :     MATTER_TRACE_SCOPE("CommissioningStageComplete", "DeviceCommissioner");
    2222              :     MATTER_LOG_METRIC_END(MetricKeyForCommissioningStage(mCommissioningStage), err);
    2223            2 :     VerifyOrDie(mDeviceBeingCommissioned);
    2224              : 
    2225            2 :     NodeId nodeId            = mDeviceBeingCommissioned->GetDeviceId();
    2226            2 :     DeviceProxy * proxy      = mDeviceBeingCommissioned;
    2227            2 :     mDeviceBeingCommissioned = nullptr;
    2228            2 :     mInvokeCancelFn          = nullptr;
    2229            2 :     mWriteCancelFn           = nullptr;
    2230              : 
    2231            2 :     if (mPairingDelegate != nullptr)
    2232              :     {
    2233            2 :         mPairingDelegate->OnCommissioningStatusUpdate(PeerId(GetCompressedFabricId(), nodeId), mCommissioningStage, err);
    2234              :     }
    2235              : 
    2236            2 :     if (mCommissioningDelegate == nullptr)
    2237              :     {
    2238            2 :         return;
    2239              :     }
    2240            0 :     report.stageCompleted = mCommissioningStage;
    2241            0 :     CHIP_ERROR status     = mCommissioningDelegate->CommissioningStepFinished(err, report);
    2242            0 :     if (status != CHIP_NO_ERROR && mCommissioningStage != CommissioningStage::kCleanup)
    2243              :     {
    2244              :         // Commissioning delegate will only return error if it failed to perform the appropriate commissioning step.
    2245              :         // In this case, we should complete the commissioning for it.
    2246            0 :         CompletionStatus completionStatus;
    2247            0 :         completionStatus.err         = status;
    2248            0 :         completionStatus.failedStage = MakeOptional(report.stageCompleted);
    2249            0 :         mCommissioningStage          = CommissioningStage::kCleanup;
    2250            0 :         mDeviceBeingCommissioned     = proxy;
    2251            0 :         CleanupCommissioning(proxy, nodeId, completionStatus);
    2252            0 :     }
    2253              : }
    2254              : 
    2255            0 : void DeviceCommissioner::OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr,
    2256              :                                              const SessionHandle & sessionHandle)
    2257              : {
    2258              :     // CASE session established.
    2259              :     MATTER_LOG_METRIC_END(kMetricDeviceCommissioningOperationalSetup, CHIP_NO_ERROR);
    2260            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    2261            0 :     VerifyOrDie(commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForStayActive ||
    2262              :                 commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForCommissioningComplete);
    2263            0 :     VerifyOrDie(commissioner->mDeviceBeingCommissioned->GetDeviceId() == sessionHandle->GetPeer().GetNodeId());
    2264            0 :     commissioner->CancelCASECallbacks(); // ensure all CASE callbacks are unregistered
    2265              : 
    2266            0 :     CommissioningDelegate::CommissioningReport report;
    2267            0 :     report.Set<OperationalNodeFoundData>(OperationalNodeFoundData(OperationalDeviceProxy(&exchangeMgr, sessionHandle)));
    2268            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
    2269            0 : }
    2270              : 
    2271            0 : void DeviceCommissioner::OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
    2272              : {
    2273              :     // CASE session establishment failed.
    2274              :     MATTER_LOG_METRIC_END(kMetricDeviceCommissioningOperationalSetup, error);
    2275            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    2276            0 :     VerifyOrDie(commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForStayActive ||
    2277              :                 commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForCommissioningComplete);
    2278            0 :     VerifyOrDie(commissioner->mDeviceBeingCommissioned->GetDeviceId() == peerId.GetNodeId());
    2279            0 :     commissioner->CancelCASECallbacks(); // ensure all CASE callbacks are unregistered
    2280              : 
    2281            0 :     if (error != CHIP_NO_ERROR)
    2282              :     {
    2283            0 :         ChipLogProgress(Controller, "Device connection failed. Error %" CHIP_ERROR_FORMAT, error.Format());
    2284              :     }
    2285              :     else
    2286              :     {
    2287              :         // Ensure that commissioning stage advancement is done based on seeing an error.
    2288            0 :         ChipLogError(Controller, "Device connection failed without a valid error code.");
    2289            0 :         error = CHIP_ERROR_INTERNAL;
    2290              :     }
    2291            0 :     commissioner->CommissioningStageComplete(error);
    2292            0 : }
    2293              : 
    2294              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
    2295              : // No specific action to take on either success or failure here; we're just
    2296              : // trying to bump the fail-safe, and if that fails it's not clear there's much
    2297              : // we can to with that.
    2298            0 : static void OnExtendFailsafeForCASERetryFailure(void * context, CHIP_ERROR error)
    2299              : {
    2300            0 :     ChipLogError(Controller, "Failed to extend fail-safe for CASE retry: %" CHIP_ERROR_FORMAT, error.Format());
    2301            0 : }
    2302              : static void
    2303            0 : OnExtendFailsafeForCASERetrySuccess(void * context,
    2304              :                                     const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
    2305              : {
    2306            0 :     ChipLogProgress(Controller, "Status of extending fail-safe for CASE retry: %u", to_underlying(data.errorCode));
    2307            0 : }
    2308              : 
    2309            0 : void DeviceCommissioner::OnDeviceConnectionRetryFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error,
    2310              :                                                    System::Clock::Seconds16 retryTimeout)
    2311              : {
    2312            0 :     ChipLogError(Controller,
    2313              :                  "Session establishment failed for " ChipLogFormatScopedNodeId ", error: %" CHIP_ERROR_FORMAT
    2314              :                  ".  Next retry expected to get a response to Sigma1 or fail within %d seconds",
    2315              :                  ChipLogValueScopedNodeId(peerId), error.Format(), retryTimeout.count());
    2316              : 
    2317            0 :     auto self = static_cast<DeviceCommissioner *>(context);
    2318            0 :     VerifyOrDie(self->GetCommissioningStage() == CommissioningStage::kFindOperationalForStayActive ||
    2319              :                 self->GetCommissioningStage() == CommissioningStage::kFindOperationalForCommissioningComplete);
    2320            0 :     VerifyOrDie(self->mDeviceBeingCommissioned->GetDeviceId() == peerId.GetNodeId());
    2321              : 
    2322              :     bool supportsConcurrent =
    2323            0 :         self->mCommissioningDelegate->GetCommissioningParameters().GetSupportsConcurrentConnection().ValueOr(true);
    2324            0 :     if (!supportsConcurrent)
    2325              :     {
    2326              :         // Concurrent mode not supported.
    2327              :         // We are in operational phase so the commissioning channel is not
    2328              :         // available anymore and it is not possible to re-arm the fail-safe timer.
    2329            0 :         return;
    2330              :     }
    2331              : 
    2332              :     // We need to do the fail-safe arming over the PASE session.
    2333            0 :     auto * commissioneeDevice = self->FindCommissioneeDevice(peerId.GetNodeId());
    2334            0 :     if (!commissioneeDevice)
    2335              :     {
    2336              :         // Commissioning canceled, presumably.  Just ignore the notification,
    2337              :         // not much we can do here.
    2338            0 :         return;
    2339              :     }
    2340              : 
    2341              :     // Extend by the default failsafe timeout plus our retry timeout, so we can
    2342              :     // be sure the fail-safe will not expire before we try the next time, if
    2343              :     // there will be a next time.
    2344              :     //
    2345              :     // TODO: Make it possible for our clients to control the exact timeout here?
    2346              :     uint16_t failsafeTimeout;
    2347            0 :     if (UINT16_MAX - retryTimeout.count() < kDefaultFailsafeTimeout)
    2348              :     {
    2349            0 :         failsafeTimeout = UINT16_MAX;
    2350              :     }
    2351              :     else
    2352              :     {
    2353            0 :         failsafeTimeout = static_cast<uint16_t>(retryTimeout.count() + kDefaultFailsafeTimeout);
    2354              :     }
    2355              : 
    2356              :     // A false return is fine; we don't want to make the fail-safe shorter here.
    2357            0 :     self->ExtendArmFailSafeInternal(commissioneeDevice, self->GetCommissioningStage(), failsafeTimeout,
    2358            0 :                                     MakeOptional(kMinimumCommissioningStepTimeout), OnExtendFailsafeForCASERetrySuccess,
    2359              :                                     OnExtendFailsafeForCASERetryFailure, /* fireAndForget = */ true);
    2360              : }
    2361              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
    2362              : 
    2363              : // ClusterStateCache::Callback / ReadClient::Callback
    2364            0 : void DeviceCommissioner::OnDone(app::ReadClient * readClient)
    2365              : {
    2366            0 :     VerifyOrDie(readClient != nullptr && readClient == mReadClient.get());
    2367            0 :     mReadClient.reset();
    2368            0 :     switch (mCommissioningStage)
    2369              :     {
    2370            0 :     case CommissioningStage::kReadCommissioningInfo:
    2371            0 :         ContinueReadingCommissioningInfo(mCommissioningDelegate->GetCommissioningParameters());
    2372            0 :         break;
    2373            0 :     default:
    2374            0 :         VerifyOrDie(false);
    2375              :         break;
    2376              :     }
    2377            0 : }
    2378              : 
    2379              : namespace {
    2380              : // Helper for grouping attribute paths into read interactions in ContinueReadingCommissioningInfo()
    2381              : // below. The logic generates a sequence of calls to AddAttributePath(), stopping when the capacity
    2382              : // of the builder is exceeded. When creating subsequent read requests, the same sequence of calls
    2383              : // is generated again, but the builder will skip however many attributes were already read in
    2384              : // previous requests. This makes it easy to have logic that conditionally reads attributes, without
    2385              : // needing to write manual code to work out where subsequent reads need to resume -- the logic that
    2386              : // decides which attributes to read simply needs to be repeatable / deterministic.
    2387              : class ReadInteractionBuilder
    2388              : {
    2389              :     static constexpr auto kCapacity = InteractionModelEngine::kMinSupportedPathsPerReadRequest;
    2390              : 
    2391              :     size_t mSkip  = 0;
    2392              :     size_t mCount = 0;
    2393              :     app::AttributePathParams mPaths[kCapacity];
    2394              : 
    2395              : public:
    2396            0 :     ReadInteractionBuilder(size_t skip = 0) : mSkip(skip) {}
    2397              : 
    2398            0 :     size_t size() { return std::min(mCount, kCapacity); }
    2399            0 :     bool exceeded() { return mCount > kCapacity; }
    2400            0 :     app::AttributePathParams * paths() { return mPaths; }
    2401              : 
    2402              :     // Adds an attribute path if within the current window.
    2403              :     // Returns false if the available space has been exceeded.
    2404              :     template <typename... Ts>
    2405            0 :     bool AddAttributePath(Ts &&... args)
    2406              :     {
    2407            0 :         if (mSkip > 0)
    2408              :         {
    2409            0 :             mSkip--;
    2410            0 :             return true;
    2411              :         }
    2412            0 :         if (mCount >= kCapacity)
    2413              :         {
    2414              :             // capacity exceeded
    2415            0 :             mCount = kCapacity + 1;
    2416            0 :             return false;
    2417              :         }
    2418            0 :         mPaths[mCount++] = app::AttributePathParams(std::forward<Ts>(args)...);
    2419            0 :         return true;
    2420              :     }
    2421              : };
    2422              : } // namespace
    2423              : 
    2424            0 : void DeviceCommissioner::ContinueReadingCommissioningInfo(const CommissioningParameters & params)
    2425              : {
    2426            0 :     VerifyOrDie(mCommissioningStage == CommissioningStage::kReadCommissioningInfo);
    2427              : 
    2428              :     // mReadCommissioningInfoProgress starts at 0 and counts the number of paths we have read.
    2429              :     // A marker value is used to indicate that there are no further attributes to read.
    2430              :     static constexpr auto kReadProgressNoFurtherAttributes = std::numeric_limits<decltype(mReadCommissioningInfoProgress)>::max();
    2431            0 :     if (mReadCommissioningInfoProgress == kReadProgressNoFurtherAttributes)
    2432              :     {
    2433            0 :         FinishReadingCommissioningInfo(params);
    2434            0 :         return;
    2435              :     }
    2436              : 
    2437              :     // We can ony read 9 paths per Read Interaction, since that is the minimum a server has to
    2438              :     // support per spec (see "Interaction Model Limits"), so we generally need to perform more
    2439              :     // that one interaction. To build the list of attributes for each interaction, we use a
    2440              :     // builder that skips adding paths that we already handled in a previous interaction, and
    2441              :     // returns false if the current request is exhausted. This construction avoids allocating
    2442              :     // memory to hold the complete list of attributes to read up front; however the logic to
    2443              :     // determine the attributes to include must be deterministic since it runs multiple times.
    2444              :     // The use of an immediately-invoked lambda is convenient for control flow.
    2445            0 :     ReadInteractionBuilder builder(mReadCommissioningInfoProgress);
    2446            0 :     [&]() -> void {
    2447              :         // General Commissioning
    2448            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
    2449              :                                                 Clusters::GeneralCommissioning::Attributes::SupportsConcurrentConnection::Id));
    2450            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
    2451              :                                                 Clusters::GeneralCommissioning::Attributes::Breadcrumb::Id));
    2452            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
    2453              :                                                 Clusters::GeneralCommissioning::Attributes::BasicCommissioningInfo::Id));
    2454            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
    2455              :                                                 Clusters::GeneralCommissioning::Attributes::RegulatoryConfig::Id));
    2456            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
    2457              :                                                 Clusters::GeneralCommissioning::Attributes::LocationCapability::Id));
    2458            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
    2459              :                                                 Clusters::GeneralCommissioning::Attributes::IsCommissioningWithoutPower::Id));
    2460              : 
    2461              :         // Basic Information: VID and PID for device attestation purposes
    2462            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::BasicInformation::Id,
    2463              :                                                 Clusters::BasicInformation::Attributes::VendorID::Id));
    2464            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::BasicInformation::Id,
    2465              :                                                 Clusters::BasicInformation::Attributes::ProductID::Id));
    2466              : 
    2467              :         // Time Synchronization: all attributes
    2468            0 :         VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::TimeSynchronization::Id));
    2469              : 
    2470              :         // Network Commissioning (all endpoints): Read the feature map and connect time
    2471              :         // TODO: Expose a flag that disables network setup so we don't need to read this
    2472            0 :         VerifyOrReturn(builder.AddAttributePath(Clusters::NetworkCommissioning::Id,
    2473              :                                                 Clusters::NetworkCommissioning::Attributes::FeatureMap::Id));
    2474            0 :         VerifyOrReturn(builder.AddAttributePath(Clusters::NetworkCommissioning::Id,
    2475              :                                                 Clusters::NetworkCommissioning::Attributes::ConnectMaxTimeSeconds::Id));
    2476              : 
    2477              :         // If we were asked to do network scans, also read ScanMaxTimeSeconds,
    2478              :         // so we know how long to wait for those.
    2479            0 :         if (params.GetAttemptWiFiNetworkScan().ValueOr(false) || params.GetAttemptThreadNetworkScan().ValueOr(false))
    2480              :         {
    2481            0 :             VerifyOrReturn(builder.AddAttributePath(Clusters::NetworkCommissioning::Id,
    2482              :                                                     Clusters::NetworkCommissioning::Attributes::ScanMaxTimeSeconds::Id));
    2483              :         }
    2484              : 
    2485              :         // OperationalCredentials: existing fabrics, if necessary
    2486            0 :         if (params.GetCheckForMatchingFabric())
    2487              :         {
    2488            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::OperationalCredentials::Id,
    2489              :                                                     Clusters::OperationalCredentials::Attributes::Fabrics::Id));
    2490              :         }
    2491              : 
    2492              :         // ICD Management
    2493            0 :         if (params.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore)
    2494              :         {
    2495            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2496              :                                                     Clusters::IcdManagement::Attributes::FeatureMap::Id));
    2497            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2498              :                                                     Clusters::IcdManagement::Attributes::UserActiveModeTriggerHint::Id));
    2499            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2500              :                                                     Clusters::IcdManagement::Attributes::UserActiveModeTriggerInstruction::Id));
    2501            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2502              :                                                     Clusters::IcdManagement::Attributes::IdleModeDuration::Id));
    2503            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2504              :                                                     Clusters::IcdManagement::Attributes::ActiveModeDuration::Id));
    2505            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2506              :                                                     Clusters::IcdManagement::Attributes::ActiveModeThreshold::Id));
    2507            0 :             VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
    2508              :                                                     Clusters::IcdManagement::Attributes::ClusterRevision::Id));
    2509              :         }
    2510              : 
    2511              :         // Extra paths requested via CommissioningParameters
    2512            0 :         for (auto const & path : params.GetExtraReadPaths())
    2513              :         {
    2514            0 :             VerifyOrReturn(builder.AddAttributePath(path));
    2515              :         }
    2516            0 :     }();
    2517              : 
    2518            0 :     VerifyOrDie(builder.size() > 0); // our logic is broken if there is nothing to read
    2519            0 :     if (builder.exceeded())
    2520              :     {
    2521              :         // Keep track of the number of attributes we have read already so we can resume from there.
    2522            0 :         auto progress = mReadCommissioningInfoProgress + builder.size();
    2523            0 :         VerifyOrDie(progress < kReadProgressNoFurtherAttributes);
    2524            0 :         mReadCommissioningInfoProgress = static_cast<decltype(mReadCommissioningInfoProgress)>(progress);
    2525              :     }
    2526              :     else
    2527              :     {
    2528            0 :         mReadCommissioningInfoProgress = kReadProgressNoFurtherAttributes;
    2529              :     }
    2530              : 
    2531            0 :     SendCommissioningReadRequest(mDeviceBeingCommissioned, mCommissioningStepTimeout, builder.paths(), builder.size());
    2532              : }
    2533              : 
    2534              : namespace {
    2535            0 : void AccumulateErrors(CHIP_ERROR & acc, CHIP_ERROR err)
    2536              : {
    2537            0 :     if (acc == CHIP_NO_ERROR && err != CHIP_NO_ERROR)
    2538              :     {
    2539            0 :         acc = err;
    2540              :     }
    2541            0 : }
    2542              : } // namespace
    2543              : 
    2544            0 : void DeviceCommissioner::FinishReadingCommissioningInfo(const CommissioningParameters & params)
    2545              : {
    2546              :     // We want to parse as much information as possible, even if we eventually end
    2547              :     // up returning an error (e.g. because some mandatory information was missing).
    2548            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    2549            0 :     ReadCommissioningInfo info;
    2550            0 :     info.attributes = mAttributeCache.get();
    2551            0 :     AccumulateErrors(err, ParseGeneralCommissioningInfo(info));
    2552            0 :     AccumulateErrors(err, ParseBasicInformation(info));
    2553            0 :     AccumulateErrors(err, ParseNetworkCommissioningInfo(info));
    2554            0 :     AccumulateErrors(err, ParseTimeSyncInfo(info));
    2555            0 :     AccumulateErrors(err, ParseFabrics(info));
    2556            0 :     AccumulateErrors(err, ParseICDInfo(info));
    2557            0 :     AccumulateErrors(err, ParseExtraCommissioningInfo(info, params));
    2558              : 
    2559            0 :     if (mPairingDelegate != nullptr && err == CHIP_NO_ERROR)
    2560              :     {
    2561            0 :         mPairingDelegate->OnReadCommissioningInfo(info);
    2562              :     }
    2563              : 
    2564            0 :     CommissioningDelegate::CommissioningReport report;
    2565            0 :     report.Set<ReadCommissioningInfo>(info);
    2566            0 :     CommissioningStageComplete(err, report);
    2567              : 
    2568              :     // Only release the attribute cache once `info` is no longer needed.
    2569            0 :     mAttributeCache.reset();
    2570            0 : }
    2571              : 
    2572            0 : CHIP_ERROR DeviceCommissioner::ParseGeneralCommissioningInfo(ReadCommissioningInfo & info)
    2573              : {
    2574              :     using namespace GeneralCommissioning::Attributes;
    2575            0 :     CHIP_ERROR return_err = CHIP_NO_ERROR;
    2576              :     CHIP_ERROR err;
    2577              : 
    2578            0 :     BasicCommissioningInfo::TypeInfo::DecodableType basicInfo;
    2579            0 :     err = mAttributeCache->Get<BasicCommissioningInfo::TypeInfo>(kRootEndpointId, basicInfo);
    2580            0 :     if (err == CHIP_NO_ERROR)
    2581              :     {
    2582            0 :         info.general.recommendedFailsafe = basicInfo.failSafeExpiryLengthSeconds;
    2583              :     }
    2584              :     else
    2585              :     {
    2586            0 :         ChipLogError(Controller, "Failed to read BasicCommissioningInfo: %" CHIP_ERROR_FORMAT, err.Format());
    2587            0 :         return_err = err;
    2588              :     }
    2589              : 
    2590            0 :     err = mAttributeCache->Get<RegulatoryConfig::TypeInfo>(kRootEndpointId, info.general.currentRegulatoryLocation);
    2591            0 :     if (err != CHIP_NO_ERROR)
    2592              :     {
    2593            0 :         ChipLogError(Controller, "Failed to read RegulatoryConfig: %" CHIP_ERROR_FORMAT, err.Format());
    2594            0 :         return_err = err;
    2595              :     }
    2596              : 
    2597            0 :     err = mAttributeCache->Get<LocationCapability::TypeInfo>(kRootEndpointId, info.general.locationCapability);
    2598            0 :     if (err != CHIP_NO_ERROR)
    2599              :     {
    2600            0 :         ChipLogError(Controller, "Failed to read LocationCapability: %" CHIP_ERROR_FORMAT, err.Format());
    2601            0 :         return_err = err;
    2602              :     }
    2603              : 
    2604            0 :     err = mAttributeCache->Get<Breadcrumb::TypeInfo>(kRootEndpointId, info.general.breadcrumb);
    2605            0 :     if (err != CHIP_NO_ERROR)
    2606              :     {
    2607            0 :         ChipLogError(Controller, "Failed to read Breadcrumb: %" CHIP_ERROR_FORMAT, err.Format());
    2608            0 :         return_err = err;
    2609              :     }
    2610              : 
    2611            0 :     err = mAttributeCache->Get<SupportsConcurrentConnection::TypeInfo>(kRootEndpointId, info.supportsConcurrentConnection);
    2612            0 :     if (err != CHIP_NO_ERROR)
    2613              :     {
    2614            0 :         ChipLogError(Controller, "Ignoring failure to read SupportsConcurrentConnection: %" CHIP_ERROR_FORMAT, err.Format());
    2615            0 :         info.supportsConcurrentConnection = true; // default to true (concurrent), not a fatal error
    2616              :     }
    2617              : 
    2618            0 :     err = mAttributeCache->Get<IsCommissioningWithoutPower::TypeInfo>(kRootEndpointId, info.general.isCommissioningWithoutPower);
    2619            0 :     if (err != CHIP_NO_ERROR)
    2620              :     {
    2621              :         // 'IsCommissioningWithoutPower' is optional. Any failures (likely not present) means default to assuming false.
    2622            0 :         info.general.isCommissioningWithoutPower = false;
    2623              :     }
    2624              : 
    2625            0 :     return return_err;
    2626              : }
    2627              : 
    2628            0 : CHIP_ERROR DeviceCommissioner::ParseBasicInformation(ReadCommissioningInfo & info)
    2629              : {
    2630              :     using namespace BasicInformation::Attributes;
    2631            0 :     CHIP_ERROR return_err = CHIP_NO_ERROR;
    2632              :     CHIP_ERROR err;
    2633              : 
    2634            0 :     err = mAttributeCache->Get<VendorID::TypeInfo>(kRootEndpointId, info.basic.vendorId);
    2635            0 :     if (err != CHIP_NO_ERROR)
    2636              :     {
    2637            0 :         ChipLogError(Controller, "Failed to read VendorID: %" CHIP_ERROR_FORMAT, err.Format());
    2638            0 :         return_err = err;
    2639              :     }
    2640              : 
    2641            0 :     err = mAttributeCache->Get<ProductID::TypeInfo>(kRootEndpointId, info.basic.productId);
    2642            0 :     if (err != CHIP_NO_ERROR)
    2643              :     {
    2644            0 :         ChipLogError(Controller, "Failed to read ProductID: %" CHIP_ERROR_FORMAT, err.Format());
    2645            0 :         return_err = err;
    2646              :     }
    2647              : 
    2648            0 :     return return_err;
    2649              : }
    2650              : 
    2651            0 : CHIP_ERROR DeviceCommissioner::ParseNetworkCommissioningInfo(ReadCommissioningInfo & info)
    2652              : {
    2653              :     using namespace NetworkCommissioning::Attributes;
    2654            0 :     CHIP_ERROR return_err = CHIP_NO_ERROR;
    2655              :     CHIP_ERROR err;
    2656              : 
    2657              :     // Set the network cluster endpoints first so we can match up the connection
    2658              :     // times. Note that here we don't know what endpoints the network
    2659              :     // commissioning clusters might be on.
    2660            0 :     err = mAttributeCache->ForEachAttribute(NetworkCommissioning::Id, [this, &info](const ConcreteAttributePath & path) {
    2661            0 :         VerifyOrReturnError(path.mAttributeId == FeatureMap::Id, CHIP_NO_ERROR);
    2662            0 :         BitFlags<NetworkCommissioning::Feature> features;
    2663            0 :         if (mAttributeCache->Get<FeatureMap::TypeInfo>(path, *features.RawStorage()) == CHIP_NO_ERROR)
    2664              :         {
    2665            0 :             if (features.Has(NetworkCommissioning::Feature::kWiFiNetworkInterface))
    2666              :             {
    2667            0 :                 ChipLogProgress(Controller, "NetworkCommissioning Features: has WiFi. endpointid = %u", path.mEndpointId);
    2668            0 :                 info.network.wifi.endpoint = path.mEndpointId;
    2669              :             }
    2670            0 :             else if (features.Has(NetworkCommissioning::Feature::kThreadNetworkInterface))
    2671              :             {
    2672            0 :                 ChipLogProgress(Controller, "NetworkCommissioning Features: has Thread. endpointid = %u", path.mEndpointId);
    2673            0 :                 info.network.thread.endpoint = path.mEndpointId;
    2674              :             }
    2675            0 :             else if (features.Has(NetworkCommissioning::Feature::kEthernetNetworkInterface))
    2676              :             {
    2677            0 :                 ChipLogProgress(Controller, "NetworkCommissioning Features: has Ethernet. endpointid = %u", path.mEndpointId);
    2678            0 :                 info.network.eth.endpoint = path.mEndpointId;
    2679              :             }
    2680              :         }
    2681            0 :         return CHIP_NO_ERROR;
    2682              :     });
    2683            0 :     AccumulateErrors(return_err, err);
    2684              : 
    2685            0 :     if (info.network.thread.endpoint != kInvalidEndpointId)
    2686              :     {
    2687            0 :         err = ParseNetworkCommissioningTimeouts(info.network.thread, "Thread");
    2688            0 :         AccumulateErrors(return_err, err);
    2689              :     }
    2690              : 
    2691            0 :     if (info.network.wifi.endpoint != kInvalidEndpointId)
    2692              :     {
    2693            0 :         err = ParseNetworkCommissioningTimeouts(info.network.wifi, "Wi-Fi");
    2694            0 :         AccumulateErrors(return_err, err);
    2695              :     }
    2696              : 
    2697            0 :     if (return_err != CHIP_NO_ERROR)
    2698              :     {
    2699            0 :         ChipLogError(Controller, "Failed to parse Network Commissioning information: %" CHIP_ERROR_FORMAT, return_err.Format());
    2700              :     }
    2701            0 :     return return_err;
    2702              : }
    2703              : 
    2704            0 : CHIP_ERROR DeviceCommissioner::ParseNetworkCommissioningTimeouts(NetworkClusterInfo & networkInfo, const char * networkType)
    2705              : {
    2706              :     using namespace NetworkCommissioning::Attributes;
    2707              : 
    2708            0 :     CHIP_ERROR err = mAttributeCache->Get<ConnectMaxTimeSeconds::TypeInfo>(networkInfo.endpoint, networkInfo.minConnectionTime);
    2709            0 :     if (err != CHIP_NO_ERROR)
    2710              :     {
    2711            0 :         ChipLogError(Controller, "Failed to read %s ConnectMaxTimeSeconds (endpoint %u): %" CHIP_ERROR_FORMAT, networkType,
    2712              :                      networkInfo.endpoint, err.Format());
    2713            0 :         return err;
    2714              :     }
    2715              : 
    2716            0 :     err = mAttributeCache->Get<ScanMaxTimeSeconds::TypeInfo>(networkInfo.endpoint, networkInfo.maxScanTime);
    2717            0 :     if (err != CHIP_NO_ERROR)
    2718              :     {
    2719              :         // We don't always read this attribute, and we read it as a wildcard, so
    2720              :         // don't treat it as an error simply because it's missing.
    2721            0 :         if (err != CHIP_ERROR_KEY_NOT_FOUND)
    2722              :         {
    2723            0 :             ChipLogError(Controller, "Failed to read %s ScanMaxTimeSeconds (endpoint: %u): %" CHIP_ERROR_FORMAT, networkType,
    2724              :                          networkInfo.endpoint, err.Format());
    2725            0 :             return err;
    2726              :         }
    2727              : 
    2728              :         // Just flag as "we don't know".
    2729            0 :         networkInfo.maxScanTime = 0;
    2730              :     }
    2731              : 
    2732            0 :     return CHIP_NO_ERROR;
    2733              : }
    2734              : 
    2735            0 : CHIP_ERROR DeviceCommissioner::ParseTimeSyncInfo(ReadCommissioningInfo & info)
    2736              : {
    2737              :     using namespace TimeSynchronization::Attributes;
    2738              :     CHIP_ERROR err;
    2739              : 
    2740              :     // If we fail to get the feature map, there's no viable time cluster, don't set anything.
    2741            0 :     BitFlags<TimeSynchronization::Feature> featureMap;
    2742            0 :     err = mAttributeCache->Get<FeatureMap::TypeInfo>(kRootEndpointId, *featureMap.RawStorage());
    2743            0 :     if (err != CHIP_NO_ERROR)
    2744              :     {
    2745            0 :         info.requiresUTC               = false;
    2746            0 :         info.requiresTimeZone          = false;
    2747            0 :         info.requiresDefaultNTP        = false;
    2748            0 :         info.requiresTrustedTimeSource = false;
    2749            0 :         return CHIP_NO_ERROR;
    2750              :     }
    2751            0 :     info.requiresUTC               = true;
    2752            0 :     info.requiresTimeZone          = featureMap.Has(TimeSynchronization::Feature::kTimeZone);
    2753            0 :     info.requiresDefaultNTP        = featureMap.Has(TimeSynchronization::Feature::kNTPClient);
    2754            0 :     info.requiresTrustedTimeSource = featureMap.Has(TimeSynchronization::Feature::kTimeSyncClient);
    2755              : 
    2756            0 :     if (info.requiresTimeZone)
    2757              :     {
    2758            0 :         err = mAttributeCache->Get<TimeZoneListMaxSize::TypeInfo>(kRootEndpointId, info.maxTimeZoneSize);
    2759            0 :         if (err != CHIP_NO_ERROR)
    2760              :         {
    2761              :             // This information should be available, let's do our best with what we have, but we can't set
    2762              :             // the time zone without this information
    2763            0 :             info.requiresTimeZone = false;
    2764              :         }
    2765            0 :         err = mAttributeCache->Get<DSTOffsetListMaxSize::TypeInfo>(kRootEndpointId, info.maxDSTSize);
    2766            0 :         if (err != CHIP_NO_ERROR)
    2767              :         {
    2768            0 :             info.requiresTimeZone = false;
    2769              :         }
    2770              :     }
    2771            0 :     if (info.requiresDefaultNTP)
    2772              :     {
    2773            0 :         DefaultNTP::TypeInfo::DecodableType defaultNTP;
    2774            0 :         err = mAttributeCache->Get<DefaultNTP::TypeInfo>(kRootEndpointId, defaultNTP);
    2775            0 :         if (err == CHIP_NO_ERROR && (!defaultNTP.IsNull()) && (defaultNTP.Value().size() != 0))
    2776              :         {
    2777            0 :             info.requiresDefaultNTP = false;
    2778              :         }
    2779              :     }
    2780            0 :     if (info.requiresTrustedTimeSource)
    2781              :     {
    2782            0 :         TrustedTimeSource::TypeInfo::DecodableType trustedTimeSource;
    2783            0 :         err = mAttributeCache->Get<TrustedTimeSource::TypeInfo>(kRootEndpointId, trustedTimeSource);
    2784            0 :         if (err == CHIP_NO_ERROR && !trustedTimeSource.IsNull())
    2785              :         {
    2786            0 :             info.requiresTrustedTimeSource = false;
    2787              :         }
    2788              :     }
    2789              : 
    2790            0 :     return CHIP_NO_ERROR;
    2791              : }
    2792              : 
    2793            0 : CHIP_ERROR DeviceCommissioner::ParseFabrics(ReadCommissioningInfo & info)
    2794              : {
    2795              :     using namespace OperationalCredentials::Attributes;
    2796              :     CHIP_ERROR err;
    2797            0 :     CHIP_ERROR return_err = CHIP_NO_ERROR;
    2798              : 
    2799              :     // We might not have requested a Fabrics attribute at all, so not having a
    2800              :     // value for it is not an error.
    2801            0 :     err = mAttributeCache->ForEachAttribute(OperationalCredentials::Id, [this, &info](const ConcreteAttributePath & path) {
    2802              :         using namespace chip::app::Clusters::OperationalCredentials::Attributes;
    2803              :         // this code is checking if the device is already on the commissioner's fabric.
    2804              :         // if a matching fabric is found, then remember the nodeId so that the commissioner
    2805              :         // can, if it decides to, cancel commissioning (before it fails in AddNoc) and know
    2806              :         // the device's nodeId on its fabric.
    2807            0 :         switch (path.mAttributeId)
    2808              :         {
    2809            0 :         case Fabrics::Id: {
    2810            0 :             Fabrics::TypeInfo::DecodableType fabrics;
    2811            0 :             ReturnErrorOnFailure(this->mAttributeCache->Get<Fabrics::TypeInfo>(path, fabrics));
    2812              :             // this is a best effort attempt to find a matching fabric, so no error checking on iter
    2813            0 :             auto iter = fabrics.begin();
    2814            0 :             while (iter.Next())
    2815              :             {
    2816            0 :                 auto & fabricDescriptor = iter.GetValue();
    2817            0 :                 ChipLogProgress(Controller,
    2818              :                                 "DeviceCommissioner::OnDone - fabric.vendorId=0x%04X fabric.fabricId=0x" ChipLogFormatX64
    2819              :                                 " fabric.nodeId=0x" ChipLogFormatX64,
    2820              :                                 fabricDescriptor.vendorID, ChipLogValueX64(fabricDescriptor.fabricID),
    2821              :                                 ChipLogValueX64(fabricDescriptor.nodeID));
    2822            0 :                 if (GetFabricId() == fabricDescriptor.fabricID)
    2823              :                 {
    2824            0 :                     ChipLogProgress(Controller, "DeviceCommissioner::OnDone - found a matching fabric id");
    2825            0 :                     chip::ByteSpan rootKeySpan = fabricDescriptor.rootPublicKey;
    2826            0 :                     if (rootKeySpan.size() != Crypto::kP256_PublicKey_Length)
    2827              :                     {
    2828            0 :                         ChipLogError(Controller, "DeviceCommissioner::OnDone - fabric root key size mismatch %u != %u",
    2829              :                                      static_cast<unsigned>(rootKeySpan.size()),
    2830              :                                      static_cast<unsigned>(Crypto::kP256_PublicKey_Length));
    2831            0 :                         continue;
    2832              :                     }
    2833            0 :                     P256PublicKeySpan rootPubKeySpan(rootKeySpan.data());
    2834            0 :                     Crypto::P256PublicKey deviceRootPublicKey(rootPubKeySpan);
    2835              : 
    2836            0 :                     Crypto::P256PublicKey commissionerRootPublicKey;
    2837            0 :                     if (CHIP_NO_ERROR != GetRootPublicKey(commissionerRootPublicKey))
    2838              :                     {
    2839            0 :                         ChipLogError(Controller, "DeviceCommissioner::OnDone - error reading commissioner root public key");
    2840              :                     }
    2841            0 :                     else if (commissionerRootPublicKey.Matches(deviceRootPublicKey))
    2842              :                     {
    2843            0 :                         ChipLogProgress(Controller, "DeviceCommissioner::OnDone - fabric root keys match");
    2844            0 :                         info.remoteNodeId = fabricDescriptor.nodeID;
    2845              :                     }
    2846            0 :                 }
    2847              :             }
    2848              : 
    2849            0 :             return CHIP_NO_ERROR;
    2850              :         }
    2851            0 :         default:
    2852            0 :             return CHIP_NO_ERROR;
    2853              :         }
    2854              :     });
    2855              : 
    2856            0 :     if (mPairingDelegate != nullptr)
    2857              :     {
    2858            0 :         mPairingDelegate->OnFabricCheck(info.remoteNodeId);
    2859              :     }
    2860              : 
    2861            0 :     return return_err;
    2862              : }
    2863              : 
    2864            2 : CHIP_ERROR DeviceCommissioner::ParseICDInfo(ReadCommissioningInfo & info)
    2865              : {
    2866              :     using namespace IcdManagement::Attributes;
    2867              :     CHIP_ERROR err;
    2868              : 
    2869            2 :     bool hasUserActiveModeTrigger = false;
    2870            2 :     bool isICD                    = false;
    2871              : 
    2872            2 :     BitFlags<IcdManagement::Feature> featureMap;
    2873            2 :     err = mAttributeCache->Get<FeatureMap::TypeInfo>(kRootEndpointId, *featureMap.RawStorage());
    2874            4 :     if (err == CHIP_NO_ERROR)
    2875              :     {
    2876            2 :         info.icd.isLIT                  = featureMap.Has(IcdManagement::Feature::kLongIdleTimeSupport);
    2877            2 :         info.icd.checkInProtocolSupport = featureMap.Has(IcdManagement::Feature::kCheckInProtocolSupport);
    2878            2 :         hasUserActiveModeTrigger        = featureMap.Has(IcdManagement::Feature::kUserActiveModeTrigger);
    2879            2 :         isICD                           = true;
    2880              : 
    2881              :         // LIT support was introduced but broken in ICD Management cluster revision 2 (Matter 1.3).
    2882              :         // Only treat a device as LIT for cluster revisions after 1.3 (i.e., revision > 2).
    2883            2 :         if (info.icd.isLIT)
    2884              :         {
    2885            2 :             uint16_t clusterRevision = 0;
    2886            2 :             CHIP_ERROR revErr        = mAttributeCache->Get<ClusterRevision::TypeInfo>(kRootEndpointId, clusterRevision);
    2887            4 :             if (revErr != CHIP_NO_ERROR || clusterRevision <= 2)
    2888              :             {
    2889            2 :                 if (revErr == CHIP_NO_ERROR)
    2890              :                 {
    2891            1 :                     ChipLogProgress(Controller,
    2892              :                                     "IcdManagement: Device claims LIT support but cluster revision is %" PRIu16
    2893              :                                     " (Matter 1.3). Disabling LIT due to known Matter 1.3 LIT issues.",
    2894              :                                     clusterRevision);
    2895              :                 }
    2896              :                 else
    2897              :                 {
    2898            0 :                     ChipLogProgress(Controller,
    2899              :                                     "IcdManagement: Device claims LIT support but ClusterRevision attribute is "
    2900              :                                     "missing or unreadable (err=%" CHIP_ERROR_FORMAT
    2901              :                                     "). Treating as revision <= 2 and disabling LIT.",
    2902              :                                     revErr.Format());
    2903              :                 }
    2904            1 :                 info.icd.isLIT = false;
    2905              :             }
    2906              :         }
    2907              :     }
    2908            0 :     else if (err == CHIP_ERROR_KEY_NOT_FOUND)
    2909              :     {
    2910              :         // This key is optional so not an error
    2911            0 :         info.icd.isLIT = false;
    2912            0 :         err            = CHIP_NO_ERROR;
    2913              :     }
    2914            0 :     else if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
    2915              :     {
    2916            0 :         app::StatusIB statusIB;
    2917            0 :         err = mAttributeCache->GetStatus(app::ConcreteAttributePath(kRootEndpointId, IcdManagement::Id, FeatureMap::Id), statusIB);
    2918            0 :         if (err == CHIP_NO_ERROR)
    2919              :         {
    2920            0 :             if (statusIB.mStatus == Protocols::InteractionModel::Status::UnsupportedCluster)
    2921              :             {
    2922            0 :                 info.icd.isLIT = false;
    2923              :             }
    2924              :             else
    2925              :             {
    2926            0 :                 err = statusIB.ToChipError();
    2927              :             }
    2928              :         }
    2929              :     }
    2930              : 
    2931            2 :     ReturnErrorOnFailure(err);
    2932              : 
    2933            2 :     info.icd.userActiveModeTriggerHint.ClearAll();
    2934            2 :     info.icd.userActiveModeTriggerInstruction = CharSpan();
    2935              : 
    2936            2 :     if (hasUserActiveModeTrigger)
    2937              :     {
    2938              :         // Intentionally ignore errors since they are not mandatory.
    2939            0 :         bool activeModeTriggerInstructionRequired = false;
    2940              : 
    2941            0 :         err = mAttributeCache->Get<UserActiveModeTriggerHint::TypeInfo>(kRootEndpointId, info.icd.userActiveModeTriggerHint);
    2942            0 :         if (err != CHIP_NO_ERROR)
    2943              :         {
    2944            0 :             ChipLogError(Controller, "IcdManagement.UserActiveModeTriggerHint expected, but failed to read.");
    2945            0 :             return err;
    2946              :         }
    2947              : 
    2948              :         using IcdManagement::UserActiveModeTriggerBitmap;
    2949            0 :         activeModeTriggerInstructionRequired = info.icd.userActiveModeTriggerHint.HasAny(
    2950            0 :             UserActiveModeTriggerBitmap::kCustomInstruction, UserActiveModeTriggerBitmap::kActuateSensorSeconds,
    2951            0 :             UserActiveModeTriggerBitmap::kActuateSensorTimes, UserActiveModeTriggerBitmap::kActuateSensorLightsBlink,
    2952            0 :             UserActiveModeTriggerBitmap::kResetButtonLightsBlink, UserActiveModeTriggerBitmap::kResetButtonSeconds,
    2953            0 :             UserActiveModeTriggerBitmap::kResetButtonTimes, UserActiveModeTriggerBitmap::kSetupButtonSeconds,
    2954            0 :             UserActiveModeTriggerBitmap::kSetupButtonTimes, UserActiveModeTriggerBitmap::kSetupButtonTimes,
    2955            0 :             UserActiveModeTriggerBitmap::kAppDefinedButton);
    2956              : 
    2957            0 :         if (activeModeTriggerInstructionRequired)
    2958              :         {
    2959            0 :             err = mAttributeCache->Get<UserActiveModeTriggerInstruction::TypeInfo>(kRootEndpointId,
    2960            0 :                                                                                    info.icd.userActiveModeTriggerInstruction);
    2961            0 :             if (err != CHIP_NO_ERROR)
    2962              :             {
    2963            0 :                 ChipLogError(Controller,
    2964              :                              "IcdManagement.UserActiveModeTriggerInstruction expected for given active mode trigger hint, but "
    2965              :                              "failed to read.");
    2966            0 :                 return err;
    2967              :             }
    2968              :         }
    2969              :     }
    2970              : 
    2971            2 :     if (!isICD)
    2972              :     {
    2973            0 :         info.icd.idleModeDuration    = 0;
    2974            0 :         info.icd.activeModeDuration  = 0;
    2975            0 :         info.icd.activeModeThreshold = 0;
    2976            0 :         return CHIP_NO_ERROR;
    2977              :     }
    2978              : 
    2979            2 :     err = mAttributeCache->Get<IdleModeDuration::TypeInfo>(kRootEndpointId, info.icd.idleModeDuration);
    2980            4 :     if (err != CHIP_NO_ERROR)
    2981              :     {
    2982            0 :         ChipLogError(Controller, "IcdManagement.IdleModeDuration expected, but failed to read: %" CHIP_ERROR_FORMAT, err.Format());
    2983            0 :         return err;
    2984              :     }
    2985              : 
    2986            2 :     err = mAttributeCache->Get<ActiveModeDuration::TypeInfo>(kRootEndpointId, info.icd.activeModeDuration);
    2987            4 :     if (err != CHIP_NO_ERROR)
    2988              :     {
    2989            0 :         ChipLogError(Controller, "IcdManagement.ActiveModeDuration expected, but failed to read: %" CHIP_ERROR_FORMAT,
    2990              :                      err.Format());
    2991            0 :         return err;
    2992              :     }
    2993              : 
    2994            2 :     err = mAttributeCache->Get<ActiveModeThreshold::TypeInfo>(kRootEndpointId, info.icd.activeModeThreshold);
    2995            4 :     if (err != CHIP_NO_ERROR)
    2996              :     {
    2997            0 :         ChipLogError(Controller, "IcdManagement.ActiveModeThreshold expected, but failed to read: %" CHIP_ERROR_FORMAT,
    2998              :                      err.Format());
    2999              :     }
    3000              : 
    3001            2 :     return err;
    3002              : }
    3003              : 
    3004            0 : void DeviceCommissioner::OnArmFailSafe(void * context,
    3005              :                                        const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
    3006              : {
    3007            0 :     CommissioningDelegate::CommissioningReport report;
    3008            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    3009              : 
    3010            0 :     ChipLogProgress(Controller, "Received ArmFailSafe response errorCode=%u", to_underlying(data.errorCode));
    3011            0 :     if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
    3012              :     {
    3013            0 :         err = CHIP_ERROR_INTERNAL;
    3014              :         // Preserve the device-supplied debugText so failure consumers can disambiguate
    3015              :         // ambiguous error codes (e.g. kBusyWithOtherAdmin specifics).
    3016            0 :         report.Set<CommissioningErrorInfo>(data.errorCode, data.debugText);
    3017              :     }
    3018              : 
    3019            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3020            0 :     commissioner->CommissioningStageComplete(err, report);
    3021            0 : }
    3022              : 
    3023            0 : void DeviceCommissioner::OnSetRegulatoryConfigResponse(
    3024              :     void * context, const GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data)
    3025              : {
    3026            0 :     CommissioningDelegate::CommissioningReport report;
    3027            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    3028              : 
    3029            0 :     ChipLogProgress(Controller, "Received SetRegulatoryConfig response errorCode=%u", to_underlying(data.errorCode));
    3030            0 :     if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
    3031              :     {
    3032            0 :         err = CHIP_ERROR_INTERNAL;
    3033            0 :         report.Set<CommissioningErrorInfo>(data.errorCode, data.debugText);
    3034              :     }
    3035            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3036            0 :     commissioner->CommissioningStageComplete(err, report);
    3037            0 : }
    3038              : 
    3039            0 : void DeviceCommissioner::OnSetTCAcknowledgementsResponse(
    3040              :     void * context, const GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data)
    3041              : {
    3042            0 :     CommissioningDelegate::CommissioningReport report;
    3043            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    3044              : 
    3045            0 :     ChipLogProgress(Controller, "Received SetTCAcknowledgements response errorCode=%u", to_underlying(data.errorCode));
    3046            0 :     if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
    3047              :     {
    3048            0 :         err = CHIP_ERROR_INTERNAL;
    3049              :         // SetTCAcknowledgementsResponse has no debugText field per spec.
    3050            0 :         report.Set<CommissioningErrorInfo>(data.errorCode);
    3051              :     }
    3052            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3053            0 :     commissioner->CommissioningStageComplete(err, report);
    3054            0 : }
    3055              : 
    3056            0 : void DeviceCommissioner::OnSetTimeZoneResponse(void * context,
    3057              :                                                const TimeSynchronization::Commands::SetTimeZoneResponse::DecodableType & data)
    3058              : {
    3059            0 :     CommissioningDelegate::CommissioningReport report;
    3060            0 :     CHIP_ERROR err                    = CHIP_NO_ERROR;
    3061            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3062              :     TimeZoneResponseInfo info;
    3063            0 :     info.requiresDSTOffsets = data.DSTOffsetRequired;
    3064            0 :     report.Set<TimeZoneResponseInfo>(info);
    3065            0 :     commissioner->CommissioningStageComplete(err, report);
    3066            0 : }
    3067              : 
    3068            0 : void DeviceCommissioner::OnSetUTCError(void * context, CHIP_ERROR error)
    3069              : {
    3070              :     // For SetUTCTime, we don't actually care if the commissionee didn't want out time, that's its choice
    3071            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3072            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
    3073            0 : }
    3074              : 
    3075            0 : void DeviceCommissioner::OnScanNetworksFailure(void * context, CHIP_ERROR error)
    3076              : {
    3077            0 :     ChipLogProgress(Controller, "Received ScanNetworks failure response %" CHIP_ERROR_FORMAT, error.Format());
    3078              : 
    3079            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3080              : 
    3081              :     // advance to the kNeedsNetworkCreds waiting step
    3082              :     // clear error so that we don't abort the commissioning when ScanNetworks fails
    3083            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
    3084              : 
    3085            0 :     if (commissioner->GetPairingDelegate() != nullptr)
    3086              :     {
    3087            0 :         commissioner->GetPairingDelegate()->OnScanNetworksFailure(error);
    3088              :     }
    3089            0 : }
    3090              : 
    3091            0 : void DeviceCommissioner::OnScanNetworksResponse(void * context,
    3092              :                                                 const NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & data)
    3093              : {
    3094            0 :     CommissioningDelegate::CommissioningReport report;
    3095              : 
    3096            0 :     ChipLogProgress(Controller, "Received ScanNetwork response, networkingStatus=%u debugText=%s",
    3097              :                     to_underlying(data.networkingStatus),
    3098              :                     (data.debugText.HasValue() ? std::string(data.debugText.Value().data(), data.debugText.Value().size()).c_str()
    3099              :                                                : "none provided"));
    3100            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3101              : 
    3102              :     // advance to the kNeedsNetworkCreds waiting step
    3103            0 :     commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
    3104              : 
    3105            0 :     if (commissioner->GetPairingDelegate() != nullptr)
    3106              :     {
    3107            0 :         commissioner->GetPairingDelegate()->OnScanNetworksSuccess(data);
    3108              :     }
    3109            0 : }
    3110              : 
    3111            0 : CHIP_ERROR DeviceCommissioner::NetworkCredentialsReady()
    3112              : {
    3113            0 :     VerifyOrReturnError(mCommissioningStage == CommissioningStage::kNeedsNetworkCreds, CHIP_ERROR_INCORRECT_STATE);
    3114              : 
    3115              :     // need to advance to next step
    3116            0 :     CommissioningStageComplete(CHIP_NO_ERROR);
    3117              : 
    3118            0 :     return CHIP_NO_ERROR;
    3119              : }
    3120              : 
    3121            0 : CHIP_ERROR DeviceCommissioner::ICDRegistrationInfoReady()
    3122              : {
    3123            0 :     VerifyOrReturnError(mCommissioningStage == CommissioningStage::kICDGetRegistrationInfo, CHIP_ERROR_INCORRECT_STATE);
    3124              : 
    3125              :     // need to advance to next step
    3126            0 :     CommissioningStageComplete(CHIP_NO_ERROR);
    3127              : 
    3128            0 :     return CHIP_NO_ERROR;
    3129              : }
    3130              : 
    3131            0 : void DeviceCommissioner::OnNetworkConfigResponse(void * context,
    3132              :                                                  const NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data)
    3133              : {
    3134            0 :     CommissioningDelegate::CommissioningReport report;
    3135            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    3136              : 
    3137            0 :     ChipLogProgress(Controller, "Received NetworkConfig response, networkingStatus=%u", to_underlying(data.networkingStatus));
    3138            0 :     if (data.networkingStatus != NetworkCommissioning::NetworkCommissioningStatusEnum::kSuccess)
    3139              :     {
    3140            0 :         err = CHIP_ERROR_INTERNAL;
    3141              :         // Preserve debugText alongside the status enum so callers can distinguish
    3142              :         // ambiguous statuses (e.g. kAuthFailure: "wrong password" vs "regulatory restriction").
    3143            0 :         report.Set<NetworkCommissioningStatusInfo>(data.networkingStatus, data.debugText.ValueOr(CharSpan{}));
    3144              :     }
    3145            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3146            0 :     commissioner->CommissioningStageComplete(err, report);
    3147            0 : }
    3148              : 
    3149            0 : void DeviceCommissioner::OnConnectNetworkResponse(
    3150              :     void * context, const NetworkCommissioning::Commands::ConnectNetworkResponse::DecodableType & data)
    3151              : {
    3152            0 :     CommissioningDelegate::CommissioningReport report;
    3153            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    3154              : 
    3155            0 :     ChipLogProgress(Controller, "Received ConnectNetwork response, networkingStatus=%u", to_underlying(data.networkingStatus));
    3156            0 :     if (data.networkingStatus != NetworkCommissioning::NetworkCommissioningStatusEnum::kSuccess)
    3157              :     {
    3158            0 :         err = CHIP_ERROR_INTERNAL;
    3159              :         // Preserve debugText alongside the status enum (see OnNetworkConfigResponse). Also
    3160              :         // surface the device-specific errorValue which carries driver-level failure detail
    3161              :         // (TX-power-limited / interference / association-failure code) distinct from the
    3162              :         // spec-level networkingStatus enum.
    3163            0 :         Optional<int32_t> errorValue = data.errorValue.IsNull() ? NullOptional : MakeOptional(data.errorValue.Value());
    3164            0 :         report.Set<NetworkCommissioningStatusInfo>(data.networkingStatus, data.debugText.ValueOr(CharSpan{}), errorValue);
    3165              :     }
    3166            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3167            0 :     commissioner->CommissioningStageComplete(err, report);
    3168            0 : }
    3169              : 
    3170            0 : void DeviceCommissioner::OnCommissioningCompleteResponse(
    3171              :     void * context, const GeneralCommissioning::Commands::CommissioningCompleteResponse::DecodableType & data)
    3172              : {
    3173            0 :     CommissioningDelegate::CommissioningReport report;
    3174            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
    3175              : 
    3176            0 :     ChipLogProgress(Controller, "Received CommissioningComplete response, errorCode=%u", to_underlying(data.errorCode));
    3177            0 :     if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
    3178              :     {
    3179            0 :         err = CHIP_ERROR_INTERNAL;
    3180            0 :         report.Set<CommissioningErrorInfo>(data.errorCode, data.debugText);
    3181              :     }
    3182            0 :     DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
    3183            0 :     commissioner->CommissioningStageComplete(err, report);
    3184            0 : }
    3185              : 
    3186              : template <typename RequestObjectT>
    3187              : CHIP_ERROR
    3188            0 : DeviceCommissioner::SendCommissioningCommand(DeviceProxy * device, const RequestObjectT & request,
    3189              :                                              CommandResponseSuccessCallback<typename RequestObjectT::ResponseType> successCb,
    3190              :                                              CommandResponseFailureCallback failureCb, EndpointId endpoint,
    3191              :                                              Optional<System::Clock::Timeout> timeout, bool fireAndForget)
    3192              : 
    3193              : {
    3194              :     // Default behavior is to make sequential, cancellable calls tracked via mInvokeCancelFn.
    3195              :     // Fire-and-forget calls are not cancellable and don't receive `this` as context in callbacks.
    3196            0 :     VerifyOrDie(fireAndForget || !mInvokeCancelFn); // we don't make parallel (cancellable) calls
    3197              : 
    3198            0 :     void * context   = (!fireAndForget) ? this : nullptr;
    3199            0 :     auto onSuccessCb = [context, successCb](const app::ConcreteCommandPath & aPath, const app::StatusIB & aStatus,
    3200              :                                             const typename RequestObjectT::ResponseType & responseData) {
    3201            0 :         successCb(context, responseData);
    3202              :     };
    3203            0 :     auto onFailureCb = [context, failureCb](CHIP_ERROR aError) { failureCb(context, aError); };
    3204              : 
    3205            0 :     return InvokeCommandRequest(device->GetExchangeManager(), device->GetSecureSession().Value(), endpoint, request, onSuccessCb,
    3206            0 :                                 onFailureCb, NullOptional, timeout, (!fireAndForget) ? &mInvokeCancelFn : nullptr);
    3207              : }
    3208              : 
    3209              : template <typename AttrType>
    3210              : CHIP_ERROR DeviceCommissioner::SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster,
    3211              :                                                              AttributeId attribute, const AttrType & requestData,
    3212              :                                                              WriteResponseSuccessCallback successCb,
    3213              :                                                              WriteResponseFailureCallback failureCb)
    3214              : {
    3215              :     VerifyOrDie(!mWriteCancelFn); // we don't make parallel (cancellable) calls
    3216              :     auto onSuccessCb = [this, successCb](const app::ConcreteAttributePath & aPath) { successCb(this); };
    3217              :     auto onFailureCb = [this, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) { failureCb(this, aError); };
    3218              :     return WriteAttribute(device->GetSecureSession().Value(), endpoint, cluster, attribute, requestData, onSuccessCb, onFailureCb,
    3219              :                           /* aTimedWriteTimeoutMs = */ NullOptional, /* onDoneCb = */ nullptr, /* aDataVersion = */ NullOptional,
    3220              :                           /* outCancelFn = */ &mWriteCancelFn);
    3221              : }
    3222              : 
    3223            0 : void DeviceCommissioner::SendCommissioningReadRequest(DeviceProxy * proxy, Optional<System::Clock::Timeout> timeout,
    3224              :                                                       app::AttributePathParams * readPaths, size_t readPathsSize)
    3225              : {
    3226            0 :     VerifyOrDie(!mReadClient); // we don't perform parallel reads
    3227              : 
    3228            0 :     app::InteractionModelEngine * engine = app::InteractionModelEngine::GetInstance();
    3229            0 :     app::ReadPrepareParams readParams(proxy->GetSecureSession().Value());
    3230            0 :     readParams.mIsFabricFiltered = false;
    3231            0 :     if (timeout.HasValue())
    3232              :     {
    3233            0 :         readParams.mTimeout = timeout.Value();
    3234              :     }
    3235            0 :     readParams.mpAttributePathParamsList    = readPaths;
    3236            0 :     readParams.mAttributePathParamsListSize = readPathsSize;
    3237              : 
    3238              :     // Take ownership of the attribute cache, so it can be released if SendRequest fails.
    3239            0 :     auto attributeCache = std::move(mAttributeCache);
    3240              :     auto readClient     = chip::Platform::MakeUnique<app::ReadClient>(
    3241            0 :         engine, proxy->GetExchangeManager(), attributeCache->GetBufferedCallback(), app::ReadClient::InteractionType::Read);
    3242            0 :     CHIP_ERROR err = readClient->SendRequest(readParams);
    3243            0 :     if (err != CHIP_NO_ERROR)
    3244              :     {
    3245            0 :         ChipLogError(Controller, "Failed to send read request: %" CHIP_ERROR_FORMAT, err.Format());
    3246            0 :         CommissioningStageComplete(err);
    3247            0 :         return;
    3248              :     }
    3249            0 :     mAttributeCache = std::move(attributeCache);
    3250            0 :     mReadClient     = std::move(readClient);
    3251            0 : }
    3252              : 
    3253            0 : void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, CommissioningStage step, CommissioningParameters & params,
    3254              :                                                   CommissioningDelegate * delegate, EndpointId endpoint,
    3255              :                                                   Optional<System::Clock::Timeout> timeout)
    3256              : 
    3257              : {
    3258              :     MATTER_LOG_METRIC(kMetricDeviceCommissionerCommissionStage, step);
    3259              :     MATTER_LOG_METRIC_BEGIN(MetricKeyForCommissioningStage(step));
    3260              : 
    3261            0 :     if (params.GetCompletionStatus().err == CHIP_NO_ERROR)
    3262              :     {
    3263            0 :         ChipLogProgress(Controller, "Performing next commissioning step '%s'", StageToString(step));
    3264              :     }
    3265              :     else
    3266              :     {
    3267            0 :         ChipLogProgress(Controller, "Performing next commissioning step '%s' with completion status = '%s'", StageToString(step),
    3268              :                         params.GetCompletionStatus().err.AsString());
    3269              :     }
    3270              : 
    3271            0 :     if (mPairingDelegate)
    3272              :     {
    3273            0 :         mPairingDelegate->OnCommissioningStageStart(PeerId(GetCompressedFabricId(), proxy->GetDeviceId()), step);
    3274              :     }
    3275              : 
    3276            0 :     mCommissioningStepTimeout = timeout;
    3277            0 :     mCommissioningStage       = step;
    3278            0 :     mCommissioningDelegate    = delegate;
    3279            0 :     mDeviceBeingCommissioned  = proxy;
    3280              : 
    3281              :     // TODO: Extend timeouts to the DAC and Opcert requests.
    3282              :     // TODO(cecille): We probably want something better than this for breadcrumbs.
    3283            0 :     uint64_t breadcrumb = static_cast<uint64_t>(step);
    3284              : 
    3285            0 :     switch (step)
    3286              :     {
    3287            0 :     case CommissioningStage::kArmFailsafe: {
    3288            0 :         VerifyOrDie(endpoint == kRootEndpointId);
    3289              :         // Make sure the fail-safe value we set here actually ends up being used
    3290              :         // no matter what.
    3291            0 :         proxy->SetFailSafeExpirationTimestamp(System::Clock::kZero);
    3292            0 :         VerifyOrDie(ExtendArmFailSafeInternal(proxy, step, params.GetFailsafeTimerSeconds().ValueOr(kDefaultFailsafeTimeout),
    3293              :                                               timeout, OnArmFailSafe, OnBasicFailure, /* fireAndForget = */ false));
    3294              :     }
    3295            0 :     break;
    3296            0 :     case CommissioningStage::kReadCommissioningInfo: {
    3297            0 :         VerifyOrDie(endpoint == kRootEndpointId);
    3298            0 :         ChipLogProgress(Controller, "Sending read requests for commissioning information");
    3299              : 
    3300              :         // Allocate a ClusterStateCache to collect the data from our read requests.
    3301              :         // The cache will be released in:
    3302              :         // - SendCommissioningReadRequest when failing to send a read request.
    3303              :         // - FinishReadingCommissioningInfo when the ReadCommissioningInfo stage is completed.
    3304              :         // - CancelCommissioningInteractions
    3305            0 :         mAttributeCache = Platform::MakeUnique<app::ClusterStateCache>(*this);
    3306              : 
    3307              :         // Generally we need to make more than one read request, because as per spec a server only
    3308              :         // supports a limited number of paths per Read Interaction. Because the actual number of
    3309              :         // interactions we end up performing is dynamic, we track all of them within a single
    3310              :         // commissioning stage.
    3311            0 :         mReadCommissioningInfoProgress = 0;
    3312            0 :         ContinueReadingCommissioningInfo(params); // Note: assume params == delegate.GetCommissioningParameters()
    3313            0 :         break;
    3314              :     }
    3315            0 :     case CommissioningStage::kConfigureUTCTime: {
    3316            0 :         TimeSynchronization::Commands::SetUTCTime::Type request;
    3317            0 :         uint64_t kChipEpochUsSinceUnixEpoch = static_cast<uint64_t>(kChipEpochSecondsSinceUnixEpoch) * chip::kMicrosecondsPerSecond;
    3318              :         System::Clock::Microseconds64 utcTime;
    3319            0 :         if (System::SystemClock().GetClock_RealTime(utcTime) != CHIP_NO_ERROR || utcTime.count() <= kChipEpochUsSinceUnixEpoch)
    3320              :         {
    3321              :             // We have no time to give, but that's OK, just complete this stage
    3322            0 :             CommissioningStageComplete(CHIP_NO_ERROR);
    3323            0 :             return;
    3324              :         }
    3325              : 
    3326            0 :         request.UTCTime = utcTime.count() - kChipEpochUsSinceUnixEpoch;
    3327              :         // For now, we assume a seconds granularity
    3328            0 :         request.granularity = TimeSynchronization::GranularityEnum::kSecondsGranularity;
    3329            0 :         CHIP_ERROR err      = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnSetUTCError, endpoint, timeout);
    3330            0 :         if (err != CHIP_NO_ERROR)
    3331              :         {
    3332              :             // We won't get any async callbacks here, so just complete our stage.
    3333            0 :             ChipLogError(Controller, "Failed to send SetUTCTime command: %" CHIP_ERROR_FORMAT, err.Format());
    3334            0 :             CommissioningStageComplete(err);
    3335            0 :             return;
    3336              :         }
    3337            0 :         break;
    3338              :     }
    3339            0 :     case CommissioningStage::kConfigureTimeZone: {
    3340            0 :         if (!params.GetTimeZone().HasValue())
    3341              :         {
    3342            0 :             ChipLogError(Controller, "ConfigureTimeZone stage called with no time zone data");
    3343            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3344            0 :             return;
    3345              :         }
    3346            0 :         TimeSynchronization::Commands::SetTimeZone::Type request;
    3347            0 :         request.timeZone = params.GetTimeZone().Value();
    3348            0 :         CHIP_ERROR err   = SendCommissioningCommand(proxy, request, OnSetTimeZoneResponse, OnBasicFailure, endpoint, timeout);
    3349            0 :         if (err != CHIP_NO_ERROR)
    3350              :         {
    3351              :             // We won't get any async callbacks here, so just complete our stage.
    3352            0 :             ChipLogError(Controller, "Failed to send SetTimeZone command: %" CHIP_ERROR_FORMAT, err.Format());
    3353            0 :             CommissioningStageComplete(err);
    3354            0 :             return;
    3355              :         }
    3356            0 :         break;
    3357              :     }
    3358            0 :     case CommissioningStage::kConfigureDSTOffset: {
    3359            0 :         if (!params.GetDSTOffsets().HasValue())
    3360              :         {
    3361            0 :             ChipLogError(Controller, "ConfigureDSTOffset stage called with no DST data");
    3362            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3363            0 :             return;
    3364              :         }
    3365            0 :         TimeSynchronization::Commands::SetDSTOffset::Type request;
    3366            0 :         request.DSTOffset = params.GetDSTOffsets().Value();
    3367            0 :         CHIP_ERROR err    = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnBasicFailure, endpoint, timeout);
    3368            0 :         if (err != CHIP_NO_ERROR)
    3369              :         {
    3370              :             // We won't get any async callbacks here, so just complete our stage.
    3371            0 :             ChipLogError(Controller, "Failed to send SetDSTOffset command: %" CHIP_ERROR_FORMAT, err.Format());
    3372            0 :             CommissioningStageComplete(err);
    3373            0 :             return;
    3374              :         }
    3375            0 :         break;
    3376              :     }
    3377            0 :     case CommissioningStage::kConfigureDefaultNTP: {
    3378            0 :         if (!params.GetDefaultNTP().HasValue())
    3379              :         {
    3380            0 :             ChipLogError(Controller, "ConfigureDefaultNTP stage called with no default NTP data");
    3381            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3382            0 :             return;
    3383              :         }
    3384            0 :         TimeSynchronization::Commands::SetDefaultNTP::Type request;
    3385            0 :         request.defaultNTP = params.GetDefaultNTP().Value();
    3386            0 :         CHIP_ERROR err     = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnBasicFailure, endpoint, timeout);
    3387            0 :         if (err != CHIP_NO_ERROR)
    3388              :         {
    3389              :             // We won't get any async callbacks here, so just complete our stage.
    3390            0 :             ChipLogError(Controller, "Failed to send SetDefaultNTP command: %" CHIP_ERROR_FORMAT, err.Format());
    3391            0 :             CommissioningStageComplete(err);
    3392            0 :             return;
    3393              :         }
    3394            0 :         break;
    3395              :     }
    3396            0 :     case CommissioningStage::kScanNetworks: {
    3397            0 :         NetworkCommissioning::Commands::ScanNetworks::Type request;
    3398            0 :         if (params.GetWiFiCredentials().HasValue())
    3399              :         {
    3400            0 :             request.ssid.Emplace(params.GetWiFiCredentials().Value().ssid);
    3401              :         }
    3402            0 :         request.breadcrumb.Emplace(breadcrumb);
    3403            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnScanNetworksResponse, OnScanNetworksFailure, endpoint, timeout);
    3404            0 :         if (err != CHIP_NO_ERROR)
    3405              :         {
    3406              :             // We won't get any async callbacks here, so just complete our stage.
    3407            0 :             ChipLogError(Controller, "Failed to send ScanNetworks command: %" CHIP_ERROR_FORMAT, err.Format());
    3408            0 :             CommissioningStageComplete(err);
    3409            0 :             return;
    3410              :         }
    3411            0 :         break;
    3412              :     }
    3413            0 :     case CommissioningStage::kNeedsNetworkCreds: {
    3414              :         // Nothing to do.
    3415              :         //
    3416              :         // Either we did a scan and the OnScanNetworksSuccess and OnScanNetworksFailure
    3417              :         // callbacks will tell the DevicePairingDelegate that network credentials are
    3418              :         // needed, or we asked the DevicePairingDelegate for network credentials
    3419              :         // explicitly, and are waiting for it to get back to us.
    3420            0 :         break;
    3421              :     }
    3422            0 :     case CommissioningStage::kConfigRegulatory: {
    3423              :         // TODO(cecille): Worthwhile to keep this around as part of the class?
    3424              :         // TODO(cecille): Where is the country config actually set?
    3425            0 :         ChipLogProgress(Controller, "Setting Regulatory Config");
    3426              :         auto capability =
    3427            0 :             params.GetLocationCapability().ValueOr(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kOutdoor);
    3428              :         app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum regulatoryConfig;
    3429              :         // Value is only switchable on the devices with indoor/outdoor capability
    3430            0 :         if (capability == app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor)
    3431              :         {
    3432              :             // If the device supports indoor and outdoor configs, use the setting from the commissioner, otherwise fall back to
    3433              :             // the current device setting then to outdoor (most restrictive)
    3434            0 :             if (params.GetDeviceRegulatoryLocation().HasValue())
    3435              :             {
    3436            0 :                 regulatoryConfig = params.GetDeviceRegulatoryLocation().Value();
    3437            0 :                 ChipLogProgress(Controller, "Setting regulatory config to %u from commissioner override",
    3438              :                                 static_cast<uint8_t>(regulatoryConfig));
    3439              :             }
    3440            0 :             else if (params.GetDefaultRegulatoryLocation().HasValue())
    3441              :             {
    3442            0 :                 regulatoryConfig = params.GetDefaultRegulatoryLocation().Value();
    3443            0 :                 ChipLogProgress(Controller, "No regulatory config supplied by controller, leaving as device default (%u)",
    3444              :                                 static_cast<uint8_t>(regulatoryConfig));
    3445              :             }
    3446              :             else
    3447              :             {
    3448            0 :                 regulatoryConfig = app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kOutdoor;
    3449            0 :                 ChipLogProgress(Controller, "No overrride or device regulatory config supplied, setting to outdoor");
    3450              :             }
    3451              :         }
    3452              :         else
    3453              :         {
    3454            0 :             ChipLogProgress(Controller, "Device does not support configurable regulatory location");
    3455            0 :             regulatoryConfig = capability;
    3456              :         }
    3457              : 
    3458            0 :         CharSpan countryCode;
    3459            0 :         const auto & providedCountryCode = params.GetCountryCode();
    3460            0 :         if (providedCountryCode.HasValue())
    3461              :         {
    3462            0 :             countryCode = providedCountryCode.Value();
    3463              :         }
    3464              :         else
    3465              :         {
    3466              :             // Default to "XX", for lack of anything better.
    3467            0 :             countryCode = "XX"_span;
    3468              :         }
    3469              : 
    3470            0 :         GeneralCommissioning::Commands::SetRegulatoryConfig::Type request;
    3471            0 :         request.newRegulatoryConfig = regulatoryConfig;
    3472            0 :         request.countryCode         = countryCode;
    3473            0 :         request.breadcrumb          = breadcrumb;
    3474            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnSetRegulatoryConfigResponse, OnBasicFailure, endpoint, timeout);
    3475            0 :         if (err != CHIP_NO_ERROR)
    3476              :         {
    3477              :             // We won't get any async callbacks here, so just complete our stage.
    3478            0 :             ChipLogError(Controller, "Failed to send SetRegulatoryConfig command: %" CHIP_ERROR_FORMAT, err.Format());
    3479            0 :             CommissioningStageComplete(err);
    3480            0 :             return;
    3481              :         }
    3482              :     }
    3483            0 :     break;
    3484            0 :     case CommissioningStage::kConfigureTCAcknowledgments: {
    3485            0 :         ChipLogProgress(Controller, "Setting Terms and Conditions");
    3486              : 
    3487            0 :         if (!params.GetTermsAndConditionsAcknowledgement().HasValue())
    3488              :         {
    3489            0 :             ChipLogProgress(Controller, "Setting Terms and Conditions: Skipped");
    3490            0 :             CommissioningStageComplete(CHIP_NO_ERROR);
    3491            0 :             return;
    3492              :         }
    3493              : 
    3494            0 :         GeneralCommissioning::Commands::SetTCAcknowledgements::Type request;
    3495            0 :         TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = params.GetTermsAndConditionsAcknowledgement().Value();
    3496            0 :         request.TCUserResponse = termsAndConditionsAcknowledgement.acceptedTermsAndConditions;
    3497            0 :         request.TCVersion      = termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion;
    3498              : 
    3499            0 :         ChipLogProgress(Controller, "Setting Terms and Conditions: %hu, %hu", request.TCUserResponse, request.TCVersion);
    3500              :         CHIP_ERROR err =
    3501            0 :             SendCommissioningCommand(proxy, request, OnSetTCAcknowledgementsResponse, OnBasicFailure, endpoint, timeout);
    3502            0 :         if (err != CHIP_NO_ERROR)
    3503              :         {
    3504            0 :             ChipLogError(Controller, "Failed to send SetTCAcknowledgements command: %" CHIP_ERROR_FORMAT, err.Format());
    3505            0 :             CommissioningStageComplete(err);
    3506            0 :             return;
    3507              :         }
    3508            0 :         break;
    3509              :     }
    3510            0 :     case CommissioningStage::kSendPAICertificateRequest: {
    3511            0 :         ChipLogProgress(Controller, "Sending request for PAI certificate");
    3512            0 :         CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kPAI, timeout);
    3513            0 :         if (err != CHIP_NO_ERROR)
    3514              :         {
    3515              :             // We won't get any async callbacks here, so just complete our stage.
    3516            0 :             ChipLogError(Controller, "Failed to send CertificateChainRequest command to get PAI: %" CHIP_ERROR_FORMAT,
    3517              :                          err.Format());
    3518            0 :             CommissioningStageComplete(err);
    3519            0 :             return;
    3520              :         }
    3521            0 :         break;
    3522              :     }
    3523            0 :     case CommissioningStage::kSendDACCertificateRequest: {
    3524            0 :         ChipLogProgress(Controller, "Sending request for DAC certificate");
    3525            0 :         CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kDAC, timeout);
    3526            0 :         if (err != CHIP_NO_ERROR)
    3527              :         {
    3528              :             // We won't get any async callbacks here, so just complete our stage.
    3529            0 :             ChipLogError(Controller, "Failed to send CertificateChainRequest command to get DAC: %" CHIP_ERROR_FORMAT,
    3530              :                          err.Format());
    3531            0 :             CommissioningStageComplete(err);
    3532            0 :             return;
    3533              :         }
    3534            0 :         break;
    3535              :     }
    3536            0 :     case CommissioningStage::kSendAttestationRequest: {
    3537            0 :         ChipLogProgress(Controller, "Sending Attestation Request to the device.");
    3538            0 :         if (!params.GetAttestationNonce().HasValue())
    3539              :         {
    3540            0 :             ChipLogError(Controller, "No attestation nonce found");
    3541            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3542            0 :             return;
    3543              :         }
    3544            0 :         CHIP_ERROR err = SendAttestationRequestCommand(proxy, params.GetAttestationNonce().Value(), timeout);
    3545            0 :         if (err != CHIP_NO_ERROR)
    3546              :         {
    3547              :             // We won't get any async callbacks here, so just complete our stage.
    3548            0 :             ChipLogError(Controller, "Failed to send AttestationRequest command: %" CHIP_ERROR_FORMAT, err.Format());
    3549            0 :             CommissioningStageComplete(err);
    3550            0 :             return;
    3551              :         }
    3552            0 :         break;
    3553              :     }
    3554            0 :     case CommissioningStage::kAttestationVerification: {
    3555            0 :         ChipLogProgress(Controller, "Verifying Device Attestation information received from the device");
    3556            0 :         if (IsAttestationInformationMissing(params))
    3557              :         {
    3558            0 :             ChipLogError(Controller, "Missing attestation information");
    3559            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3560            0 :             return;
    3561              :         }
    3562              : 
    3563              :         DeviceAttestationVerifier::AttestationInfo info(
    3564            0 :             params.GetAttestationElements().Value(),
    3565            0 :             proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge(),
    3566            0 :             params.GetAttestationSignature().Value(), params.GetPAI().Value(), params.GetDAC().Value(),
    3567            0 :             params.GetAttestationNonce().Value(), params.GetRemoteVendorId().Value(), params.GetRemoteProductId().Value());
    3568              : 
    3569            0 :         CHIP_ERROR err = ValidateAttestationInfo(info);
    3570            0 :         if (err != CHIP_NO_ERROR)
    3571              :         {
    3572            0 :             ChipLogError(Controller, "Error validating attestation information: %" CHIP_ERROR_FORMAT, err.Format());
    3573            0 :             CommissioningStageComplete(CHIP_ERROR_FAILED_DEVICE_ATTESTATION);
    3574            0 :             return;
    3575              :         }
    3576              :     }
    3577            0 :     break;
    3578            0 :     case CommissioningStage::kAttestationRevocationCheck: {
    3579            0 :         ChipLogProgress(Controller, "Verifying the device's DAC chain revocation status");
    3580            0 :         if (IsAttestationInformationMissing(params))
    3581              :         {
    3582            0 :             ChipLogError(Controller, "Missing attestation information");
    3583            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3584            0 :             return;
    3585              :         }
    3586              : 
    3587              :         DeviceAttestationVerifier::AttestationInfo info(
    3588            0 :             params.GetAttestationElements().Value(),
    3589            0 :             proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge(),
    3590            0 :             params.GetAttestationSignature().Value(), params.GetPAI().Value(), params.GetDAC().Value(),
    3591            0 :             params.GetAttestationNonce().Value(), params.GetRemoteVendorId().Value(), params.GetRemoteProductId().Value());
    3592              : 
    3593            0 :         CHIP_ERROR err = CheckForRevokedDACChain(info);
    3594              : 
    3595            0 :         if (err != CHIP_NO_ERROR)
    3596              :         {
    3597            0 :             ChipLogError(Controller, "Error validating device's DAC chain revocation status: %" CHIP_ERROR_FORMAT, err.Format());
    3598            0 :             CommissioningStageComplete(CHIP_ERROR_FAILED_DEVICE_ATTESTATION);
    3599            0 :             return;
    3600              :         }
    3601              :     }
    3602            0 :     break;
    3603            0 :     case CommissioningStage::kJCMTrustVerification: {
    3604            0 :         CHIP_ERROR err = StartJCMTrustVerification(proxy);
    3605            0 :         if (err != CHIP_NO_ERROR)
    3606              :         {
    3607            0 :             ChipLogError(Controller, "Failed to start JCM Trust Verification: %" CHIP_ERROR_FORMAT, err.Format());
    3608            0 :             CommissioningStageComplete(err);
    3609            0 :             return;
    3610              :         }
    3611            0 :         break;
    3612              :     }
    3613              : 
    3614            0 :     case CommissioningStage::kSendOpCertSigningRequest: {
    3615            0 :         if (!params.GetCSRNonce().HasValue())
    3616              :         {
    3617            0 :             ChipLogError(Controller, "No CSR nonce found");
    3618            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3619            0 :             return;
    3620              :         }
    3621            0 :         CHIP_ERROR err = SendOperationalCertificateSigningRequestCommand(proxy, params.GetCSRNonce().Value(), timeout);
    3622            0 :         if (err != CHIP_NO_ERROR)
    3623              :         {
    3624              :             // We won't get any async callbacks here, so just complete our stage.
    3625            0 :             ChipLogError(Controller, "Failed to send CSR request: %" CHIP_ERROR_FORMAT, err.Format());
    3626            0 :             CommissioningStageComplete(err);
    3627            0 :             return;
    3628              :         }
    3629            0 :         break;
    3630              :     }
    3631            0 :     case CommissioningStage::kValidateCSR: {
    3632            0 :         if (!params.GetNOCChainGenerationParameters().HasValue() || !params.GetDAC().HasValue() || !params.GetCSRNonce().HasValue())
    3633              :         {
    3634            0 :             ChipLogError(Controller, "Unable to validate CSR");
    3635            0 :             return CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3636              :         }
    3637              :         // This is non-blocking, so send the callback immediately.
    3638            0 :         CHIP_ERROR err = ValidateCSR(proxy, params.GetNOCChainGenerationParameters().Value().nocsrElements,
    3639            0 :                                      params.GetNOCChainGenerationParameters().Value().signature, params.GetDAC().Value(),
    3640            0 :                                      params.GetCSRNonce().Value());
    3641            0 :         if (err != CHIP_NO_ERROR)
    3642              :         {
    3643            0 :             ChipLogError(Controller, "Failed to validate CSR: %" CHIP_ERROR_FORMAT, err.Format());
    3644              :         }
    3645            0 :         CommissioningStageComplete(err);
    3646            0 :         return;
    3647              :     }
    3648              :     break;
    3649            0 :     case CommissioningStage::kGenerateNOCChain: {
    3650            0 :         if (!params.GetNOCChainGenerationParameters().HasValue() || !params.GetDAC().HasValue() || !params.GetPAI().HasValue() ||
    3651            0 :             !params.GetCSRNonce().HasValue())
    3652              :         {
    3653            0 :             ChipLogError(Controller, "Unable to generate NOC chain parameters");
    3654            0 :             return CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3655              :         }
    3656            0 :         CHIP_ERROR err = ProcessCSR(proxy, params.GetNOCChainGenerationParameters().Value().nocsrElements,
    3657            0 :                                     params.GetNOCChainGenerationParameters().Value().signature, params.GetDAC().Value(),
    3658            0 :                                     params.GetPAI().Value(), params.GetCSRNonce().Value());
    3659            0 :         if (err != CHIP_NO_ERROR)
    3660              :         {
    3661            0 :             ChipLogError(Controller, "Failed to process Operational Certificate Signing Request (CSR): %" CHIP_ERROR_FORMAT,
    3662              :                          err.Format());
    3663            0 :             CommissioningStageComplete(err);
    3664            0 :             return;
    3665              :         }
    3666              :     }
    3667            0 :     break;
    3668            0 :     case CommissioningStage::kSendTrustedRootCert: {
    3669            0 :         if (!params.GetRootCert().HasValue() || !params.GetNoc().HasValue())
    3670              :         {
    3671            0 :             ChipLogError(Controller, "No trusted root cert or NOC specified");
    3672            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3673            0 :             return;
    3674              :         }
    3675            0 :         CHIP_ERROR err = SendTrustedRootCertificate(proxy, params.GetRootCert().Value(), timeout);
    3676            0 :         if (err != CHIP_NO_ERROR)
    3677              :         {
    3678            0 :             ChipLogError(Controller, "Error sending trusted root certificate: %" CHIP_ERROR_FORMAT, err.Format());
    3679            0 :             CommissioningStageComplete(err);
    3680            0 :             return;
    3681              :         }
    3682              : 
    3683            0 :         err = proxy->SetPeerId(params.GetRootCert().Value(), params.GetNoc().Value());
    3684            0 :         if (err != CHIP_NO_ERROR)
    3685              :         {
    3686            0 :             ChipLogError(Controller, "Error setting peer id: %" CHIP_ERROR_FORMAT, err.Format());
    3687            0 :             CommissioningStageComplete(err);
    3688            0 :             return;
    3689              :         }
    3690            0 :         if (!IsOperationalNodeId(proxy->GetDeviceId()))
    3691              :         {
    3692            0 :             ChipLogError(Controller, "Given node ID is not an operational node ID");
    3693            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3694            0 :             return;
    3695              :         }
    3696              :     }
    3697            0 :     break;
    3698            0 :     case CommissioningStage::kSendNOC: {
    3699            0 :         if (!params.GetNoc().HasValue() || !params.GetIpk().HasValue() || !params.GetAdminSubject().HasValue())
    3700              :         {
    3701            0 :             ChipLogError(Controller, "AddNOC contents not specified");
    3702            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3703            0 :             return;
    3704              :         }
    3705            0 :         CHIP_ERROR err = SendOperationalCertificate(proxy, params.GetNoc().Value(), params.GetIcac(), params.GetIpk().Value(),
    3706            0 :                                                     params.GetAdminSubject().Value(), timeout);
    3707            0 :         if (err != CHIP_NO_ERROR)
    3708              :         {
    3709              :             // We won't get any async callbacks here, so just complete our stage.
    3710            0 :             ChipLogError(Controller, "Error installing operational certificate with AddNOC: %" CHIP_ERROR_FORMAT, err.Format());
    3711            0 :             CommissioningStageComplete(err);
    3712            0 :             return;
    3713              :         }
    3714            0 :         break;
    3715              :     }
    3716            0 :     case CommissioningStage::kConfigureTrustedTimeSource: {
    3717            0 :         if (!params.GetTrustedTimeSource().HasValue())
    3718              :         {
    3719            0 :             ChipLogError(Controller, "ConfigureTrustedTimeSource stage called with no trusted time source data!");
    3720            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3721            0 :             return;
    3722              :         }
    3723            0 :         TimeSynchronization::Commands::SetTrustedTimeSource::Type request;
    3724            0 :         request.trustedTimeSource = params.GetTrustedTimeSource().Value();
    3725            0 :         CHIP_ERROR err            = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnBasicFailure, endpoint, timeout);
    3726            0 :         if (err != CHIP_NO_ERROR)
    3727              :         {
    3728              :             // We won't get any async callbacks here, so just complete our stage.
    3729            0 :             ChipLogError(Controller, "Failed to send SendTrustedTimeSource command: %" CHIP_ERROR_FORMAT, err.Format());
    3730            0 :             CommissioningStageComplete(err);
    3731            0 :             return;
    3732              :         }
    3733            0 :         break;
    3734              :     }
    3735            0 :     case CommissioningStage::kRequestWiFiCredentials: {
    3736            0 :         if (!mPairingDelegate)
    3737              :         {
    3738            0 :             ChipLogError(Controller, "Unable to request Wi-Fi credentials: no delegate available");
    3739            0 :             CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
    3740            0 :             return;
    3741              :         }
    3742              : 
    3743            0 :         CHIP_ERROR err = mPairingDelegate->WiFiCredentialsNeeded(endpoint);
    3744            0 :         CommissioningStageComplete(err);
    3745            0 :         return;
    3746              :     }
    3747            0 :     case CommissioningStage::kRequestThreadCredentials: {
    3748            0 :         if (!mPairingDelegate)
    3749              :         {
    3750            0 :             ChipLogError(Controller, "Unable to request Thread credentials: no delegate available");
    3751            0 :             CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
    3752            0 :             return;
    3753              :         }
    3754              : 
    3755            0 :         CHIP_ERROR err = mPairingDelegate->ThreadCredentialsNeeded(endpoint);
    3756            0 :         CommissioningStageComplete(err);
    3757            0 :         return;
    3758              :     }
    3759            0 :     case CommissioningStage::kWiFiNetworkSetup: {
    3760            0 :         if (!params.GetWiFiCredentials().HasValue())
    3761              :         {
    3762            0 :             ChipLogError(Controller, "No wifi credentials specified");
    3763            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3764            0 :             return;
    3765              :         }
    3766              : 
    3767            0 :         NetworkCommissioning::Commands::AddOrUpdateWiFiNetwork::Type request;
    3768            0 :         request.ssid        = params.GetWiFiCredentials().Value().ssid;
    3769            0 :         request.credentials = params.GetWiFiCredentials().Value().credentials;
    3770            0 :         request.breadcrumb.Emplace(breadcrumb);
    3771            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
    3772            0 :         if (err != CHIP_NO_ERROR)
    3773              :         {
    3774              :             // We won't get any async callbacks here, so just complete our stage.
    3775            0 :             ChipLogError(Controller, "Failed to send AddOrUpdateWiFiNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
    3776            0 :             CommissioningStageComplete(err);
    3777            0 :             return;
    3778              :         }
    3779              :     }
    3780            0 :     break;
    3781            0 :     case CommissioningStage::kThreadNetworkSetup: {
    3782            0 :         if (!params.GetThreadOperationalDataset().HasValue())
    3783              :         {
    3784            0 :             ChipLogError(Controller, "No thread credentials specified");
    3785            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3786            0 :             return;
    3787              :         }
    3788            0 :         NetworkCommissioning::Commands::AddOrUpdateThreadNetwork::Type request;
    3789            0 :         request.operationalDataset = params.GetThreadOperationalDataset().Value();
    3790            0 :         request.breadcrumb.Emplace(breadcrumb);
    3791            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
    3792            0 :         if (err != CHIP_NO_ERROR)
    3793              :         {
    3794              :             // We won't get any async callbacks here, so just complete our stage.
    3795            0 :             ChipLogError(Controller, "Failed to send AddOrUpdateThreadNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
    3796            0 :             CommissioningStageComplete(err);
    3797            0 :             return;
    3798              :         }
    3799              :     }
    3800            0 :     break;
    3801            0 :     case CommissioningStage::kFailsafeBeforeWiFiEnable:
    3802              :         FALLTHROUGH;
    3803              :     case CommissioningStage::kFailsafeBeforeThreadEnable:
    3804              :         // Before we try to do network enablement, make sure that our fail-safe
    3805              :         // is set far enough out that we can later try to do operational
    3806              :         // discovery without it timing out.
    3807            0 :         ExtendFailsafeBeforeNetworkEnable(proxy, params, step);
    3808            0 :         break;
    3809            0 :     case CommissioningStage::kWiFiNetworkEnable: {
    3810            0 :         if (!params.GetWiFiCredentials().HasValue())
    3811              :         {
    3812            0 :             ChipLogError(Controller, "No wifi credentials specified");
    3813            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3814            0 :             return;
    3815              :         }
    3816            0 :         NetworkCommissioning::Commands::ConnectNetwork::Type request;
    3817            0 :         request.networkID = params.GetWiFiCredentials().Value().ssid;
    3818            0 :         request.breadcrumb.Emplace(breadcrumb);
    3819              : 
    3820            0 :         CHIP_ERROR err = CHIP_NO_ERROR;
    3821            0 :         ChipLogProgress(Controller, "SendCommand kWiFiNetworkEnable, supportsConcurrentConnection=%s",
    3822              :                         params.GetSupportsConcurrentConnection().HasValue()
    3823              :                             ? (params.GetSupportsConcurrentConnection().Value() ? "true" : "false")
    3824              :                             : "missing");
    3825            0 :         err = SendCommissioningCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout);
    3826              : 
    3827            0 :         if (err != CHIP_NO_ERROR)
    3828              :         {
    3829              :             // We won't get any async callbacks here, so just complete our stage.
    3830            0 :             ChipLogError(Controller, "Failed to send WiFi ConnectNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
    3831            0 :             CommissioningStageComplete(err);
    3832            0 :             return;
    3833              :         }
    3834              :     }
    3835            0 :     break;
    3836            0 :     case CommissioningStage::kThreadNetworkEnable: {
    3837            0 :         ByteSpan extendedPanId;
    3838            0 :         chip::Thread::OperationalDataset operationalDataset;
    3839            0 :         if (!params.GetThreadOperationalDataset().HasValue() ||
    3840            0 :             operationalDataset.Init(params.GetThreadOperationalDataset().Value()) != CHIP_NO_ERROR ||
    3841            0 :             operationalDataset.GetExtendedPanIdAsByteSpan(extendedPanId) != CHIP_NO_ERROR)
    3842              :         {
    3843            0 :             ChipLogError(Controller, "Invalid Thread operational dataset configured at commissioner!");
    3844            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3845            0 :             return;
    3846              :         }
    3847            0 :         NetworkCommissioning::Commands::ConnectNetwork::Type request;
    3848            0 :         request.networkID = extendedPanId;
    3849            0 :         request.breadcrumb.Emplace(breadcrumb);
    3850            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout);
    3851            0 :         if (err != CHIP_NO_ERROR)
    3852              :         {
    3853              :             // We won't get any async callbacks here, so just complete our stage.
    3854            0 :             ChipLogError(Controller, "Failed to send Thread ConnectNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
    3855            0 :             CommissioningStageComplete(err);
    3856            0 :             return;
    3857              :         }
    3858              :     }
    3859            0 :     break;
    3860            0 :     case CommissioningStage::kICDGetRegistrationInfo: {
    3861            0 :         GetPairingDelegate()->OnICDRegistrationInfoRequired();
    3862            0 :         return;
    3863              :     }
    3864              :     break;
    3865            0 :     case CommissioningStage::kICDRegistration: {
    3866            0 :         IcdManagement::Commands::RegisterClient::Type request;
    3867              : 
    3868            0 :         if (!(params.GetICDCheckInNodeId().HasValue() && params.GetICDMonitoredSubject().HasValue() &&
    3869            0 :               params.GetICDSymmetricKey().HasValue()))
    3870              :         {
    3871            0 :             ChipLogError(Controller, "No ICD Registration information provided!");
    3872            0 :             CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
    3873            0 :             return;
    3874              :         }
    3875              : 
    3876            0 :         request.checkInNodeID    = params.GetICDCheckInNodeId().Value();
    3877            0 :         request.monitoredSubject = params.GetICDMonitoredSubject().Value();
    3878            0 :         request.key              = params.GetICDSymmetricKey().Value();
    3879              : 
    3880              :         CHIP_ERROR err =
    3881            0 :             SendCommissioningCommand(proxy, request, OnICDManagementRegisterClientResponse, OnBasicFailure, endpoint, timeout);
    3882            0 :         if (err != CHIP_NO_ERROR)
    3883              :         {
    3884              :             // We won't get any async callbacks here, so just complete our stage.
    3885            0 :             ChipLogError(Controller, "Failed to send IcdManagement.RegisterClient command: %" CHIP_ERROR_FORMAT, err.Format());
    3886            0 :             CommissioningStageComplete(err);
    3887            0 :             return;
    3888              :         }
    3889              :     }
    3890            0 :     break;
    3891            0 :     case CommissioningStage::kEvictPreviousCaseSessions: {
    3892            0 :         auto scopedPeerId = GetPeerScopedId(proxy->GetDeviceId());
    3893              : 
    3894              :         // If we ever had a commissioned device with this node ID before, we may
    3895              :         // have stale sessions to it.  Make sure we don't re-use any of those,
    3896              :         // because clearly they are not related to this new device we are
    3897              :         // commissioning.  We only care about sessions we might reuse, so just
    3898              :         // clearing the ones associated with our fabric index is good enough and
    3899              :         // we don't need to worry about ExpireAllSessionsOnLogicalFabric.
    3900            0 :         mSystemState->SessionMgr()->ExpireAllSessions(scopedPeerId);
    3901              : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
    3902              :         Transport::Type type = proxy->GetSecureSession().Value()->AsSecureSession()->GetPeerAddress().GetTransportType();
    3903              :         // cache address if we are connected over TCP or UDP
    3904              :         if (type == Transport::Type::kTcp || type == Transport::Type::kUdp)
    3905              :         {
    3906              :             // Store the address we are using for PASE as a fallback for operational discovery
    3907              :             ResolveResult result;
    3908              :             result.address         = proxy->GetSecureSession().Value()->AsSecureSession()->GetPeerAddress();
    3909              :             result.mrpRemoteConfig = proxy->GetSecureSession().Value()->GetRemoteMRPConfig();
    3910              :             // Note: supportsTcpClient and supportsTcpServer are device capabilities from DNS-SD TXT records,
    3911              :             // not derivable from the transport type. They remain false (default) here.
    3912              :             // TODO: Consider passing these through RendezvousParameters if available from SetUpCodePairer.
    3913              :             mFallbackOperationalResolveResult.SetValue(result);
    3914              :         }
    3915              : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
    3916            0 :         CommissioningStageComplete(CHIP_NO_ERROR);
    3917            0 :         return;
    3918              :     }
    3919            0 :     case CommissioningStage::kFindOperationalForStayActive:
    3920              :     case CommissioningStage::kFindOperationalForCommissioningComplete: {
    3921              :         // If there is an error, CommissioningStageComplete will be called from OnDeviceConnectionFailureFn.
    3922            0 :         auto scopedPeerId = GetPeerScopedId(proxy->GetDeviceId());
    3923              :         MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissioningOperationalSetup);
    3924            0 :         mSystemState->CASESessionMgr()->FindOrEstablishSession(
    3925              :             scopedPeerId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback,
    3926              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
    3927              :             /* attemptCount = */ 3, &mOnDeviceConnectionRetryCallback,
    3928              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
    3929            0 :             TransportPayloadCapability::kMRPPayload, mFallbackOperationalResolveResult);
    3930              :     }
    3931            0 :     break;
    3932            0 :     case CommissioningStage::kPrimaryOperationalNetworkFailed: {
    3933              :         // nothing to do. This stage indicates that the primary operational network failed and the network config should be
    3934              :         // removed later.
    3935            0 :         break;
    3936              :     }
    3937            0 :     case CommissioningStage::kRemoveWiFiNetworkConfig: {
    3938            0 :         NetworkCommissioning::Commands::RemoveNetwork::Type request;
    3939            0 :         request.networkID = params.GetWiFiCredentials().Value().ssid;
    3940            0 :         request.breadcrumb.Emplace(breadcrumb);
    3941            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
    3942            0 :         if (err != CHIP_NO_ERROR)
    3943              :         {
    3944              :             // We won't get any async callbacks here, so just complete our stage.
    3945            0 :             ChipLogError(Controller, "Failed to send RemoveNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
    3946            0 :             CommissioningStageComplete(err);
    3947            0 :             return;
    3948              :         }
    3949            0 :         break;
    3950              :     }
    3951            0 :     case CommissioningStage::kRemoveThreadNetworkConfig: {
    3952            0 :         ByteSpan extendedPanId;
    3953            0 :         chip::Thread::OperationalDataset operationalDataset;
    3954            0 :         if (!params.GetThreadOperationalDataset().HasValue() ||
    3955            0 :             operationalDataset.Init(params.GetThreadOperationalDataset().Value()) != CHIP_NO_ERROR ||
    3956            0 :             operationalDataset.GetExtendedPanIdAsByteSpan(extendedPanId) != CHIP_NO_ERROR)
    3957              :         {
    3958            0 :             ChipLogError(Controller, "Invalid Thread operational dataset configured at commissioner!");
    3959            0 :             CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
    3960            0 :             return;
    3961              :         }
    3962            0 :         NetworkCommissioning::Commands::RemoveNetwork::Type request;
    3963            0 :         request.networkID = extendedPanId;
    3964            0 :         request.breadcrumb.Emplace(breadcrumb);
    3965            0 :         CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
    3966            0 :         if (err != CHIP_NO_ERROR)
    3967              :         {
    3968              :             // We won't get any async callbacks here, so just complete our stage.
    3969            0 :             ChipLogError(Controller, "Failed to send RemoveNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
    3970            0 :             CommissioningStageComplete(err);
    3971            0 :             return;
    3972              :         }
    3973            0 :         break;
    3974              :     }
    3975            0 :     case CommissioningStage::kICDSendStayActive: {
    3976            0 :         if (!(params.GetICDStayActiveDurationMsec().HasValue()))
    3977              :         {
    3978            0 :             ChipLogProgress(Controller, "Skipping kICDSendStayActive");
    3979            0 :             CommissioningStageComplete(CHIP_NO_ERROR);
    3980            0 :             return;
    3981              :         }
    3982              : 
    3983              :         // StayActive Command happens over CASE Connection
    3984            0 :         IcdManagement::Commands::StayActiveRequest::Type request;
    3985            0 :         request.stayActiveDuration = params.GetICDStayActiveDurationMsec().Value();
    3986            0 :         ChipLogError(Controller, "Send ICD StayActive with Duration %u", request.stayActiveDuration);
    3987              :         CHIP_ERROR err =
    3988            0 :             SendCommissioningCommand(proxy, request, OnICDManagementStayActiveResponse, OnBasicFailure, endpoint, timeout);
    3989            0 :         if (err != CHIP_NO_ERROR)
    3990              :         {
    3991              :             // We won't get any async callbacks here, so just complete our stage.
    3992            0 :             ChipLogError(Controller, "Failed to send IcdManagement.StayActive command: %" CHIP_ERROR_FORMAT, err.Format());
    3993            0 :             CommissioningStageComplete(err);
    3994            0 :             return;
    3995              :         }
    3996              :     }
    3997            0 :     break;
    3998            0 :     case CommissioningStage::kSendComplete: {
    3999              :         // CommissioningComplete command happens over the CASE connection.
    4000              :         GeneralCommissioning::Commands::CommissioningComplete::Type request;
    4001              :         CHIP_ERROR err =
    4002            0 :             SendCommissioningCommand(proxy, request, OnCommissioningCompleteResponse, OnBasicFailure, endpoint, timeout);
    4003            0 :         if (err != CHIP_NO_ERROR)
    4004              :         {
    4005              :             // We won't get any async callbacks here, so just complete our stage.
    4006            0 :             ChipLogError(Controller, "Failed to send CommissioningComplete command: %" CHIP_ERROR_FORMAT, err.Format());
    4007            0 :             CommissioningStageComplete(err);
    4008            0 :             return;
    4009              :         }
    4010              :     }
    4011            0 :     break;
    4012              : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
    4013              :     case CommissioningStage::kUnpoweredPhaseComplete:
    4014              :         ChipLogProgress(Controller, "Completed unpowered commissioning phase, marking commissioning as complete");
    4015              :         CommissioningStageComplete(CHIP_NO_ERROR);
    4016              :         break;
    4017              : #endif
    4018            0 :     case CommissioningStage::kCleanup:
    4019            0 :         CleanupCommissioning(proxy, proxy->GetDeviceId(), params.GetCompletionStatus());
    4020            0 :         break;
    4021            0 :     case CommissioningStage::kError:
    4022            0 :         mCommissioningStage = CommissioningStage::kSecurePairing;
    4023            0 :         break;
    4024            0 :     case CommissioningStage::kSecurePairing:
    4025            0 :         break;
    4026              :     }
    4027              : }
    4028              : 
    4029            0 : void DeviceCommissioner::ExtendFailsafeBeforeNetworkEnable(DeviceProxy * device, CommissioningParameters & params,
    4030              :                                                            CommissioningStage step)
    4031              : {
    4032            0 :     auto * commissioneeDevice = FindCommissioneeDevice(device->GetDeviceId());
    4033            0 :     if (device != commissioneeDevice)
    4034              :     {
    4035              :         // Not a commissionee device; just return.
    4036            0 :         ChipLogError(Controller, "Trying to extend fail-safe for an unknown commissionee with device id " ChipLogFormatX64,
    4037              :                      ChipLogValueX64(device->GetDeviceId()));
    4038            0 :         CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE, CommissioningDelegate::CommissioningReport());
    4039            0 :         return;
    4040              :     }
    4041              : 
    4042              :     // Try to make sure we have at least enough time for our expected
    4043              :     // commissioning bits plus the MRP retries for a Sigma1.
    4044            0 :     uint16_t failSafeTimeoutSecs = params.GetFailsafeTimerSeconds().ValueOr(kDefaultFailsafeTimeout);
    4045            0 :     auto sigma1Timeout           = CASESession::ComputeSigma1ResponseTimeout(commissioneeDevice->GetPairing().GetRemoteMRPConfig());
    4046            0 :     uint16_t sigma1TimeoutSecs   = std::chrono::duration_cast<System::Clock::Seconds16>(sigma1Timeout).count();
    4047            0 :     if (UINT16_MAX - failSafeTimeoutSecs < sigma1TimeoutSecs)
    4048              :     {
    4049            0 :         failSafeTimeoutSecs = UINT16_MAX;
    4050              :     }
    4051              :     else
    4052              :     {
    4053            0 :         failSafeTimeoutSecs = static_cast<uint16_t>(failSafeTimeoutSecs + sigma1TimeoutSecs);
    4054              :     }
    4055              : 
    4056            0 :     if (!ExtendArmFailSafeInternal(commissioneeDevice, step, failSafeTimeoutSecs, MakeOptional(kMinimumCommissioningStepTimeout),
    4057              :                                    OnArmFailSafe, OnBasicFailure, /* fireAndForget = */ false))
    4058              :     {
    4059              :         // A false return is fine; we don't want to make the fail-safe shorter here.
    4060            0 :         CommissioningStageComplete(CHIP_NO_ERROR, CommissioningDelegate::CommissioningReport());
    4061              :     }
    4062              : }
    4063              : 
    4064            0 : bool DeviceCommissioner::IsAttestationInformationMissing(const CommissioningParameters & params)
    4065              : {
    4066            0 :     if (!params.GetAttestationElements().HasValue() || !params.GetAttestationSignature().HasValue() ||
    4067            0 :         !params.GetAttestationNonce().HasValue() || !params.GetDAC().HasValue() || !params.GetPAI().HasValue() ||
    4068            0 :         !params.GetRemoteVendorId().HasValue() || !params.GetRemoteProductId().HasValue())
    4069              :     {
    4070            0 :         return true;
    4071              :     }
    4072              : 
    4073            0 :     return false;
    4074              : }
    4075              : 
    4076            0 : CHIP_ERROR DeviceController::GetCompressedFabricIdBytes(MutableByteSpan & outBytes) const
    4077              : {
    4078            0 :     const auto * fabricInfo = GetFabricInfo();
    4079            0 :     VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
    4080            0 :     return fabricInfo->GetCompressedFabricIdBytes(outBytes);
    4081              : }
    4082              : 
    4083            0 : CHIP_ERROR DeviceController::GetRootPublicKey(Crypto::P256PublicKey & outRootPublicKey) const
    4084              : {
    4085            0 :     const auto * fabricTable = GetFabricTable();
    4086            0 :     VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
    4087            0 :     return fabricTable->FetchRootPubkey(mFabricIndex, outRootPublicKey);
    4088              : }
    4089              : 
    4090            0 : bool DeviceCommissioner::HasValidCommissioningMode(const Dnssd::CommissionNodeData & nodeData)
    4091              : {
    4092            0 :     if (nodeData.commissioningMode == to_underlying(Dnssd::CommissioningMode::kDisabled))
    4093              :     {
    4094            0 :         ChipLogProgress(Controller, "Discovered device does not have an open commissioning window.");
    4095            0 :         return false;
    4096              :     }
    4097            0 :     return true;
    4098              : }
    4099              : 
    4100              : } // namespace Controller
    4101              : } // namespace chip
        

Generated by: LCOV version 2.0-1