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