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