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