Matter SDK Coverage Report
Current view: top level - app/server - CommissioningWindowManager.cpp (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 82.7 % 266 220
Test Date: 2026-01-31 08:14:20 Functions: 85.7 % 35 30

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2022 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : #include <app/icd/server/ICDServerConfig.h>
      19              : #include <app/server/CommissioningWindowManager.h>
      20              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      21              : #include <app/icd/server/ICDNotifier.h> // nogncheck
      22              : #endif
      23              : #include <app/reporting/reporting.h>
      24              : #include <app/server/Dnssd.h>
      25              : #include <app/server/Server.h>
      26              : #include <lib/dnssd/Advertiser.h>
      27              : #include <lib/support/CodeUtils.h>
      28              : #include <platform/CHIPDeviceLayer.h>
      29              : #include <platform/CommissionableDataProvider.h>
      30              : #include <platform/DeviceControlServer.h>
      31              : 
      32              : using namespace chip::app::Clusters;
      33              : using namespace chip::System::Clock;
      34              : using namespace chip::Crypto;
      35              : 
      36              : using AdministratorCommissioning::CommissioningWindowStatusEnum;
      37              : using chip::app::DataModel::MakeNullable;
      38              : using chip::app::DataModel::Nullable;
      39              : using chip::app::DataModel::NullNullable;
      40              : 
      41              : namespace {
      42              : 
      43              : // As per specifications (Section 13.3), Nodes SHALL exit commissioning mode after 20 failed commission attempts.
      44              : constexpr uint8_t kMaxFailedCommissioningAttempts = 20;
      45              : 
      46              : // As per specifications (Section 5.5: Commissioning Flows), Upon completion of PASE session establishment, the Commissionee SHALL
      47              : // autonomously arm the Fail-safe timer for a timeout of 60 seconds.
      48              : constexpr Seconds16 kFailSafeTimeoutPostPaseCompletion(60);
      49              : 
      50            0 : void HandleSessionEstablishmentTimeout(chip::System::Layer * aSystemLayer, void * aAppState)
      51              : {
      52            0 :     chip::CommissioningWindowManager * commissionMgr = static_cast<chip::CommissioningWindowManager *>(aAppState);
      53            0 :     commissionMgr->OnSessionEstablishmentError(CHIP_ERROR_TIMEOUT);
      54            0 : }
      55              : 
      56            6 : void OnPlatformEventWrapper(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
      57              : {
      58            6 :     chip::CommissioningWindowManager * commissionMgr = reinterpret_cast<chip::CommissioningWindowManager *>(arg);
      59            6 :     commissionMgr->OnPlatformEvent(event);
      60            6 : }
      61              : } // namespace
      62              : 
      63              : namespace chip {
      64              : 
      65            6 : void CommissioningWindowManager::OnPlatformEvent(const DeviceLayer::ChipDeviceEvent * event)
      66              : {
      67            6 :     if (event->Type == DeviceLayer::DeviceEventType::kCommissioningComplete)
      68              :     {
      69            0 :         ChipLogProgress(AppServer, "Commissioning completed successfully");
      70            0 :         DeviceLayer::SystemLayer().CancelTimer(HandleCommissioningWindowTimeout, this);
      71            0 :         mCommissioningTimeoutTimerArmed = false;
      72            0 :         Cleanup();
      73            0 :         mServer->GetSecureSessionManager().ExpireAllPASESessions();
      74              :         // That should have cleared out mPASESession.
      75              : #if CONFIG_NETWORK_LAYER_BLE && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION
      76              :         // If in NonConcurrentConnection, this will already have been completed
      77            0 :         mServer->GetBleLayerObject()->CloseAllBleConnections();
      78              : #endif
      79              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
      80            0 :         chip::WiFiPAF::WiFiPAFLayer::GetWiFiPAFLayer().Shutdown([](uint32_t id, WiFiPAF::WiFiPafRole role) {
      81            0 :             TEMPORARY_RETURN_IGNORED DeviceLayer::ConnectivityMgr().WiFiPAFShutdown(id, role);
      82            0 :         });
      83              : #endif
      84              :     }
      85            6 :     else if (event->Type == DeviceLayer::DeviceEventType::kFailSafeTimerExpired)
      86              :     {
      87            2 :         ChipLogError(AppServer, "Failsafe timer expired");
      88            2 :         if (mPASESession)
      89              :         {
      90            2 :             mPASESession->AsSecureSession()->MarkForEviction();
      91              :         }
      92            2 :         HandleFailedAttempt(CHIP_ERROR_TIMEOUT);
      93              :     }
      94            4 :     else if (event->Type == DeviceLayer::DeviceEventType::kOperationalNetworkEnabled)
      95              :     {
      96            0 :         CHIP_ERROR err = app::DnssdServer::Instance().AdvertiseOperational();
      97            0 :         if (err != CHIP_NO_ERROR)
      98              :         {
      99            0 :             ChipLogError(AppServer, "Operational advertising failed: %" CHIP_ERROR_FORMAT, err.Format());
     100              :         }
     101              :         else
     102              :         {
     103            0 :             ChipLogProgress(AppServer, "Operational advertising enabled");
     104              :         }
     105              :     }
     106              : #if CONFIG_NETWORK_LAYER_BLE
     107            4 :     else if (event->Type == DeviceLayer::DeviceEventType::kCloseAllBleConnections)
     108              :     {
     109            0 :         ChipLogProgress(AppServer, "Received kCloseAllBleConnections:%d", static_cast<int>(event->Type));
     110            0 :         mServer->GetBleLayerObject()->Shutdown();
     111              :     }
     112              : #endif
     113            6 : }
     114              : 
     115            1 : void CommissioningWindowManager::Shutdown()
     116              : {
     117            1 :     VerifyOrReturn(nullptr != mServer);
     118              : 
     119            1 :     TEMPORARY_RETURN_IGNORED StopAdvertisement(/* aShuttingDown = */ true);
     120              : 
     121            1 :     ResetState();
     122              : }
     123              : 
     124            9 : void CommissioningWindowManager::ResetState()
     125              : {
     126            9 :     mUseECM = false;
     127              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     128              :     mJCM = false;
     129              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     130              : 
     131            9 :     mECMDiscriminator = 0;
     132            9 :     mECMIterations    = 0;
     133            9 :     mECMSaltLength    = 0;
     134              : 
     135            9 :     UpdateWindowStatus(CommissioningWindowStatusEnum::kWindowNotOpen);
     136              : 
     137            9 :     UpdateOpenerFabricIndex(NullNullable);
     138            9 :     UpdateOpenerVendorId(NullNullable);
     139              : 
     140            9 :     memset(&mECMPASEVerifier, 0, sizeof(mECMPASEVerifier));
     141            9 :     memset(mECMSalt, 0, sizeof(mECMSalt));
     142              : 
     143            9 :     DeviceLayer::SystemLayer().CancelTimer(HandleCommissioningWindowTimeout, this);
     144            9 :     mCommissioningTimeoutTimerArmed = false;
     145            9 : }
     146              : 
     147            8 : void CommissioningWindowManager::Cleanup()
     148              : {
     149            8 :     TEMPORARY_RETURN_IGNORED StopAdvertisement(/* aShuttingDown = */ false);
     150            8 :     ResetState();
     151            8 : }
     152              : 
     153            0 : void CommissioningWindowManager::OnSessionEstablishmentError(CHIP_ERROR err)
     154              : {
     155            0 :     DeviceLayer::SystemLayer().CancelTimer(HandleSessionEstablishmentTimeout, this);
     156            0 :     HandleFailedAttempt(err);
     157            0 : }
     158              : 
     159            2 : void CommissioningWindowManager::HandleFailedAttempt(CHIP_ERROR err)
     160              : {
     161            2 :     mFailedCommissioningAttempts++;
     162            2 :     ChipLogError(AppServer, "Commissioning failed (attempt %d): %" CHIP_ERROR_FORMAT, mFailedCommissioningAttempts, err.Format());
     163              : #if CONFIG_NETWORK_LAYER_BLE
     164            2 :     mServer->GetBleLayerObject()->CloseAllBleConnections();
     165              : #endif
     166              : 
     167            2 :     CHIP_ERROR prevErr = err;
     168            2 :     if (mFailedCommissioningAttempts < kMaxFailedCommissioningAttempts)
     169              :     {
     170              :         // If the number of commissioning attempts has not exceeded maximum
     171              :         // retries, let's start listening for commissioning connections again.
     172            2 :         err = AdvertiseAndListenForPASE();
     173              :     }
     174              : 
     175            2 :     if (mAppDelegate != nullptr)
     176              :     {
     177            0 :         mAppDelegate->OnCommissioningSessionEstablishmentError(prevErr);
     178              :     }
     179              : 
     180            4 :     if (err != CHIP_NO_ERROR)
     181              :     {
     182              :         // The commissioning attempts limit was exceeded, or listening for
     183              :         // commmissioning connections failed.
     184            2 :         Cleanup();
     185              : 
     186            2 :         if (mAppDelegate != nullptr)
     187              :         {
     188            0 :             mAppDelegate->OnCommissioningSessionStopped();
     189              :         }
     190              :     }
     191            2 : }
     192              : 
     193            2 : void CommissioningWindowManager::OnSessionEstablishmentStarted()
     194              : {
     195              :     // As per specifications, section 5.5: Commissioning Flows
     196            2 :     constexpr System::Clock::Timeout kPASESessionEstablishmentTimeout = System::Clock::Seconds16(60);
     197            2 :     TEMPORARY_RETURN_IGNORED DeviceLayer::SystemLayer().StartTimer(kPASESessionEstablishmentTimeout,
     198              :                                                                    HandleSessionEstablishmentTimeout, this);
     199              : 
     200            2 :     ChipLogProgress(AppServer, "Commissioning session establishment step started");
     201            2 :     if (mAppDelegate != nullptr)
     202              :     {
     203            0 :         mAppDelegate->OnCommissioningSessionEstablishmentStarted();
     204              :     }
     205            2 : }
     206              : 
     207            2 : void CommissioningWindowManager::OnSessionEstablished(const SessionHandle & session)
     208              : {
     209            2 :     DeviceLayer::SystemLayer().CancelTimer(HandleSessionEstablishmentTimeout, this);
     210              : 
     211            2 :     ChipLogProgress(AppServer, "Commissioning completed session establishment step");
     212            2 :     if (mAppDelegate != nullptr)
     213              :     {
     214            0 :         mAppDelegate->OnCommissioningSessionStarted();
     215              :     }
     216              : 
     217            2 :     TEMPORARY_RETURN_IGNORED StopAdvertisement(/* aShuttingDown = */ false);
     218              : 
     219            2 :     auto & failSafeContext = Server::GetInstance().GetFailSafeContext();
     220              :     // This should never be armed because we don't allow CASE sessions to arm the failsafe when the commissioning window is open and
     221              :     // we check that the failsafe is not armed before opening the commissioning window. None the less, it is good to double-check.
     222            2 :     CHIP_ERROR err = CHIP_NO_ERROR;
     223            2 :     if (failSafeContext.IsFailSafeArmed())
     224              :     {
     225            0 :         ChipLogError(AppServer, "Error - arm failsafe is already armed on PASE session establishment completion");
     226              :     }
     227              :     else
     228              :     {
     229            2 :         err = failSafeContext.ArmFailSafe(kUndefinedFabricIndex, kFailSafeTimeoutPostPaseCompletion);
     230            4 :         if (err != CHIP_NO_ERROR)
     231              :         {
     232            0 :             ChipLogError(AppServer, "Error arming failsafe on PASE session establishment completion");
     233              :             // Don't allow a PASE session to hang around without a fail-safe.
     234            0 :             session->AsSecureSession()->MarkForEviction();
     235            0 :             HandleFailedAttempt(err);
     236              :         }
     237              :     }
     238              : 
     239            2 :     ChipLogProgress(AppServer, "Device completed Rendezvous process");
     240              : 
     241            4 :     if (err == CHIP_NO_ERROR)
     242              :     {
     243              :         // When the now-armed fail-safe is disarmed or expires it will handle
     244              :         // clearing out mPASESession.
     245            2 :         mPASESession.Grab(session);
     246            2 :         TEMPORARY_RETURN_IGNORED DeviceLayer::PlatformMgr().AddEventHandler(OnPlatformEventWrapper,
     247              :                                                                             reinterpret_cast<intptr_t>(this));
     248              :     }
     249            2 : }
     250              : 
     251            8 : CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow(Seconds32 commissioningTimeout)
     252              : {
     253            8 :     VerifyOrReturnError(commissioningTimeout <= MaxCommissioningTimeout() && commissioningTimeout >= MinCommissioningTimeout(),
     254              :                         CHIP_ERROR_INVALID_ARGUMENT);
     255            8 :     auto & failSafeContext = Server::GetInstance().GetFailSafeContext();
     256            8 :     VerifyOrReturnError(failSafeContext.IsFailSafeFullyDisarmed(), CHIP_ERROR_INCORRECT_STATE);
     257              : 
     258            8 :     ReturnErrorOnFailure(Dnssd::ServiceAdvertiser::Instance().UpdateCommissionableInstanceName());
     259              : 
     260           16 :     ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(commissioningTimeout, HandleCommissioningWindowTimeout, this));
     261              : 
     262            8 :     mCommissioningTimeoutTimerArmed = true;
     263              : 
     264            8 :     return AdvertiseAndListenForPASE();
     265              : }
     266              : 
     267           10 : CHIP_ERROR CommissioningWindowManager::AdvertiseAndListenForPASE()
     268              : {
     269           10 :     VerifyOrReturnError(mCommissioningTimeoutTimerArmed, CHIP_ERROR_INCORRECT_STATE);
     270              : 
     271            8 :     mPairingSession.Clear();
     272              : 
     273            8 :     ReturnErrorOnFailure(mServer->GetExchangeManager().RegisterUnsolicitedMessageHandlerForType(
     274              :         Protocols::SecureChannel::MsgType::PBKDFParamRequest, this));
     275            8 :     mListeningForPASE = true;
     276              : 
     277            8 :     if (mUseECM)
     278              :     {
     279            3 :         ReturnErrorOnFailure(SetTemporaryDiscriminator(mECMDiscriminator));
     280            3 :         ReturnErrorOnFailure(mPairingSession.WaitForPairing(mServer->GetSecureSessionManager(), mECMPASEVerifier, mECMIterations,
     281              :                                                             ByteSpan(mECMSalt, mECMSaltLength), GetLocalMRPConfig(), this));
     282              :     }
     283              :     else
     284              :     {
     285            5 :         uint32_t iterationCount                      = 0;
     286            5 :         uint8_t salt[kSpake2p_Max_PBKDF_Salt_Length] = { 0 };
     287            5 :         Spake2pVerifierSerialized serializedVerifier = { 0 };
     288            5 :         size_t serializedVerifierLen                 = 0;
     289              :         Spake2pVerifier verifier;
     290            5 :         MutableByteSpan saltSpan{ salt };
     291            5 :         MutableByteSpan verifierSpan{ serializedVerifier };
     292              : 
     293            5 :         auto * commissionableDataProvider = DeviceLayer::GetCommissionableDataProvider();
     294            5 :         ReturnErrorOnFailure(commissionableDataProvider->GetSpake2pIterationCount(iterationCount));
     295            5 :         ReturnErrorOnFailure(commissionableDataProvider->GetSpake2pSalt(saltSpan));
     296            5 :         ReturnErrorOnFailure(commissionableDataProvider->GetSpake2pVerifier(verifierSpan, serializedVerifierLen));
     297            5 :         VerifyOrReturnError(Crypto::kSpake2p_VerifierSerialized_Length == serializedVerifierLen, CHIP_ERROR_INVALID_ARGUMENT);
     298            5 :         VerifyOrReturnError(verifierSpan.size() == serializedVerifierLen, CHIP_ERROR_INTERNAL);
     299              : 
     300            5 :         ReturnErrorOnFailure(verifier.Deserialize(ByteSpan(serializedVerifier)));
     301              : 
     302            5 :         ReturnErrorOnFailure(mPairingSession.WaitForPairing(mServer->GetSecureSessionManager(), verifier, iterationCount, saltSpan,
     303              :                                                             GetLocalMRPConfig(), this));
     304              :     }
     305              : 
     306            8 :     ReturnErrorOnFailure(StartAdvertisement());
     307              : 
     308            8 :     return CHIP_NO_ERROR;
     309              : }
     310              : 
     311           12 : System::Clock::Seconds32 CommissioningWindowManager::MaxCommissioningTimeout() const
     312              : {
     313              : #if CHIP_DEVICE_CONFIG_EXT_ADVERTISING
     314              :     /* Allow for extended announcement only if the device is uncomissioned. */
     315              :     if (mServer->GetFabricTable().FabricCount() == 0)
     316              :     {
     317              :         // Specification section 2.3.1 - Extended Announcement Duration up to 48h
     318              :         return System::Clock::Seconds32(60 * 60 * 48);
     319              :     }
     320              : #endif
     321              :     // Specification section 5.4.2.3. Announcement Duration says 15 minutes.
     322           12 :     return System::Clock::Seconds32(15 * 60);
     323              : }
     324              : 
     325            5 : CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindow(Seconds32 commissioningTimeout,
     326              :                                                                     CommissioningWindowAdvertisement advertisementMode)
     327              : {
     328            5 :     TEMPORARY_RETURN_IGNORED RestoreDiscriminator();
     329              : 
     330              : #if CONFIG_NETWORK_LAYER_BLE
     331              :     // Enable BLE advertisements if commissioning window is to be opened on all supported
     332              :     // transports, and BLE is supported on the current device.
     333            5 :     SetBLE(advertisementMode == chip::CommissioningWindowAdvertisement::kAllSupported);
     334              : #else
     335              :     SetBLE(false);
     336              : #endif // CONFIG_NETWORK_LAYER_BLE
     337              : 
     338            5 :     mFailedCommissioningAttempts = 0;
     339              : 
     340            5 :     mUseECM = false;
     341              : 
     342            5 :     CHIP_ERROR err = OpenCommissioningWindow(commissioningTimeout);
     343           10 :     if (err != CHIP_NO_ERROR)
     344              :     {
     345            0 :         Cleanup();
     346              :     }
     347              : 
     348            5 :     return err;
     349              : }
     350              : 
     351              : CHIP_ERROR
     352            1 : CommissioningWindowManager::OpenBasicCommissioningWindowForAdministratorCommissioningCluster(
     353              :     System::Clock::Seconds32 commissioningTimeout, FabricIndex fabricIndex, VendorId vendorId)
     354              : {
     355            1 :     ReturnErrorOnFailure(OpenBasicCommissioningWindow(commissioningTimeout, CommissioningWindowAdvertisement::kDnssdOnly));
     356              : 
     357            1 :     UpdateOpenerFabricIndex(MakeNullable(fabricIndex));
     358            1 :     UpdateOpenerVendorId(MakeNullable(vendorId));
     359              : 
     360            1 :     return CHIP_NO_ERROR;
     361              : }
     362              : 
     363            3 : CHIP_ERROR CommissioningWindowManager::OpenEnhancedCommissioningWindow(Seconds32 commissioningTimeout, uint16_t discriminator,
     364              :                                                                        Spake2pVerifier & verifier, uint32_t iterations,
     365              :                                                                        ByteSpan salt, FabricIndex fabricIndex, VendorId vendorId)
     366              : {
     367              :     // Once a device is operational, it shall be commissioned into subsequent fabrics using
     368              :     // the operational network only.
     369            3 :     SetBLE(false);
     370              : 
     371            3 :     VerifyOrReturnError(salt.size() <= sizeof(mECMSalt), CHIP_ERROR_INVALID_ARGUMENT);
     372              : 
     373            3 :     memcpy(mECMSalt, salt.data(), salt.size());
     374            3 :     mECMSaltLength = static_cast<uint32_t>(salt.size());
     375              : 
     376            3 :     mFailedCommissioningAttempts = 0;
     377              : 
     378            3 :     mECMDiscriminator = discriminator;
     379            3 :     mECMIterations    = iterations;
     380              : 
     381            3 :     memcpy(&mECMPASEVerifier, &verifier, sizeof(Spake2pVerifier));
     382              : 
     383            3 :     mUseECM = true;
     384              : 
     385            3 :     CHIP_ERROR err = OpenCommissioningWindow(commissioningTimeout);
     386            6 :     if (err != CHIP_NO_ERROR)
     387              :     {
     388            0 :         Cleanup();
     389              :     }
     390              :     else
     391              :     {
     392            3 :         UpdateOpenerFabricIndex(MakeNullable(fabricIndex));
     393            3 :         UpdateOpenerVendorId(MakeNullable(vendorId));
     394              :     }
     395              : 
     396            3 :     return err;
     397              : }
     398              : 
     399              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     400              : CHIP_ERROR CommissioningWindowManager::OpenJointCommissioningWindow(Seconds32 commissioningTimeout, uint16_t discriminator,
     401              :                                                                     Spake2pVerifier & verifier, uint32_t iterations, ByteSpan salt,
     402              :                                                                     FabricIndex fabricIndex, VendorId vendorId)
     403              : {
     404              :     mJCM = true;
     405              :     return OpenEnhancedCommissioningWindow(commissioningTimeout, discriminator, verifier, iterations, salt, fabricIndex, vendorId);
     406              : }
     407              : 
     408              : bool CommissioningWindowManager::IsJCM() const
     409              : {
     410              :     return mJCM;
     411              : }
     412              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     413              : 
     414            6 : void CommissioningWindowManager::CloseCommissioningWindow()
     415              : {
     416            6 :     if (IsCommissioningWindowOpen())
     417              :     {
     418              : #if CONFIG_NETWORK_LAYER_BLE
     419            6 :         if (mListeningForPASE)
     420              :         {
     421              :             // We never established PASE, so never armed a fail-safe and hence
     422              :             // can't rely on it expiring to close our BLE connection.  Do that
     423              :             // manually here.
     424            4 :             mServer->GetBleLayerObject()->CloseAllBleConnections();
     425              :         }
     426              : #endif
     427            6 :         ChipLogProgress(AppServer, "Closing pairing window");
     428            6 :         Cleanup();
     429              :     }
     430            6 : }
     431              : 
     432           66 : CommissioningWindowStatusEnum CommissioningWindowManager::CommissioningWindowStatusForCluster() const
     433              : {
     434              :     // If the condition we use to determine whether we were opened via the
     435              :     // cluster ever changes, make sure whatever code affects that condition
     436              :     // marks calls MatterReportingAttributeChangeCallback for WindowStatus as
     437              :     // needed.
     438           66 :     if (mOpenerVendorId.IsNull())
     439              :     {
     440              :         // Not opened via the cluster.
     441           48 :         return CommissioningWindowStatusEnum::kWindowNotOpen;
     442              :     }
     443              : 
     444           18 :     return mWindowStatus;
     445              : }
     446              : 
     447           22 : bool CommissioningWindowManager::IsCommissioningWindowOpen() const
     448              : {
     449           22 :     return mWindowStatus != CommissioningWindowStatusEnum::kWindowNotOpen;
     450              : }
     451              : 
     452            0 : void CommissioningWindowManager::OnFabricRemoved(FabricIndex removedIndex)
     453              : {
     454            0 :     if (!mOpenerFabricIndex.IsNull() && mOpenerFabricIndex.Value() == removedIndex)
     455              :     {
     456              :         // Per spec, we should clear out the stale fabric index.
     457            0 :         UpdateOpenerFabricIndex(NullNullable);
     458              :     }
     459            0 : }
     460              : 
     461           20 : Dnssd::CommissioningMode CommissioningWindowManager::GetCommissioningMode() const
     462              : {
     463           20 :     if (!mListeningForPASE)
     464              :     {
     465              :         // We should not be advertising ourselves as in commissioning mode.
     466              :         // We need to check this before mWindowStatus, because we might have an
     467              :         // open window even while we are not listening for PASE.
     468           11 :         return Dnssd::CommissioningMode::kDisabled;
     469              :     }
     470              : 
     471            9 :     switch (mWindowStatus)
     472              :     {
     473            3 :     case CommissioningWindowStatusEnum::kEnhancedWindowOpen:
     474              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     475              :         return mJCM ? Dnssd::CommissioningMode::kEnabledJointFabric : Dnssd::CommissioningMode::kEnabledEnhanced;
     476              : #else
     477            3 :         return Dnssd::CommissioningMode::kEnabledEnhanced;
     478              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     479            6 :     case CommissioningWindowStatusEnum::kBasicWindowOpen:
     480            6 :         return Dnssd::CommissioningMode::kEnabledBasic;
     481            0 :     default:
     482            0 :         return Dnssd::CommissioningMode::kDisabled;
     483              :     }
     484              : }
     485              : 
     486            8 : CHIP_ERROR CommissioningWindowManager::StartAdvertisement()
     487              : {
     488              : #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
     489              :     // notify device layer that advertisement is beginning (to do work such as increment rotating id)
     490              :     DeviceLayer::ConfigurationMgr().NotifyOfAdvertisementStart();
     491              : #endif
     492              : 
     493              : #if CONFIG_NETWORK_LAYER_BLE
     494            8 :     if (mIsBLE)
     495              :     {
     496            1 :         CHIP_ERROR err = chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(true);
     497              :         // BLE advertising may just not be supported.  That should not prevent
     498              :         // us from opening a commissioning window and advertising over IP.
     499            2 :         if (err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE)
     500              :         {
     501            0 :             ChipLogProgress(AppServer, "BLE networking available but BLE advertising is not supported");
     502            0 :             err = CHIP_NO_ERROR;
     503              :         }
     504            1 :         ReturnErrorOnFailure(err);
     505              :     }
     506              : #endif // CONFIG_NETWORK_LAYER_BLE
     507              : 
     508            8 :     if (mUseECM)
     509              :     {
     510            3 :         UpdateWindowStatus(CommissioningWindowStatusEnum::kEnhancedWindowOpen);
     511              :     }
     512              :     else
     513              :     {
     514            5 :         UpdateWindowStatus(CommissioningWindowStatusEnum::kBasicWindowOpen);
     515              :     }
     516              : 
     517            8 :     if (mAppDelegate != nullptr)
     518              :     {
     519            0 :         mAppDelegate->OnCommissioningWindowOpened();
     520              :     }
     521              : 
     522              :     // reset all advertising, switching to our new commissioning mode.
     523            8 :     app::DnssdServer::Instance().StartServer();
     524              : 
     525            8 :     return CHIP_NO_ERROR;
     526              : }
     527              : 
     528           11 : CHIP_ERROR CommissioningWindowManager::StopAdvertisement(bool aShuttingDown)
     529              : {
     530           11 :     TEMPORARY_RETURN_IGNORED RestoreDiscriminator();
     531              : 
     532           11 :     TEMPORARY_RETURN_IGNORED mServer->GetExchangeManager().UnregisterUnsolicitedMessageHandlerForType(
     533              :         Protocols::SecureChannel::MsgType::PBKDFParamRequest);
     534           11 :     mListeningForPASE = false;
     535           11 :     mPairingSession.Clear();
     536              : 
     537              :     // If aShuttingDown, don't try to change our DNS-SD advertisements.
     538           11 :     if (!aShuttingDown)
     539              :     {
     540              :         // Stop advertising commissioning mode, since we're not accepting PASE
     541              :         // connections right now.  If we start accepting them again (via
     542              :         // AdvertiseAndListenForPASE) that will call StartAdvertisement as needed.
     543           10 :         app::DnssdServer::Instance().StartServer();
     544              :     }
     545              : 
     546              : #if CONFIG_NETWORK_LAYER_BLE
     547           11 :     if (mIsBLE)
     548              :     {
     549              :         // Ignore errors from SetBLEAdvertisingEnabled (which could be due to
     550              :         // BLE advertising not being supported at all).  Our commissioning
     551              :         // window is now closed and we need to notify our delegate of that.
     552            1 :         (void) chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false);
     553              :     }
     554              : #endif // CONFIG_NETWORK_LAYER_BLE
     555              : 
     556           11 :     if (mAppDelegate != nullptr)
     557              :     {
     558            0 :         mAppDelegate->OnCommissioningWindowClosed();
     559              :     }
     560              : 
     561           11 :     return CHIP_NO_ERROR;
     562              : }
     563              : 
     564            3 : CHIP_ERROR CommissioningWindowManager::SetTemporaryDiscriminator(uint16_t discriminator)
     565              : {
     566            3 :     return app::DnssdServer::Instance().SetEphemeralDiscriminator(MakeOptional(discriminator));
     567              : }
     568              : 
     569           16 : CHIP_ERROR CommissioningWindowManager::RestoreDiscriminator()
     570              : {
     571           16 :     return app::DnssdServer::Instance().SetEphemeralDiscriminator(NullOptional);
     572              : }
     573              : 
     574            1 : void CommissioningWindowManager::HandleCommissioningWindowTimeout(chip::System::Layer * aSystemLayer, void * aAppState)
     575              : {
     576            1 :     auto * commissionMgr                           = static_cast<CommissioningWindowManager *>(aAppState);
     577            1 :     commissionMgr->mCommissioningTimeoutTimerArmed = false;
     578            1 :     commissionMgr->CloseCommissioningWindow();
     579            1 : }
     580              : 
     581            2 : void CommissioningWindowManager::OnSessionReleased()
     582              : {
     583              :     // The PASE session has died, probably due to CloseSession.  Immediately
     584              :     // expire the fail-safe, if it's still armed (which it might not be if the
     585              :     // PASE session is being released due to the fail-safe expiring or being
     586              :     // disarmed).
     587              :     //
     588              :     // Expiring the fail-safe will make us start listening for new PASE sessions
     589              :     // as needed.
     590              :     //
     591              :     // Note that at this point the fail-safe _must_ be associated with our PASE
     592              :     // session, since we arm it when the PASE session is set up, and anything
     593              :     // that disarms the fail-safe would also tear down the PASE session.
     594            2 :     ExpireFailSafeIfArmed();
     595              : 
     596            2 :     DeviceLayer::PlatformMgr().RemoveEventHandler(OnPlatformEventWrapper, reinterpret_cast<intptr_t>(this));
     597            2 : }
     598              : 
     599            4 : void CommissioningWindowManager::ExpireFailSafeIfArmed()
     600              : {
     601            4 :     auto & failSafeContext = Server::GetInstance().GetFailSafeContext();
     602            4 :     if (failSafeContext.IsFailSafeArmed())
     603              :     {
     604            2 :         failSafeContext.ForceFailSafeTimerExpiry();
     605              :     }
     606            4 : }
     607              : 
     608            3 : void CommissioningWindowManager::ExpireFailSafeIfHeldByOpenPASESession()
     609              : {
     610            3 :     if (GetPASESession().HasValue())
     611              :     {
     612            2 :         ChipLogProgress(AppServer, "Active PASE session detected; expiring the fail-safe held by it (if still armed)");
     613            2 :         ExpireFailSafeIfArmed();
     614              :     }
     615            3 : }
     616              : 
     617           17 : void CommissioningWindowManager::UpdateWindowStatus(CommissioningWindowStatusEnum aNewStatus)
     618              : {
     619           17 :     CommissioningWindowStatusEnum oldClusterStatus = CommissioningWindowStatusForCluster();
     620           17 :     if (mWindowStatus != aNewStatus)
     621              :     {
     622           13 :         mWindowStatus = aNewStatus;
     623              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     624              :         app::ICDListener::KeepActiveFlags request = app::ICDListener::KeepActiveFlag::kCommissioningWindowOpen;
     625              :         if (mWindowStatus != CommissioningWindowStatusEnum::kWindowNotOpen)
     626              :         {
     627              :             app::ICDNotifier::GetInstance().NotifyActiveRequestNotification(request);
     628              :         }
     629              :         else
     630              :         {
     631              :             app::ICDNotifier::GetInstance().NotifyActiveRequestWithdrawal(request);
     632              :         }
     633              : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     634              :     }
     635              : 
     636           17 :     if (CommissioningWindowStatusForCluster() != oldClusterStatus)
     637              :     {
     638              :         // The Administrator Commissioning cluster is always on the root endpoint.
     639            4 :         MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
     640              :                                                AdministratorCommissioning::Attributes::WindowStatus::Id);
     641              :     }
     642           17 : }
     643              : 
     644           13 : void CommissioningWindowManager::UpdateOpenerVendorId(Nullable<VendorId> aNewOpenerVendorId)
     645              : {
     646              :     // Changing the opener vendor id affects what
     647              :     // CommissioningWindowStatusForCluster() returns.
     648           13 :     CommissioningWindowStatusEnum oldClusterStatus = CommissioningWindowStatusForCluster();
     649              : 
     650           13 :     if (mOpenerVendorId != aNewOpenerVendorId)
     651              :     {
     652              :         // The Administrator Commissioning cluster is always on the root endpoint.
     653            8 :         MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
     654              :                                                AdministratorCommissioning::Attributes::AdminVendorId::Id);
     655              :     }
     656              : 
     657           13 :     mOpenerVendorId = aNewOpenerVendorId;
     658              : 
     659           13 :     if (CommissioningWindowStatusForCluster() != oldClusterStatus)
     660              :     {
     661              :         // The Administrator Commissioning cluster is always on the root endpoint.
     662            4 :         MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
     663              :                                                AdministratorCommissioning::Attributes::WindowStatus::Id);
     664              :     }
     665           13 : }
     666              : 
     667           13 : void CommissioningWindowManager::UpdateOpenerFabricIndex(Nullable<FabricIndex> aNewOpenerFabricIndex)
     668              : {
     669           13 :     if (mOpenerFabricIndex != aNewOpenerFabricIndex)
     670              :     {
     671              :         // The Administrator Commissioning cluster is always on the root endpoint.
     672            8 :         MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
     673              :                                                AdministratorCommissioning::Attributes::AdminFabricIndex::Id);
     674              :     }
     675              : 
     676           13 :     mOpenerFabricIndex = aNewOpenerFabricIndex;
     677           13 : }
     678              : 
     679            2 : CHIP_ERROR CommissioningWindowManager::OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader,
     680              :                                                                     Messaging::ExchangeDelegate *& newDelegate)
     681              : {
     682              :     using Protocols::SecureChannel::MsgType;
     683              : 
     684              :     // Must be a PBKDFParamRequest message.  Stop listening to new
     685              :     // PBKDFParamRequest messages and hand it off to mPairingSession.  If
     686              :     // mPairingSession's OnMessageReceived fails, it will call our
     687              :     // OnSessionEstablishmentError, and that will either start listening for a
     688              :     // new PBKDFParamRequest or not, depending on how many failures we had seen.
     689              :     //
     690              :     // It's very important that we stop listening here, so that new incoming
     691              :     // PASE establishment attempts don't interrupt our existing establishment.
     692            2 :     TEMPORARY_RETURN_IGNORED mServer->GetExchangeManager().UnregisterUnsolicitedMessageHandlerForType(MsgType::PBKDFParamRequest);
     693            2 :     newDelegate = &mPairingSession;
     694            2 :     return CHIP_NO_ERROR;
     695              : }
     696              : 
     697            0 : void CommissioningWindowManager::OnExchangeCreationFailed(Messaging::ExchangeDelegate * delegate)
     698              : {
     699              :     using Protocols::SecureChannel::MsgType;
     700              : 
     701              :     // We couldn't create an exchange, so didn't manage to call
     702              :     // OnMessageReceived on mPairingSession.  Just go back to listening for
     703              :     // PBKDFParamRequest messages.
     704            0 :     TEMPORARY_RETURN_IGNORED mServer->GetExchangeManager().RegisterUnsolicitedMessageHandlerForType(MsgType::PBKDFParamRequest,
     705              :                                                                                                     this);
     706            0 : }
     707              : 
     708              : } // namespace chip
        

Generated by: LCOV version 2.0-1