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