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