Matter SDK Coverage Report
Current view: top level - app/server - CommissioningWindowManager.cpp (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 84.4 % 282 238
Test Date: 2026-06-03 07:35:21 Functions: 86.1 % 36 31

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

Generated by: LCOV version 2.0-1