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