Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * Implementation of SetUp Code Pairer, a class that parses a given
22 : * setup code and uses the extracted informations to discover and
23 : * filter commissionables nodes, before initiating the pairing process.
24 : *
25 : */
26 :
27 : #include <controller/SetUpCodePairer.h>
28 :
29 : #include <controller/CHIPDeviceController.h>
30 : #include <lib/dnssd/Resolver.h>
31 : #include <lib/support/CodeUtils.h>
32 : #include <memory>
33 : #include <system/SystemClock.h>
34 : #include <tracing/metric_event.h>
35 :
36 : constexpr uint32_t kDeviceDiscoveredTimeout = CHIP_CONFIG_SETUP_CODE_PAIRER_DISCOVERY_TIMEOUT_SECS * chip::kMillisecondsPerSecond;
37 :
38 : using namespace chip::Tracing;
39 :
40 : namespace chip {
41 : namespace Controller {
42 :
43 : namespace {
44 :
45 0 : CHIP_ERROR GetPayload(const char * setUpCode, SetupPayload & payload)
46 : {
47 0 : bool isQRCode = strncmp(setUpCode, kQRCodePrefix, strlen(kQRCodePrefix)) == 0;
48 0 : if (isQRCode)
49 : {
50 0 : ReturnErrorOnFailure(QRCodeSetupPayloadParser(setUpCode).populatePayload(payload));
51 0 : VerifyOrReturnError(payload.isValidQRCodePayload(), CHIP_ERROR_INVALID_ARGUMENT);
52 : }
53 : else
54 : {
55 0 : ReturnErrorOnFailure(ManualSetupPayloadParser(setUpCode).populatePayload(payload));
56 0 : VerifyOrReturnError(payload.isValidManualCode(), CHIP_ERROR_INVALID_ARGUMENT);
57 : }
58 :
59 0 : return CHIP_NO_ERROR;
60 : }
61 : } // namespace
62 :
63 0 : SetUpCodePairer::~SetUpCodePairer()
64 : {
65 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
66 : DeviceLayer::ConnectivityMgr().WiFiPAFCancelConnect();
67 : #endif
68 0 : }
69 :
70 0 : CHIP_ERROR SetUpCodePairer::PairDevice(NodeId remoteId, const char * setUpCode, SetupCodePairerBehaviour commission,
71 : DiscoveryType discoveryType, Optional<Dnssd::CommonResolutionData> resolutionData)
72 : {
73 0 : VerifyOrReturnErrorWithMetric(kMetricSetupCodePairerPairDevice, mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);
74 0 : VerifyOrReturnErrorWithMetric(kMetricSetupCodePairerPairDevice, remoteId != kUndefinedNodeId, CHIP_ERROR_INVALID_ARGUMENT);
75 :
76 0 : SetupPayload payload;
77 0 : ReturnErrorOnFailure(GetPayload(setUpCode, payload));
78 :
79 0 : if (resolutionData.HasValue())
80 : {
81 0 : VerifyOrReturnErrorWithMetric(kMetricSetupCodePairerPairDevice, discoveryType != DiscoveryType::kAll,
82 : CHIP_ERROR_INVALID_ARGUMENT);
83 0 : if (mRemoteId == remoteId && mSetUpPINCode == payload.setUpPINCode && mConnectionType == commission &&
84 0 : mDiscoveryType == discoveryType)
85 : {
86 0 : NotifyCommissionableDeviceDiscovered(resolutionData.Value());
87 0 : return CHIP_NO_ERROR;
88 : }
89 : }
90 :
91 0 : mConnectionType = commission;
92 0 : mDiscoveryType = discoveryType;
93 0 : mRemoteId = remoteId;
94 0 : mSetUpPINCode = payload.setUpPINCode;
95 :
96 0 : ResetDiscoveryState();
97 :
98 0 : if (resolutionData.HasValue())
99 : {
100 0 : NotifyCommissionableDeviceDiscovered(resolutionData.Value());
101 0 : return CHIP_NO_ERROR;
102 : }
103 :
104 0 : ReturnErrorOnFailureWithMetric(kMetricSetupCodePairerPairDevice, Connect(payload));
105 : auto errorCode =
106 0 : mSystemLayer->StartTimer(System::Clock::Milliseconds32(kDeviceDiscoveredTimeout), OnDeviceDiscoveredTimeoutCallback, this);
107 0 : if (CHIP_NO_ERROR == errorCode)
108 : {
109 : MATTER_LOG_METRIC_BEGIN(kMetricSetupCodePairerPairDevice);
110 : }
111 0 : return errorCode;
112 0 : }
113 :
114 0 : CHIP_ERROR SetUpCodePairer::Connect(SetupPayload & payload)
115 : {
116 0 : CHIP_ERROR err = CHIP_NO_ERROR;
117 0 : bool isRunning = false;
118 :
119 0 : bool searchOverAll = !payload.rendezvousInformation.HasValue();
120 :
121 0 : if (mDiscoveryType == DiscoveryType::kAll)
122 : {
123 0 : if (searchOverAll || payload.rendezvousInformation.Value().Has(RendezvousInformationFlag::kBLE))
124 : {
125 0 : if (CHIP_NO_ERROR == (err = StartDiscoverOverBle(payload)))
126 : {
127 0 : isRunning = true;
128 : }
129 0 : VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err || CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE == err, err);
130 : }
131 :
132 0 : if (searchOverAll || payload.rendezvousInformation.Value().Has(RendezvousInformationFlag::kSoftAP))
133 : {
134 0 : if (CHIP_NO_ERROR == (err = StartDiscoverOverSoftAP(payload)))
135 : {
136 0 : isRunning = true;
137 : }
138 0 : VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err || CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE == err, err);
139 : }
140 0 : if (searchOverAll || payload.rendezvousInformation.Value().Has(RendezvousInformationFlag::kWiFiPAF))
141 : {
142 0 : ChipLogProgress(Controller, "WiFi-PAF: has RendezvousInformationFlag::kWiFiPAF");
143 0 : if (CHIP_NO_ERROR == (err = StartDiscoverOverWiFiPAF(payload)))
144 : {
145 0 : isRunning = true;
146 : }
147 0 : VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err || CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE == err, err);
148 : }
149 : }
150 :
151 : // We always want to search on network because any node that has already been commissioned will use on-network regardless of the
152 : // QR code flag.
153 0 : if (CHIP_NO_ERROR == (err = StartDiscoverOverIP(payload)))
154 : {
155 0 : isRunning = true;
156 : }
157 0 : VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err, err);
158 :
159 0 : return isRunning ? CHIP_NO_ERROR : CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
160 : }
161 :
162 0 : CHIP_ERROR SetUpCodePairer::StartDiscoverOverBle(SetupPayload & payload)
163 : {
164 : #if CONFIG_NETWORK_LAYER_BLE
165 : #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
166 : VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
167 : mCommissioner->ConnectBleTransportToSelf();
168 : #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
169 0 : VerifyOrReturnError(mBleLayer != nullptr, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
170 :
171 0 : ChipLogProgress(Controller, "Starting commissioning discovery over BLE");
172 :
173 : // Handle possibly-sync callbacks.
174 0 : mWaitingForDiscovery[kBLETransport] = true;
175 0 : CHIP_ERROR err = mBleLayer->NewBleConnectionByDiscriminator(payload.discriminator, this, OnDiscoveredDeviceOverBleSuccess,
176 : OnDiscoveredDeviceOverBleError);
177 0 : if (err != CHIP_NO_ERROR)
178 : {
179 0 : mWaitingForDiscovery[kBLETransport] = false;
180 : }
181 0 : return err;
182 : #else
183 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
184 : #endif // CONFIG_NETWORK_LAYER_BLE
185 : }
186 :
187 0 : CHIP_ERROR SetUpCodePairer::StopConnectOverBle()
188 : {
189 : // Make sure to not call CancelBleIncompleteConnection unless we are in fact
190 : // waiting on BLE discovery. It will cancel connections that are in fact
191 : // completed. In particular, if we just established PASE over BLE calling
192 : // CancelBleIncompleteConnection here unconditionally would cancel the BLE
193 : // connection underlying the PASE session. So make sure to only call
194 : // CancelBleIncompleteConnection if we're still waiting to hear back on the
195 : // BLE discovery bits.
196 0 : if (!mWaitingForDiscovery[kBLETransport])
197 : {
198 0 : return CHIP_NO_ERROR;
199 : }
200 :
201 0 : mWaitingForDiscovery[kBLETransport] = false;
202 : #if CONFIG_NETWORK_LAYER_BLE
203 0 : VerifyOrReturnError(mBleLayer != nullptr, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
204 0 : ChipLogDetail(Controller, "Stopping commissioning discovery over BLE");
205 0 : return mBleLayer->CancelBleIncompleteConnection();
206 : #else
207 : return CHIP_NO_ERROR;
208 : #endif // CONFIG_NETWORK_LAYER_BLE
209 : }
210 :
211 0 : CHIP_ERROR SetUpCodePairer::StartDiscoverOverIP(SetupPayload & payload)
212 : {
213 0 : ChipLogProgress(Controller, "Starting commissioning discovery over DNS-SD");
214 :
215 0 : auto & discriminator = payload.discriminator;
216 0 : if (discriminator.IsShortDiscriminator())
217 : {
218 0 : mCurrentFilter.type = Dnssd::DiscoveryFilterType::kShortDiscriminator;
219 0 : mCurrentFilter.code = discriminator.GetShortValue();
220 : }
221 : else
222 : {
223 0 : mCurrentFilter.type = Dnssd::DiscoveryFilterType::kLongDiscriminator;
224 0 : mCurrentFilter.code = discriminator.GetLongValue();
225 : }
226 0 : mPayloadVendorID = payload.vendorID;
227 0 : mPayloadProductID = payload.productID;
228 :
229 : // Handle possibly-sync callbacks.
230 0 : mWaitingForDiscovery[kIPTransport] = true;
231 0 : CHIP_ERROR err = mCommissioner->DiscoverCommissionableNodes(mCurrentFilter);
232 0 : if (err != CHIP_NO_ERROR)
233 : {
234 0 : mWaitingForDiscovery[kIPTransport] = false;
235 : }
236 0 : return err;
237 : }
238 :
239 0 : CHIP_ERROR SetUpCodePairer::StopConnectOverIP()
240 : {
241 0 : ChipLogDetail(Controller, "Stopping commissioning discovery over DNS-SD");
242 :
243 0 : mWaitingForDiscovery[kIPTransport] = false;
244 0 : mCurrentFilter.type = Dnssd::DiscoveryFilterType::kNone;
245 0 : mPayloadVendorID = kNotAvailable;
246 0 : mPayloadProductID = kNotAvailable;
247 :
248 0 : mCommissioner->StopCommissionableDiscovery();
249 0 : return CHIP_NO_ERROR;
250 : }
251 :
252 0 : CHIP_ERROR SetUpCodePairer::StartDiscoverOverSoftAP(SetupPayload & payload)
253 : {
254 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
255 : }
256 :
257 0 : CHIP_ERROR SetUpCodePairer::StopConnectOverSoftAP()
258 : {
259 0 : mWaitingForDiscovery[kSoftAPTransport] = false;
260 0 : return CHIP_NO_ERROR;
261 : }
262 :
263 0 : CHIP_ERROR SetUpCodePairer::StartDiscoverOverWiFiPAF(SetupPayload & payload)
264 : {
265 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
266 : ChipLogProgress(Controller, "Starting commissioning discovery over WiFiPAF");
267 : VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
268 : mWaitingForDiscovery[kWiFiPAFTransport] = true;
269 : CHIP_ERROR err = DeviceLayer::ConnectivityMgr().WiFiPAFConnect(payload.discriminator, (void *) this, OnWiFiPAFSubscribeComplete,
270 : OnWiFiPAFSubscribeError);
271 : if (err != CHIP_NO_ERROR)
272 : {
273 : ChipLogError(Controller, "Commissioning discovery over WiFiPAF failed, err = %" CHIP_ERROR_FORMAT, err.Format());
274 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
275 : }
276 : return err;
277 : #else
278 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
279 : #endif // CONFIG_NETWORK_LAYER_BLE
280 : }
281 :
282 0 : CHIP_ERROR SetUpCodePairer::StopConnectOverWiFiPAF()
283 : {
284 0 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
285 0 : return CHIP_NO_ERROR;
286 : }
287 :
288 0 : bool SetUpCodePairer::ConnectToDiscoveredDevice()
289 : {
290 0 : if (mWaitingForPASE)
291 : {
292 : // Nothing to do. Just wait until we either succeed or fail at that
293 : // PASE session establishment.
294 0 : return false;
295 : }
296 :
297 0 : while (!mDiscoveredParameters.empty())
298 : {
299 : // Grab the first element from the queue and try connecting to it.
300 : // Remove it from the queue before we try to connect, in case the
301 : // connection attempt fails and calls right back into us to try the next
302 : // thing.
303 0 : SetUpCodePairerParameters params(mDiscoveredParameters.front());
304 0 : mDiscoveredParameters.pop_front();
305 :
306 0 : params.SetSetupPINCode(mSetUpPINCode);
307 :
308 : #if CHIP_PROGRESS_LOGGING
309 : char buf[Transport::PeerAddress::kMaxToStringSize];
310 0 : params.GetPeerAddress().ToString(buf);
311 0 : ChipLogProgress(Controller, "Attempting PASE connection to %s", buf);
312 : #endif // CHIP_PROGRESS_LOGGING
313 :
314 : // Handle possibly-sync call backs from attempts to establish PASE.
315 0 : ExpectPASEEstablishment();
316 :
317 0 : if (params.GetPeerAddress().GetTransportType() == Transport::Type::kUdp)
318 : {
319 0 : mCurrentPASEParameters.SetValue(params);
320 : }
321 :
322 : CHIP_ERROR err;
323 0 : if (mConnectionType == SetupCodePairerBehaviour::kCommission)
324 : {
325 0 : err = mCommissioner->PairDevice(mRemoteId, params);
326 : }
327 : else
328 : {
329 0 : err = mCommissioner->EstablishPASEConnection(mRemoteId, params);
330 : }
331 :
332 0 : LogErrorOnFailure(err);
333 0 : if (err == CHIP_NO_ERROR)
334 : {
335 0 : return true;
336 : }
337 :
338 : // Failed to start establishing PASE. Move on to the next item.
339 0 : PASEEstablishmentComplete();
340 0 : }
341 :
342 0 : return false;
343 : }
344 :
345 : #if CONFIG_NETWORK_LAYER_BLE
346 0 : void SetUpCodePairer::OnDiscoveredDeviceOverBle(BLE_CONNECTION_OBJECT connObj)
347 : {
348 0 : ChipLogProgress(Controller, "Discovered device to be commissioned over BLE");
349 :
350 0 : mWaitingForDiscovery[kBLETransport] = false;
351 :
352 : // In order to not wait for all the possible addresses discovered over mdns to
353 : // be tried before trying to connect over BLE, the discovered connection object is
354 : // inserted at the beginning of the list.
355 : //
356 : // It makes it the 'next' thing to try to connect to if there are already some
357 : // discovered parameters in the list.
358 0 : mDiscoveredParameters.emplace_front(connObj);
359 0 : ConnectToDiscoveredDevice();
360 0 : }
361 :
362 0 : void SetUpCodePairer::OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj)
363 : {
364 0 : (static_cast<SetUpCodePairer *>(appState))->OnDiscoveredDeviceOverBle(connObj);
365 0 : }
366 :
367 0 : void SetUpCodePairer::OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err)
368 : {
369 0 : static_cast<SetUpCodePairer *>(appState)->OnBLEDiscoveryError(err);
370 0 : }
371 :
372 0 : void SetUpCodePairer::OnBLEDiscoveryError(CHIP_ERROR err)
373 : {
374 0 : ChipLogError(Controller, "Commissioning discovery over BLE failed: %" CHIP_ERROR_FORMAT, err.Format());
375 0 : mWaitingForDiscovery[kBLETransport] = false;
376 0 : LogErrorOnFailure(err);
377 0 : }
378 : #endif // CONFIG_NETWORK_LAYER_BLE
379 :
380 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
381 : void SetUpCodePairer::OnDiscoveredDeviceOverWifiPAF()
382 : {
383 : ChipLogProgress(Controller, "Discovered device to be commissioned over WiFiPAF, RemoteId: %lu", mRemoteId);
384 :
385 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
386 : auto param = SetUpCodePairerParameters();
387 : param.SetPeerAddress(Transport::PeerAddress(Transport::Type::kWiFiPAF, mRemoteId));
388 : mDiscoveredParameters.emplace_back(param);
389 : ConnectToDiscoveredDevice();
390 : }
391 :
392 : void SetUpCodePairer::OnWifiPAFDiscoveryError(CHIP_ERROR err)
393 : {
394 : ChipLogError(Controller, "Commissioning discovery over WiFiPAF failed: %" CHIP_ERROR_FORMAT, err.Format());
395 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
396 : }
397 :
398 : void SetUpCodePairer::OnWiFiPAFSubscribeComplete(void * appState)
399 : {
400 : auto self = (SetUpCodePairer *) appState;
401 : self->OnDiscoveredDeviceOverWifiPAF();
402 : }
403 :
404 : void SetUpCodePairer::OnWiFiPAFSubscribeError(void * appState, CHIP_ERROR err)
405 : {
406 : auto self = (SetUpCodePairer *) appState;
407 : self->OnWifiPAFDiscoveryError(err);
408 : }
409 : #endif
410 :
411 0 : bool SetUpCodePairer::IdIsPresent(uint16_t vendorOrProductID)
412 : {
413 0 : return vendorOrProductID != kNotAvailable;
414 : }
415 :
416 0 : bool SetUpCodePairer::NodeMatchesCurrentFilter(const Dnssd::DiscoveredNodeData & discNodeData) const
417 : {
418 0 : if (!discNodeData.Is<Dnssd::CommissionNodeData>())
419 : {
420 0 : return false;
421 : }
422 :
423 0 : const Dnssd::CommissionNodeData & nodeData = discNodeData.Get<Dnssd::CommissionNodeData>();
424 0 : if (nodeData.commissioningMode == 0)
425 : {
426 0 : ChipLogProgress(Controller, "Discovered device does not have an open commissioning window.");
427 0 : return false;
428 : }
429 :
430 : // The advertisement may not include a vendor id.
431 0 : if (IdIsPresent(mPayloadVendorID) && IdIsPresent(nodeData.vendorId) && mPayloadVendorID != nodeData.vendorId)
432 : {
433 0 : ChipLogProgress(Controller, "Discovered device does not match our vendor id.");
434 0 : return false;
435 : }
436 :
437 : // The advertisement may not include a product id.
438 0 : if (IdIsPresent(mPayloadProductID) && IdIsPresent(nodeData.productId) && mPayloadProductID != nodeData.productId)
439 : {
440 0 : ChipLogProgress(Controller, "Discovered device does not match our product id.");
441 0 : return false;
442 : }
443 :
444 0 : bool discriminatorMatches = false;
445 0 : switch (mCurrentFilter.type)
446 : {
447 0 : case Dnssd::DiscoveryFilterType::kShortDiscriminator:
448 0 : discriminatorMatches = (((nodeData.longDiscriminator >> 8) & 0x0F) == mCurrentFilter.code);
449 0 : break;
450 0 : case Dnssd::DiscoveryFilterType::kLongDiscriminator:
451 0 : discriminatorMatches = (nodeData.longDiscriminator == mCurrentFilter.code);
452 0 : break;
453 0 : case Dnssd::DiscoveryFilterType::kNone:
454 0 : ChipLogDetail(Controller, "Filter type none; all matches will fail");
455 0 : return false;
456 0 : default:
457 0 : ChipLogError(Controller, "Unknown filter type; all matches will fail");
458 0 : return false;
459 : }
460 0 : if (!discriminatorMatches)
461 : {
462 0 : ChipLogProgress(Controller, "Discovered device does not match our discriminator.");
463 : }
464 0 : return discriminatorMatches;
465 : }
466 :
467 0 : void SetUpCodePairer::NotifyCommissionableDeviceDiscovered(const Dnssd::DiscoveredNodeData & nodeData)
468 : {
469 0 : if (!NodeMatchesCurrentFilter(nodeData))
470 : {
471 0 : return;
472 : }
473 :
474 0 : ChipLogProgress(Controller, "Discovered device to be commissioned over DNS-SD");
475 :
476 0 : NotifyCommissionableDeviceDiscovered(nodeData.Get<Dnssd::CommissionNodeData>());
477 : }
478 :
479 0 : void SetUpCodePairer::NotifyCommissionableDeviceDiscovered(const Dnssd::CommonResolutionData & resolutionData)
480 : {
481 0 : if (mDiscoveryType == DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry)
482 : {
483 : // If the discovery type does not want the PASE auto retry mechanism, we will just store
484 : // a single IP. So the discovery process is stopped as it won't be of any help anymore.
485 0 : StopConnectOverIP();
486 0 : mDiscoveredParameters.emplace_back(resolutionData, 0);
487 : }
488 : else
489 : {
490 0 : for (size_t i = 0; i < resolutionData.numIPs; i++)
491 : {
492 0 : mDiscoveredParameters.emplace_back(resolutionData, i);
493 : }
494 : }
495 :
496 0 : ConnectToDiscoveredDevice();
497 0 : }
498 :
499 0 : bool SetUpCodePairer::StopPairing(NodeId remoteId)
500 : {
501 0 : VerifyOrReturnValue(mRemoteId != kUndefinedNodeId, false);
502 0 : VerifyOrReturnValue(remoteId == kUndefinedNodeId || remoteId == mRemoteId, false);
503 :
504 0 : if (mWaitingForPASE)
505 : {
506 0 : PASEEstablishmentComplete();
507 : }
508 :
509 0 : ResetDiscoveryState();
510 0 : mRemoteId = kUndefinedNodeId;
511 0 : return true;
512 : }
513 :
514 0 : bool SetUpCodePairer::TryNextRendezvousParameters()
515 : {
516 0 : if (ConnectToDiscoveredDevice())
517 : {
518 0 : ChipLogProgress(Controller, "Trying connection to commissionee over different transport");
519 0 : return true;
520 : }
521 :
522 0 : if (DiscoveryInProgress())
523 : {
524 0 : ChipLogProgress(Controller, "Waiting to discover commissionees that match our filters");
525 0 : return true;
526 : }
527 :
528 0 : return false;
529 : }
530 :
531 0 : bool SetUpCodePairer::DiscoveryInProgress() const
532 : {
533 0 : for (const auto & waiting : mWaitingForDiscovery)
534 : {
535 0 : if (waiting)
536 : {
537 0 : return true;
538 : }
539 : }
540 :
541 0 : return false;
542 : }
543 :
544 0 : void SetUpCodePairer::ResetDiscoveryState()
545 : {
546 0 : StopConnectOverBle();
547 0 : StopConnectOverIP();
548 0 : StopConnectOverSoftAP();
549 0 : StopConnectOverWiFiPAF();
550 :
551 : // Just in case any of those failed to reset the waiting state properly.
552 0 : for (auto & waiting : mWaitingForDiscovery)
553 : {
554 0 : waiting = false;
555 : }
556 :
557 0 : mDiscoveredParameters.clear();
558 0 : mCurrentPASEParameters.ClearValue();
559 0 : mLastPASEError = CHIP_NO_ERROR;
560 :
561 0 : mSystemLayer->CancelTimer(OnDeviceDiscoveredTimeoutCallback, this);
562 0 : }
563 :
564 0 : void SetUpCodePairer::ExpectPASEEstablishment()
565 : {
566 0 : VerifyOrDie(!mWaitingForPASE);
567 0 : mWaitingForPASE = true;
568 0 : auto * delegate = mCommissioner->GetPairingDelegate();
569 0 : VerifyOrDie(delegate != this);
570 0 : mPairingDelegate = delegate;
571 0 : mCommissioner->RegisterPairingDelegate(this);
572 0 : }
573 :
574 0 : void SetUpCodePairer::PASEEstablishmentComplete()
575 : {
576 0 : VerifyOrDie(mWaitingForPASE);
577 0 : mWaitingForPASE = false;
578 0 : mCommissioner->RegisterPairingDelegate(mPairingDelegate);
579 0 : mPairingDelegate = nullptr;
580 0 : }
581 :
582 0 : void SetUpCodePairer::OnStatusUpdate(DevicePairingDelegate::Status status)
583 : {
584 0 : if (status == DevicePairingDelegate::Status::SecurePairingFailed)
585 : {
586 : // If we're still waiting on discovery, don't propagate this failure
587 : // (which is due to PASE failure with something we discovered, but the
588 : // "something" may not have been the right thing) for now. Wait until
589 : // discovery completes. Then we will either succeed and notify
590 : // accordingly or time out and land in OnStatusUpdate again, but at that
591 : // point we will not be waiting on discovery anymore.
592 0 : if (!mDiscoveredParameters.empty())
593 : {
594 0 : ChipLogProgress(Controller, "Ignoring SecurePairingFailed status for now; we have more discovered devices to try");
595 0 : return;
596 : }
597 :
598 0 : if (DiscoveryInProgress())
599 : {
600 0 : ChipLogProgress(Controller,
601 : "Ignoring SecurePairingFailed status for now; we are waiting to see if we discover more devices");
602 0 : return;
603 : }
604 : }
605 :
606 0 : if (mPairingDelegate)
607 : {
608 0 : mPairingDelegate->OnStatusUpdate(status);
609 : }
610 : }
611 :
612 0 : void SetUpCodePairer::OnPairingComplete(CHIP_ERROR error)
613 : {
614 : // Save the pairing delegate so we can notify it. We want to notify it
615 : // _after_ we restore the state on the commissioner, in case the delegate
616 : // ends up immediately calling back into the commissioner again when
617 : // notified.
618 0 : auto * pairingDelegate = mPairingDelegate;
619 0 : PASEEstablishmentComplete();
620 :
621 0 : if (CHIP_NO_ERROR == error)
622 : {
623 0 : ChipLogProgress(Controller, "PASE session established with commissionee. Stopping discovery.");
624 0 : ResetDiscoveryState();
625 0 : mRemoteId = kUndefinedNodeId;
626 : MATTER_LOG_METRIC_END(kMetricSetupCodePairerPairDevice, error);
627 0 : if (pairingDelegate != nullptr)
628 : {
629 0 : pairingDelegate->OnPairingComplete(error);
630 : }
631 0 : return;
632 : }
633 :
634 : // It may happen that there is a stale DNS entry. If so, ReconfirmRecord will flush
635 : // the record from the daemon cache once it determines that it is invalid.
636 : // It may not help for this particular resolve, but may help subsequent resolves.
637 0 : if (CHIP_ERROR_TIMEOUT == error && mCurrentPASEParameters.HasValue())
638 : {
639 0 : const auto & params = mCurrentPASEParameters.Value();
640 0 : const auto & peer = params.GetPeerAddress();
641 0 : const auto & ip = peer.GetIPAddress();
642 0 : auto err = Dnssd::Resolver::Instance().ReconfirmRecord(params.mHostName, ip, params.mInterfaceId);
643 0 : if (CHIP_NO_ERROR != err && CHIP_ERROR_NOT_IMPLEMENTED != err)
644 : {
645 0 : ChipLogError(Controller, "Error when verifying the validity of an address: %" CHIP_ERROR_FORMAT, err.Format());
646 : }
647 : }
648 0 : mCurrentPASEParameters.ClearValue();
649 :
650 : // We failed to establish PASE. Try the next thing we have discovered, if
651 : // any.
652 0 : if (TryNextRendezvousParameters())
653 : {
654 : // Keep waiting until that finishes. Don't call OnPairingComplete yet.
655 0 : mLastPASEError = error;
656 0 : return;
657 : }
658 :
659 : MATTER_LOG_METRIC_END(kMetricSetupCodePairerPairDevice, error);
660 0 : if (pairingDelegate != nullptr)
661 : {
662 0 : pairingDelegate->OnPairingComplete(error);
663 : }
664 : }
665 :
666 0 : void SetUpCodePairer::OnPairingDeleted(CHIP_ERROR error)
667 : {
668 0 : if (mPairingDelegate)
669 : {
670 0 : mPairingDelegate->OnPairingDeleted(error);
671 : }
672 0 : }
673 :
674 0 : void SetUpCodePairer::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error)
675 : {
676 : // Not really expecting this, but handle it anyway.
677 0 : if (mPairingDelegate)
678 : {
679 0 : mPairingDelegate->OnCommissioningComplete(deviceId, error);
680 : }
681 0 : }
682 :
683 0 : void SetUpCodePairer::OnDeviceDiscoveredTimeoutCallback(System::Layer * layer, void * context)
684 : {
685 0 : ChipLogError(Controller, "Discovery timed out");
686 0 : auto * pairer = static_cast<SetUpCodePairer *>(context);
687 0 : LogErrorOnFailure(pairer->StopConnectOverBle());
688 0 : LogErrorOnFailure(pairer->StopConnectOverIP());
689 0 : LogErrorOnFailure(pairer->StopConnectOverSoftAP());
690 0 : if (!pairer->mWaitingForPASE && pairer->mDiscoveredParameters.empty())
691 : {
692 : // We're not waiting on any more PASE attempts, and we're not going to
693 : // discover anything at this point, so we should just notify our
694 : // listener.
695 0 : CHIP_ERROR err = pairer->mLastPASEError;
696 0 : if (err == CHIP_NO_ERROR)
697 : {
698 0 : err = CHIP_ERROR_TIMEOUT;
699 : }
700 : MATTER_LOG_METRIC_END(kMetricSetupCodePairerPairDevice, err);
701 0 : pairer->mCommissioner->OnSessionEstablishmentError(err);
702 : }
703 0 : }
704 :
705 0 : SetUpCodePairerParameters::SetUpCodePairerParameters(const Dnssd::CommonResolutionData & data, size_t index)
706 : {
707 0 : mInterfaceId = data.interfaceId;
708 0 : Platform::CopyString(mHostName, data.hostName);
709 :
710 0 : auto & ip = data.ipAddress[index];
711 0 : SetPeerAddress(Transport::PeerAddress::UDP(ip, data.port, ip.IsIPv6LinkLocal() ? data.interfaceId : Inet::InterfaceId::Null()));
712 :
713 0 : if (data.mrpRetryIntervalIdle.has_value())
714 : {
715 0 : SetIdleInterval(*data.mrpRetryIntervalIdle);
716 : }
717 :
718 0 : if (data.mrpRetryIntervalActive.has_value())
719 : {
720 0 : SetActiveInterval(*data.mrpRetryIntervalActive);
721 : }
722 0 : }
723 :
724 : #if CONFIG_NETWORK_LAYER_BLE
725 0 : SetUpCodePairerParameters::SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj, bool connected)
726 : {
727 0 : Transport::PeerAddress peerAddress = Transport::PeerAddress::BLE();
728 0 : SetPeerAddress(peerAddress);
729 0 : if (connected)
730 : {
731 0 : SetConnectionObject(connObj);
732 : }
733 : else
734 : {
735 0 : SetDiscoveredObject(connObj);
736 : }
737 0 : }
738 : #endif // CONFIG_NETWORK_LAYER_BLE
739 :
740 : } // namespace Controller
741 : } // namespace chip
|