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 : #pragma once 19 : 20 : #include <app/data-model/Nullable.h> 21 : #include <app/server/AppDelegate.h> 22 : #include <app/server/CommissioningModeProvider.h> 23 : #include <lib/core/CHIPVendorIdentifiers.hpp> 24 : #include <lib/core/ClusterEnums.h> 25 : #include <lib/core/DataModelTypes.h> 26 : #include <lib/dnssd/Advertiser.h> 27 : #include <messaging/ExchangeDelegate.h> 28 : #include <platform/CHIPDeviceConfig.h> 29 : #include <protocols/secure_channel/RendezvousParameters.h> 30 : #include <system/SystemClock.h> 31 : 32 : namespace chip { 33 : 34 : enum class CommissioningWindowAdvertisement 35 : { 36 : kAllSupported, 37 : kDnssdOnly, 38 : }; 39 : 40 : class Server; 41 : 42 : class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, 43 : public SessionEstablishmentDelegate, 44 : public app::CommissioningModeProvider, 45 : public SessionDelegate 46 : { 47 : public: 48 1 : CommissioningWindowManager() : mPASESession(*this) {} 49 : 50 1 : CHIP_ERROR Init(Server * server) 51 : { 52 1 : if (server == nullptr) 53 : { 54 0 : return CHIP_ERROR_INVALID_ARGUMENT; 55 : } 56 1 : mServer = server; 57 1 : return CHIP_NO_ERROR; 58 : } 59 : 60 0 : static constexpr System::Clock::Seconds16 MaxCommissioningTimeout() 61 : { 62 : #if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING 63 : // Specification section 2.3.1 - Extended Announcement Duration up to 48h 64 : return System::Clock::Seconds16(60 * 60 * 48); 65 : #else 66 : // Specification section 5.4.2.3. Announcement Duration says 15 minutes. 67 0 : return System::Clock::Seconds16(15 * 60); 68 : #endif 69 : } 70 : 71 6 : System::Clock::Seconds16 MinCommissioningTimeout() const 72 : { 73 : // Specification section 5.4.2.3. Announcement Duration says 3 minutes. 74 6 : return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds16(3 * 60)); 75 : } 76 : 77 1 : void SetAppDelegate(AppDelegate * delegate) { mAppDelegate = delegate; } 78 : 79 : /** 80 : * Open the pairing window using default configured parameters. 81 : */ 82 : CHIP_ERROR 83 : OpenBasicCommissioningWindow( 84 1 : System::Clock::Seconds16 commissioningTimeout = System::Clock::Seconds16(CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS), 85 : CommissioningWindowAdvertisement advertisementMode = chip::CommissioningWindowAdvertisement::kAllSupported); 86 : 87 : /** 88 : * Open the pairing window using default configured parameters, triggered by 89 : * the Administrator Commmissioning cluster implementation. 90 : */ 91 : CHIP_ERROR 92 : OpenBasicCommissioningWindowForAdministratorCommissioningCluster(System::Clock::Seconds16 commissioningTimeout, 93 : FabricIndex fabricIndex, VendorId vendorId); 94 : 95 : CHIP_ERROR OpenEnhancedCommissioningWindow(System::Clock::Seconds16 commissioningTimeout, uint16_t discriminator, 96 : Spake2pVerifier & verifier, uint32_t iterations, chip::ByteSpan salt, 97 : FabricIndex fabricIndex, VendorId vendorId); 98 : 99 : void CloseCommissioningWindow(); 100 : 101 : app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum CommissioningWindowStatusForCluster() const; 102 : 103 : bool IsCommissioningWindowOpen() const; 104 : 105 : const app::DataModel::Nullable<VendorId> & GetOpenerVendorId() const { return mOpenerVendorId; } 106 : 107 : const app::DataModel::Nullable<FabricIndex> & GetOpenerFabricIndex() const { return mOpenerFabricIndex; } 108 : 109 : void OnFabricRemoved(FabricIndex removedIndex); 110 : 111 : // CommissioningModeProvider implementation. 112 : Dnssd::CommissioningMode GetCommissioningMode() const override; 113 : 114 : //// UnsolicitedMessageHandler Implementation //// 115 : CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, 116 : Messaging::ExchangeDelegate *& newDelegate) override; 117 : void OnExchangeCreationFailed(Messaging::ExchangeDelegate * delegate) override; 118 : 119 : //////////// SessionEstablishmentDelegate Implementation /////////////// 120 : void OnSessionEstablishmentError(CHIP_ERROR error) override; 121 : void OnSessionEstablishmentStarted() override; 122 : void OnSessionEstablished(const SessionHandle & session) override; 123 : 124 : void Shutdown(); 125 : 126 : void OnPlatformEvent(const DeviceLayer::ChipDeviceEvent * event); 127 : 128 : // For tests only, allow overriding the spec-defined minimum value of the 129 : // commissioning window timeout. 130 : void OverrideMinCommissioningTimeout(System::Clock::Seconds16 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); } 131 : 132 : private: 133 : //////////// SessionDelegate Implementation /////////////// 134 : void OnSessionReleased() override; 135 : 136 6 : void SetBLE(bool ble) { mIsBLE = ble; } 137 : 138 : CHIP_ERROR SetTemporaryDiscriminator(uint16_t discriminator); 139 : 140 : CHIP_ERROR RestoreDiscriminator(); 141 : 142 : CHIP_ERROR StartAdvertisement(); 143 : 144 : CHIP_ERROR StopAdvertisement(bool aShuttingDown); 145 : 146 : // Start a timer that will call HandleCommissioningWindowTimeout, and then 147 : // start advertising and listen for PASE. 148 : CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds16 commissioningTimeout); 149 : 150 : // Start advertising and listening for PASE connections. Should only be 151 : // called when a commissioning window timeout timer is running. 152 : CHIP_ERROR AdvertiseAndListenForPASE(); 153 : 154 : // Call AdvertiseAndListenForPASE, only if max attempts have not been reached. 155 : // Cleans up and calls app server delegate on failure. 156 : // err gives the current error we're attemping to recover from 157 : void HandleFailedAttempt(CHIP_ERROR err); 158 : 159 : // Helper for Shutdown and Cleanup. Does not do anything with 160 : // advertisements, because Shutdown and Cleanup want to handle those 161 : // differently. 162 : void ResetState(); 163 : 164 : void Cleanup(); 165 : 166 : /** 167 : * Function that gets called when our commissioning window timeout timer 168 : * fires. 169 : * 170 : * This timer is started when a commissioning window is initially opened via 171 : * OpenEnhancedCommissioningWindow or OpenBasicCommissioningWindow. 172 : * 173 : * The timer is canceled when a PASE connection is established, because it 174 : * should not affect the actual commissioning process, and after a PASE 175 : * connection is established we will not re-enter commissioning mode without 176 : * a new call to OpenEnhancedCommissioningWindow or 177 : * OpenBasicCommissioningWindow. 178 : */ 179 : static void HandleCommissioningWindowTimeout(chip::System::Layer * aSystemLayer, void * aAppState); 180 : 181 : /** 182 : * Helper to immediately expire the fail-safe if it's currently armed. 183 : */ 184 : void ExpireFailSafeIfArmed(); 185 : 186 : /** 187 : * Helpers to ensure the right attribute reporting happens when our state is 188 : * updated. 189 : */ 190 : void UpdateWindowStatus(app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum aNewStatus); 191 : void UpdateOpenerVendorId(app::DataModel::Nullable<VendorId> aNewOpenerVendorId); 192 : void UpdateOpenerFabricIndex(app::DataModel::Nullable<FabricIndex> aNewOpenerFabricIndex); 193 : 194 : AppDelegate * mAppDelegate = nullptr; 195 : Server * mServer = nullptr; 196 : 197 : app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum mWindowStatus = 198 : app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kWindowNotOpen; 199 : 200 : bool mIsBLE = true; 201 : 202 : PASESession mPairingSession; 203 : 204 : uint8_t mFailedCommissioningAttempts = 0; 205 : 206 : bool mUseECM = false; 207 : Spake2pVerifier mECMPASEVerifier; 208 : uint16_t mECMDiscriminator = 0; 209 : // mListeningForPASE is true only when we are listening for 210 : // PBKDFParamRequest messages or when we're in the middle of a PASE 211 : // handshake. 212 : bool mListeningForPASE = false; 213 : // Boolean that tracks whether we have a live commissioning timeout timer. 214 : bool mCommissioningTimeoutTimerArmed = false; 215 : uint32_t mECMIterations = 0; 216 : uint32_t mECMSaltLength = 0; 217 : uint8_t mECMSalt[kSpake2p_Max_PBKDF_Salt_Length]; 218 : 219 : // For tests only, so that we can test the commissioning window timeout 220 : // without having to wait 3 minutes. 221 : Optional<System::Clock::Seconds16> mMinCommissioningTimeoutOverride; 222 : 223 : // The PASE session we are using, so we can handle CloseSession properly. 224 : SessionHolderWithDelegate mPASESession; 225 : 226 : // Information about who opened the commissioning window. These will only 227 : // be non-null if the window was opened via the operational credentials 228 : // cluster and the fabric index may be null even then if the fabric has been 229 : // removed. 230 : app::DataModel::Nullable<VendorId> mOpenerVendorId; 231 : app::DataModel::Nullable<FabricIndex> mOpenerFabricIndex; 232 : }; 233 : 234 : } // namespace chip