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