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 <platform/internal/NFCCommissioningManager.h>
34 : #include <system/SystemClock.h>
35 : #include <tracing/metric_event.h>
36 : #include <vector>
37 :
38 : constexpr uint32_t kDeviceDiscoveredTimeout = CHIP_CONFIG_SETUP_CODE_PAIRER_DISCOVERY_TIMEOUT_SECS * chip::kMillisecondsPerSecond;
39 :
40 : using namespace chip::Tracing;
41 :
42 : namespace chip {
43 : namespace Controller {
44 :
45 0 : CHIP_ERROR SetUpCodePairer::PairDevice(NodeId remoteId, const char * setUpCode, SetupCodePairerBehaviour commission,
46 : DiscoveryType discoveryType, Optional<Dnssd::CommonResolutionData> resolutionData)
47 : {
48 0 : VerifyOrReturnErrorWithMetric(kMetricSetupCodePairerPairDevice, mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);
49 0 : VerifyOrReturnErrorWithMetric(kMetricSetupCodePairerPairDevice, remoteId != kUndefinedNodeId, CHIP_ERROR_INVALID_ARGUMENT);
50 :
51 0 : std::vector<SetupPayload> payloads;
52 0 : ReturnErrorOnFailure(SetupPayload::FromStringRepresentation(setUpCode, payloads));
53 :
54 : // If the caller has provided a specific single resolution data, and we were
55 : // only looking for one commissionee, and the caller says that the provided
56 : // data matches that one commissionee, just go ahead and use the provided data.
57 : //
58 : // If we were looking for more than one device (i.e. if either of the
59 : // payload arrays involved does not have length 1), we can't make use of the
60 : // incoming resolution data, since it does not contain the long
61 : // discriminator of the thing that was discovered, and therefore we can't
62 : // tell which setup passcode to use for it.
63 0 : if (resolutionData.HasValue() && payloads.size() == 1 && mSetupPayloads.size() == 1)
64 : {
65 0 : VerifyOrReturnErrorWithMetric(kMetricSetupCodePairerPairDevice, discoveryType != DiscoveryType::kAll,
66 : CHIP_ERROR_INVALID_ARGUMENT);
67 0 : if (mRemoteId == remoteId && mSetupPayloads[0].setUpPINCode == payloads[0].setUpPINCode && mConnectionType == commission &&
68 0 : mDiscoveryType == discoveryType)
69 : {
70 : // Not passing a discriminator is ok, since we have only one payload.
71 0 : NotifyCommissionableDeviceDiscovered(resolutionData.Value(), /* matchedLongDiscriminator = */ std::nullopt);
72 0 : return CHIP_NO_ERROR;
73 : }
74 : }
75 :
76 0 : ResetDiscoveryState();
77 :
78 0 : mConnectionType = commission;
79 0 : mDiscoveryType = discoveryType;
80 0 : mRemoteId = remoteId;
81 0 : mSetupPayloads = std::move(payloads);
82 :
83 0 : if (resolutionData.HasValue() && mSetupPayloads.size() == 1)
84 : {
85 : // No need to pass in a discriminator if we have only one payload, which
86 : // is good because we don't have a full discriminator here anyway.
87 0 : NotifyCommissionableDeviceDiscovered(resolutionData.Value(), /* matchedLongDiscriminator = */ std::nullopt);
88 0 : return CHIP_NO_ERROR;
89 : }
90 :
91 0 : ReturnErrorOnFailureWithMetric(kMetricSetupCodePairerPairDevice, Connect());
92 : auto errorCode =
93 0 : mSystemLayer->StartTimer(System::Clock::Milliseconds32(kDeviceDiscoveredTimeout), OnDeviceDiscoveredTimeoutCallback, this);
94 0 : if (CHIP_NO_ERROR == errorCode)
95 : {
96 : MATTER_LOG_METRIC_BEGIN(kMetricSetupCodePairerPairDevice);
97 : }
98 0 : return errorCode;
99 0 : }
100 :
101 0 : CHIP_ERROR SetUpCodePairer::Connect()
102 : {
103 0 : if (mDiscoveryType == DiscoveryType::kAll)
104 : {
105 0 : if (ShouldDiscoverUsing(RendezvousInformationFlag::kBLE))
106 : {
107 0 : CHIP_ERROR err = StartDiscoveryOverBLE();
108 0 : if ((CHIP_ERROR_NOT_IMPLEMENTED == err) || (CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE == err))
109 : {
110 0 : ChipLogProgress(Controller,
111 : "Skipping commissionable node discovery over BLE since not supported by the controller!");
112 : }
113 0 : else if (err != CHIP_NO_ERROR)
114 : {
115 0 : ChipLogError(Controller, "Failed to start commissionable node discovery over BLE: %" CHIP_ERROR_FORMAT,
116 : err.Format());
117 : }
118 : }
119 0 : if (ShouldDiscoverUsing(RendezvousInformationFlag::kWiFiPAF))
120 : {
121 0 : CHIP_ERROR err = StartDiscoveryOverWiFiPAF();
122 0 : if ((CHIP_ERROR_NOT_IMPLEMENTED == err) || (CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE == err))
123 : {
124 0 : ChipLogProgress(Controller,
125 : "Skipping commissionable node discovery over Wi-Fi PAF since not supported by the controller!");
126 : }
127 0 : else if (err != CHIP_NO_ERROR)
128 : {
129 0 : ChipLogError(Controller, "Failed to start commissionable node discovery over Wi-Fi PAF: %" CHIP_ERROR_FORMAT,
130 : err.Format());
131 : }
132 : }
133 0 : if (ShouldDiscoverUsing(RendezvousInformationFlag::kNFC))
134 : {
135 0 : CHIP_ERROR err = StartDiscoveryOverNFC();
136 0 : if ((CHIP_ERROR_NOT_IMPLEMENTED == err) || (CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE == err))
137 : {
138 0 : ChipLogProgress(Controller,
139 : "Skipping commissionable node discovery over NFC since not supported by the controller!");
140 : }
141 0 : else if (err != CHIP_NO_ERROR)
142 : {
143 0 : ChipLogError(Controller, "Failed to start commissionable node discovery over NFC: %" CHIP_ERROR_FORMAT,
144 : err.Format());
145 : }
146 : }
147 : }
148 :
149 : // We always want to search on network because any node that has already been commissioned will use on-network regardless of the
150 : // QR code flag.
151 0 : CHIP_ERROR err = StartDiscoveryOverDNSSD();
152 0 : if (err != CHIP_NO_ERROR)
153 : {
154 0 : ChipLogError(Controller, "Failed to start commissionable node discovery over DNS-SD: %" CHIP_ERROR_FORMAT, err.Format());
155 : }
156 0 : return err;
157 : }
158 :
159 0 : CHIP_ERROR SetUpCodePairer::StartDiscoveryOverBLE()
160 : {
161 : #if CONFIG_NETWORK_LAYER_BLE
162 : #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
163 : VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
164 : mCommissioner->ConnectBleTransportToSelf();
165 : #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
166 0 : VerifyOrReturnError(mBleLayer != nullptr, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
167 :
168 0 : ChipLogProgress(Controller, "Starting commissionable node discovery over BLE");
169 :
170 : // Handle possibly-sync callbacks.
171 0 : mWaitingForDiscovery[kBLETransport] = true;
172 : CHIP_ERROR err;
173 : // Not all BLE backends support the new NewBleConnectionByDiscriminators
174 : // API, so use the old one when we can (i.e. when we only have one setup
175 : // payload), to avoid breaking existing API consumers.
176 0 : if (mSetupPayloads.size() == 1)
177 : {
178 0 : err = mBleLayer->NewBleConnectionByDiscriminator(mSetupPayloads[0].discriminator, this, OnDiscoveredDeviceOverBleSuccess,
179 : OnDiscoveredDeviceOverBleError);
180 : }
181 : else
182 : {
183 0 : std::vector<SetupDiscriminator> discriminators;
184 0 : discriminators.reserve(mSetupPayloads.size());
185 0 : for (auto & payload : mSetupPayloads)
186 : {
187 0 : discriminators.emplace_back(payload.discriminator);
188 : }
189 0 : err = mBleLayer->NewBleConnectionByDiscriminators(Span(discriminators.data(), discriminators.size()), this,
190 : OnDiscoveredDeviceWithDiscriminatorOverBleSuccess,
191 : OnDiscoveredDeviceOverBleError);
192 0 : }
193 0 : if (err != CHIP_NO_ERROR)
194 : {
195 0 : mWaitingForDiscovery[kBLETransport] = false;
196 : }
197 0 : return err;
198 : #else
199 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
200 : #endif // CONFIG_NETWORK_LAYER_BLE
201 : }
202 :
203 0 : CHIP_ERROR SetUpCodePairer::StopDiscoveryOverBLE()
204 : {
205 : // Make sure to not call CancelBleIncompleteConnection unless we are in fact
206 : // waiting on BLE discovery. It will cancel connections that are in fact
207 : // completed. In particular, if we just established PASE over BLE calling
208 : // CancelBleIncompleteConnection here unconditionally would cancel the BLE
209 : // connection underlying the PASE session. So make sure to only call
210 : // CancelBleIncompleteConnection if we're still waiting to hear back on the
211 : // BLE discovery bits.
212 0 : if (!mWaitingForDiscovery[kBLETransport])
213 : {
214 0 : return CHIP_NO_ERROR;
215 : }
216 :
217 0 : mWaitingForDiscovery[kBLETransport] = false;
218 : #if CONFIG_NETWORK_LAYER_BLE
219 0 : VerifyOrReturnError(mBleLayer != nullptr, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
220 0 : ChipLogProgress(Controller, "Stopping commissionable node discovery over BLE");
221 0 : return mBleLayer->CancelBleIncompleteConnection();
222 : #else
223 : return CHIP_NO_ERROR;
224 : #endif // CONFIG_NETWORK_LAYER_BLE
225 : }
226 :
227 0 : CHIP_ERROR SetUpCodePairer::StartDiscoveryOverDNSSD()
228 : {
229 0 : ChipLogProgress(Controller, "Starting commissionable node discovery over DNS-SD");
230 :
231 0 : Dnssd::DiscoveryFilter filter(Dnssd::DiscoveryFilterType::kNone);
232 0 : if (mSetupPayloads.size() == 1)
233 : {
234 0 : auto & discriminator = mSetupPayloads[0].discriminator;
235 0 : if (discriminator.IsShortDiscriminator())
236 : {
237 0 : filter.type = Dnssd::DiscoveryFilterType::kShortDiscriminator;
238 0 : filter.code = discriminator.GetShortValue();
239 : }
240 : else
241 : {
242 0 : filter.type = Dnssd::DiscoveryFilterType::kLongDiscriminator;
243 0 : filter.code = discriminator.GetLongValue();
244 : }
245 : }
246 :
247 : // In theory we could try to filter on the vendor ID if it's the same across all the setup
248 : // payloads, but DNS-SD advertisements are not required to include the Vendor ID subtype, so in
249 : // practice that's not doable.
250 :
251 : // Handle possibly-sync callbacks.
252 0 : mWaitingForDiscovery[kIPTransport] = true;
253 0 : CHIP_ERROR err = mCommissioner->DiscoverCommissionableNodes(filter);
254 0 : if (err != CHIP_NO_ERROR)
255 : {
256 0 : mWaitingForDiscovery[kIPTransport] = false;
257 : }
258 0 : return err;
259 : }
260 :
261 0 : CHIP_ERROR SetUpCodePairer::StopDiscoveryOverDNSSD()
262 : {
263 0 : ChipLogProgress(Controller, "Stopping commissionable node discovery over DNS-SD");
264 :
265 0 : mWaitingForDiscovery[kIPTransport] = false;
266 :
267 0 : mCommissioner->StopCommissionableDiscovery();
268 0 : return CHIP_NO_ERROR;
269 : }
270 :
271 0 : CHIP_ERROR SetUpCodePairer::StartDiscoveryOverWiFiPAF()
272 : {
273 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
274 0 : if (mSetupPayloads.size() != 1)
275 : {
276 0 : ChipLogError(Controller, "Wi-Fi PAF commissioning does not support concatenated QR codes yet.");
277 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
278 : }
279 :
280 0 : auto & payload = mSetupPayloads[0];
281 :
282 0 : ChipLogProgress(Controller, "Starting commissionable node discovery over Wi-Fi PAF");
283 0 : VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
284 :
285 0 : const SetupDiscriminator connDiscriminator(payload.discriminator);
286 0 : VerifyOrReturnValue(!connDiscriminator.IsShortDiscriminator(), CHIP_ERROR_INVALID_ARGUMENT,
287 : ChipLogError(Controller, "Error, Long discriminator is required"));
288 0 : uint16_t discriminator = connDiscriminator.GetLongValue();
289 0 : WiFiPAF::WiFiPAFSession sessionInfo = { .role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber,
290 0 : .nodeId = mRemoteId,
291 0 : .discriminator = discriminator };
292 0 : ReturnErrorOnFailure(
293 : DeviceLayer::ConnectivityMgr().GetWiFiPAF()->AddPafSession(WiFiPAF::PafInfoAccess::kAccNodeInfo, sessionInfo));
294 :
295 0 : mWaitingForDiscovery[kWiFiPAFTransport] = true;
296 0 : CHIP_ERROR err = DeviceLayer::ConnectivityMgr().WiFiPAFSubscribe(discriminator, (void *) this, OnWiFiPAFSubscribeComplete,
297 : OnWiFiPAFSubscribeError);
298 0 : if (err != CHIP_NO_ERROR)
299 : {
300 0 : ChipLogError(Controller, "Commissionable node discovery over Wi-Fi PAF failed, err = %" CHIP_ERROR_FORMAT, err.Format());
301 0 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
302 : }
303 0 : return err;
304 : #else
305 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
306 : #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
307 : }
308 :
309 0 : CHIP_ERROR SetUpCodePairer::StopDiscoveryOverWiFiPAF()
310 : {
311 0 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
312 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
313 0 : DeviceLayer::ConnectivityMgr().WiFiPAFCancelIncompleteSubscribe();
314 : #endif
315 0 : return CHIP_NO_ERROR;
316 : }
317 :
318 0 : CHIP_ERROR SetUpCodePairer::StartDiscoveryOverNFC()
319 : {
320 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
321 : if (mSetupPayloads.size() != 1)
322 : {
323 : ChipLogError(Controller, "NFC commissioning does not support concatenated QR codes yet.");
324 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
325 : }
326 :
327 : auto & payload = mSetupPayloads[0];
328 :
329 : ChipLogProgress(Controller, "Starting commissionable node discovery over NFC");
330 : VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
331 :
332 : const SetupDiscriminator connDiscriminator(payload.discriminator);
333 : VerifyOrReturnValue(!connDiscriminator.IsShortDiscriminator(), CHIP_ERROR_INVALID_ARGUMENT,
334 : ChipLogError(Controller, "Error, Long discriminator is required"));
335 : chip::Nfc::NFCTag::Identifier identifier = { .discriminator = payload.discriminator.GetLongValue() };
336 : Nfc::NFCReaderTransport * readerTransport = DeviceLayer::Internal::NFCCommissioningMgr().GetNFCReaderTransport();
337 : if (!readerTransport)
338 : {
339 : ChipLogError(Controller, "Commissionable node discovery over NFC since there is no valid NFC reader transport");
340 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
341 : }
342 :
343 : readerTransport->SetDelegate(this);
344 : CHIP_ERROR err = readerTransport->StartDiscoveringTagMatchingAddress(identifier);
345 : if (err != CHIP_NO_ERROR)
346 : {
347 : ChipLogError(Controller, "Commissionable node discovery over NFC failed, err = %" CHIP_ERROR_FORMAT, err.Format());
348 : }
349 : else
350 : {
351 : mWaitingForDiscovery[kNFCTransport] = true;
352 : }
353 : return err;
354 : #else
355 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
356 : #endif // CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
357 : }
358 :
359 0 : CHIP_ERROR SetUpCodePairer::StopDiscoveryOverNFC()
360 : {
361 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
362 : mWaitingForDiscovery[kNFCTransport] = false;
363 :
364 : Nfc::NFCReaderTransport * readerTransport = DeviceLayer::Internal::NFCCommissioningMgr().GetNFCReaderTransport();
365 : if (!readerTransport)
366 : {
367 : ChipLogError(Controller,
368 : "Failed to stop commissionable node discovery over NFC since there is no valid NFC reader transport");
369 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
370 : }
371 :
372 : ChipLogProgress(Controller, "Stopping commissionable node discovery over NFC by removing delegate");
373 : readerTransport->SetDelegate(nullptr);
374 : #endif
375 0 : return CHIP_NO_ERROR;
376 : }
377 :
378 0 : bool SetUpCodePairer::ConnectToDiscoveredDevice()
379 : {
380 0 : if (mWaitingForPASE)
381 : {
382 : // Nothing to do. Just wait until we either succeed or fail at that
383 : // PASE session establishment.
384 0 : return false;
385 : }
386 :
387 0 : while (!mDiscoveredParameters.empty())
388 : {
389 0 : mCurrentPASEPayload.reset();
390 :
391 : // Grab the first element from the queue and try connecting to it.
392 : // Remove it from the queue before we try to connect, in case the
393 : // connection attempt fails and calls right back into us to try the next
394 : // thing.
395 0 : SetUpCodePairerParameters params(mDiscoveredParameters.front());
396 0 : mDiscoveredParameters.pop_front();
397 :
398 0 : if (params.mLongDiscriminator)
399 : {
400 0 : auto longDiscriminator = *params.mLongDiscriminator;
401 : // Look for a matching setup passcode.
402 0 : for (auto & payload : mSetupPayloads)
403 : {
404 0 : if (payload.discriminator.MatchesLongDiscriminator(longDiscriminator))
405 : {
406 0 : params.SetSetupPINCode(payload.setUpPINCode);
407 0 : params.SetSetupDiscriminator(payload.discriminator);
408 0 : mCurrentPASEPayload = payload;
409 0 : break;
410 : }
411 : }
412 0 : if (!mCurrentPASEPayload)
413 : {
414 0 : ChipLogError(Controller, "SetUpCodePairer: Discovered discriminator %u does not match any of our setup payloads",
415 : longDiscriminator);
416 : // Move on to the the next discovered params; nothing we can do here.
417 0 : continue;
418 : }
419 : }
420 : else
421 : {
422 : // No discriminator known for this discovered device. This can work if we have only one
423 : // setup payload, but otherwise we have no idea what setup passcode to use for it.
424 0 : if (mSetupPayloads.size() == 1)
425 : {
426 0 : params.SetSetupPINCode(mSetupPayloads[0].setUpPINCode);
427 0 : params.SetSetupDiscriminator(mSetupPayloads[0].discriminator);
428 0 : mCurrentPASEPayload = mSetupPayloads[0];
429 : }
430 : else
431 : {
432 0 : ChipLogError(Controller,
433 : "SetUpCodePairer: Unable to handle discovered parameters with no discriminator, because it has %u "
434 : "possible payloads",
435 : static_cast<unsigned>(mSetupPayloads.size()));
436 0 : continue;
437 : }
438 : }
439 :
440 : #if CHIP_PROGRESS_LOGGING
441 : char buf[Transport::PeerAddress::kMaxToStringSize];
442 0 : params.GetPeerAddress().ToString(buf);
443 0 : ChipLogProgress(Controller, "Attempting PASE connection to %s", buf);
444 : #endif // CHIP_PROGRESS_LOGGING
445 :
446 : // Handle possibly-sync call backs from attempts to establish PASE.
447 0 : ExpectPASEEstablishment();
448 :
449 0 : if (params.GetPeerAddress().GetTransportType() == Transport::Type::kUdp)
450 : {
451 0 : mCurrentPASEParameters.SetValue(params);
452 : }
453 :
454 : CHIP_ERROR err;
455 0 : if (mConnectionType == SetupCodePairerBehaviour::kCommission)
456 : {
457 0 : err = mCommissioner->PairDevice(mRemoteId, params);
458 : }
459 : else
460 : {
461 0 : err = mCommissioner->EstablishPASEConnection(mRemoteId, params);
462 : }
463 :
464 0 : LogErrorOnFailure(err);
465 0 : if (err == CHIP_NO_ERROR)
466 : {
467 0 : return true;
468 : }
469 :
470 : // Failed to start establishing PASE. Move on to the next item.
471 0 : mCurrentPASEPayload.reset();
472 0 : PASEEstablishmentComplete();
473 : }
474 :
475 0 : return false;
476 : }
477 :
478 : #if CONFIG_NETWORK_LAYER_BLE
479 0 : void SetUpCodePairer::OnDiscoveredDeviceOverBle(BLE_CONNECTION_OBJECT connObj, std::optional<uint16_t> matchedLongDiscriminator)
480 : {
481 0 : ChipLogProgress(Controller, "Discovered device to be commissioned over BLE");
482 :
483 0 : mWaitingForDiscovery[kBLETransport] = false;
484 :
485 : // In order to not wait for all the possible addresses discovered over mdns to
486 : // be tried before trying to connect over BLE, the discovered connection object is
487 : // inserted at the beginning of the list.
488 : //
489 : // It makes it the 'next' thing to try to connect to if there are already some
490 : // discovered parameters in the list.
491 : //
492 : // TODO: Consider implementing the SHOULD the spec has about commissioning things
493 : // in QR code order by waiting for a second or something before actually starting
494 : // the first PASE session when we have multiple setup payloads, and sorting the
495 : // results in setup payload order. If we do this, we might want to restrict it to
496 : // cases when the different payloads have different vendor/product IDs, since if
497 : // they are all the same product presumably ordering really does not matter.
498 0 : mDiscoveredParameters.emplace_front(connObj, matchedLongDiscriminator);
499 0 : ConnectToDiscoveredDevice();
500 0 : }
501 :
502 0 : void SetUpCodePairer::OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj)
503 : {
504 0 : (static_cast<SetUpCodePairer *>(appState))->OnDiscoveredDeviceOverBle(connObj, std::nullopt);
505 0 : }
506 :
507 0 : void SetUpCodePairer::OnDiscoveredDeviceWithDiscriminatorOverBleSuccess(void * appState, uint16_t matchedLongDiscriminator,
508 : BLE_CONNECTION_OBJECT connObj)
509 : {
510 0 : (static_cast<SetUpCodePairer *>(appState))->OnDiscoveredDeviceOverBle(connObj, std::make_optional(matchedLongDiscriminator));
511 0 : }
512 :
513 0 : void SetUpCodePairer::OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err)
514 : {
515 0 : static_cast<SetUpCodePairer *>(appState)->OnBLEDiscoveryError(err);
516 0 : }
517 :
518 0 : void SetUpCodePairer::OnBLEDiscoveryError(CHIP_ERROR err)
519 : {
520 0 : ChipLogError(Controller, "Commissionable node discovery over BLE failed: %" CHIP_ERROR_FORMAT, err.Format());
521 0 : mWaitingForDiscovery[kBLETransport] = false;
522 0 : LogErrorOnFailure(err);
523 0 : }
524 : #endif // CONFIG_NETWORK_LAYER_BLE
525 :
526 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
527 0 : void SetUpCodePairer::OnDiscoveredDeviceOverWifiPAF()
528 : {
529 0 : ChipLogProgress(Controller, "Discovered device to be commissioned over Wi-Fi PAF, RemoteId: %lu", mRemoteId);
530 :
531 0 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
532 0 : auto param = SetUpCodePairerParameters();
533 0 : param.SetPeerAddress(Transport::PeerAddress(Transport::Type::kWiFiPAF, mRemoteId));
534 : // TODO: This needs to support concatenated QR codes and set the relevant
535 : // long discriminator on param.
536 : //
537 : // See https://github.com/project-chip/connectedhomeip/issues/39134
538 0 : mDiscoveredParameters.emplace_back(param);
539 0 : ConnectToDiscoveredDevice();
540 0 : }
541 :
542 0 : void SetUpCodePairer::OnWifiPAFDiscoveryError(CHIP_ERROR err)
543 : {
544 0 : ChipLogError(Controller, "Commissionable node discovery over Wi-Fi PAF failed: %" CHIP_ERROR_FORMAT, err.Format());
545 0 : mWaitingForDiscovery[kWiFiPAFTransport] = false;
546 0 : }
547 :
548 0 : void SetUpCodePairer::OnWiFiPAFSubscribeComplete(void * appState)
549 : {
550 0 : auto self = reinterpret_cast<SetUpCodePairer *>(appState);
551 0 : self->OnDiscoveredDeviceOverWifiPAF();
552 0 : }
553 :
554 0 : void SetUpCodePairer::OnWiFiPAFSubscribeError(void * appState, CHIP_ERROR err)
555 : {
556 0 : auto self = reinterpret_cast<SetUpCodePairer *>(appState);
557 0 : self->OnWifiPAFDiscoveryError(err);
558 0 : }
559 : #endif
560 :
561 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
562 : void SetUpCodePairer::OnTagDiscovered(const chip::Nfc::NFCTag::Identifier & identifier)
563 : {
564 : ChipLogProgress(Controller, "Discovered device to be commissioned over NFC, Identifier: %u", identifier.discriminator);
565 :
566 : mWaitingForDiscovery[kNFCTransport] = false;
567 : auto param = SetUpCodePairerParameters();
568 : param.SetPeerAddress(Transport::PeerAddress(Transport::PeerAddress::NFC(identifier.discriminator)));
569 : // TODO: This needs to support concatenated QR codes and set the relevant
570 : // long discriminator on param.
571 : //
572 : // See https://github.com/project-chip/connectedhomeip/issues/39134
573 : mDiscoveredParameters.emplace_back(param);
574 : ConnectToDiscoveredDevice();
575 : }
576 :
577 : void SetUpCodePairer::OnTagDiscoveryFailed(CHIP_ERROR error)
578 : {
579 : ChipLogError(Controller, "Commissionable node discovery over NFC failed: %" CHIP_ERROR_FORMAT, error.Format());
580 : mWaitingForDiscovery[kNFCTransport] = false;
581 : }
582 : #endif
583 :
584 0 : bool SetUpCodePairer::IdIsPresent(uint16_t vendorOrProductID)
585 : {
586 0 : return vendorOrProductID != kNotAvailable;
587 : }
588 :
589 0 : bool SetUpCodePairer::NodeMatchesCurrentFilter(const Dnssd::DiscoveredNodeData & discNodeData) const
590 : {
591 0 : if (!discNodeData.Is<Dnssd::CommissionNodeData>())
592 : {
593 0 : return false;
594 : }
595 :
596 0 : const Dnssd::CommissionNodeData & nodeData = discNodeData.Get<Dnssd::CommissionNodeData>();
597 :
598 0 : VerifyOrReturnError(mCommissioner != nullptr, false);
599 0 : VerifyOrReturnError(mCommissioner->HasValidCommissioningMode(nodeData), false);
600 :
601 : // Check whether this matches one of our setup payloads.
602 0 : for (auto & payload : mSetupPayloads)
603 : {
604 : // The advertisement may not include a vendor id, and the payload may not have one either.
605 0 : if (IdIsPresent(payload.vendorID) && IdIsPresent(nodeData.vendorId) && payload.vendorID != nodeData.vendorId)
606 : {
607 0 : ChipLogProgress(Controller, "Discovered device vendor ID (%u) does not match our vendor ID (%u).", nodeData.vendorId,
608 : payload.vendorID);
609 0 : continue;
610 : }
611 :
612 : // The advertisement may not include a product id, and the payload may not have one either.
613 0 : if (IdIsPresent(payload.productID) && IdIsPresent(nodeData.productId) && payload.productID != nodeData.productId)
614 : {
615 0 : ChipLogProgress(Controller, "Discovered device product ID (%u) does not match our product ID (%u).", nodeData.productId,
616 : payload.productID);
617 0 : continue;
618 : }
619 :
620 0 : if (!payload.discriminator.MatchesLongDiscriminator(nodeData.longDiscriminator))
621 : {
622 0 : ChipLogProgress(Controller, "Discovered device discriminator (%u) does not match our discriminator.",
623 : nodeData.longDiscriminator);
624 0 : continue;
625 : }
626 :
627 0 : ChipLogProgress(Controller, "Discovered device with discriminator %u matches one of our setup payloads",
628 : nodeData.longDiscriminator);
629 0 : return true;
630 : }
631 :
632 0 : return false;
633 : }
634 :
635 0 : void SetUpCodePairer::NotifyCommissionableDeviceDiscovered(const Dnssd::DiscoveredNodeData & nodeData)
636 : {
637 0 : if (!NodeMatchesCurrentFilter(nodeData))
638 : {
639 0 : return;
640 : }
641 :
642 0 : ChipLogProgress(Controller, "Discovered device to be commissioned over DNS-SD");
643 :
644 0 : auto & commissionableNodeData = nodeData.Get<Dnssd::CommissionNodeData>();
645 :
646 0 : NotifyCommissionableDeviceDiscovered(commissionableNodeData, std::make_optional(commissionableNodeData.longDiscriminator));
647 : }
648 :
649 0 : void SetUpCodePairer::NotifyCommissionableDeviceDiscovered(const Dnssd::CommonResolutionData & resolutionData,
650 : std::optional<uint16_t> matchedLongDiscriminator)
651 : {
652 0 : if (mDiscoveryType == DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry)
653 : {
654 : // If the discovery type does not want the PASE auto retry mechanism, we will just store
655 : // a single IP. So the discovery process is stopped as it won't be of any help anymore.
656 0 : StopDiscoveryOverDNSSD();
657 0 : mDiscoveredParameters.emplace_back(resolutionData, matchedLongDiscriminator, 0);
658 : }
659 : else
660 : {
661 0 : for (size_t i = 0; i < resolutionData.numIPs; i++)
662 : {
663 0 : mDiscoveredParameters.emplace_back(resolutionData, matchedLongDiscriminator, i);
664 : }
665 : }
666 :
667 0 : ConnectToDiscoveredDevice();
668 0 : }
669 :
670 0 : bool SetUpCodePairer::StopPairing(NodeId remoteId)
671 : {
672 0 : VerifyOrReturnValue(mRemoteId != kUndefinedNodeId, false);
673 0 : VerifyOrReturnValue(remoteId == kUndefinedNodeId || remoteId == mRemoteId, false);
674 :
675 0 : if (mWaitingForPASE)
676 : {
677 0 : PASEEstablishmentComplete();
678 : }
679 :
680 0 : ResetDiscoveryState();
681 0 : mRemoteId = kUndefinedNodeId;
682 0 : return true;
683 : }
684 :
685 0 : bool SetUpCodePairer::TryNextRendezvousParameters()
686 : {
687 0 : if (ConnectToDiscoveredDevice())
688 : {
689 0 : ChipLogProgress(Controller, "Trying connection to commissionee over different transport");
690 0 : return true;
691 : }
692 :
693 0 : if (DiscoveryInProgress())
694 : {
695 0 : ChipLogProgress(Controller, "Waiting to discover commissionees that match our filters");
696 0 : return true;
697 : }
698 :
699 0 : return false;
700 : }
701 :
702 0 : bool SetUpCodePairer::DiscoveryInProgress() const
703 : {
704 0 : for (const auto & waiting : mWaitingForDiscovery)
705 : {
706 0 : if (waiting)
707 : {
708 0 : return true;
709 : }
710 : }
711 :
712 0 : return false;
713 : }
714 :
715 0 : void SetUpCodePairer::StopAllDiscoveryAttempts()
716 : {
717 0 : LogErrorOnFailure(StopDiscoveryOverBLE());
718 0 : LogErrorOnFailure(StopDiscoveryOverDNSSD());
719 0 : LogErrorOnFailure(StopDiscoveryOverWiFiPAF());
720 0 : LogErrorOnFailure(StopDiscoveryOverNFC());
721 :
722 : // Just in case any of those failed to reset the waiting state properly.
723 0 : for (auto & waiting : mWaitingForDiscovery)
724 : {
725 0 : waiting = false;
726 : }
727 0 : }
728 :
729 0 : void SetUpCodePairer::ResetDiscoveryState()
730 : {
731 0 : StopAllDiscoveryAttempts();
732 :
733 0 : mDiscoveredParameters.clear();
734 0 : mCurrentPASEParameters.ClearValue();
735 0 : mLastPASEError = CHIP_NO_ERROR;
736 :
737 0 : mSetupPayloads.clear();
738 :
739 0 : mSystemLayer->CancelTimer(OnDeviceDiscoveredTimeoutCallback, this);
740 0 : }
741 :
742 0 : void SetUpCodePairer::ExpectPASEEstablishment()
743 : {
744 0 : VerifyOrDie(!mWaitingForPASE);
745 0 : mWaitingForPASE = true;
746 0 : auto * delegate = mCommissioner->GetPairingDelegate();
747 0 : VerifyOrDie(delegate != this);
748 0 : mPairingDelegate = delegate;
749 0 : mCommissioner->RegisterPairingDelegate(this);
750 0 : }
751 :
752 0 : void SetUpCodePairer::PASEEstablishmentComplete()
753 : {
754 0 : VerifyOrDie(mWaitingForPASE);
755 0 : mWaitingForPASE = false;
756 0 : mCommissioner->RegisterPairingDelegate(mPairingDelegate);
757 0 : mPairingDelegate = nullptr;
758 0 : }
759 :
760 0 : void SetUpCodePairer::OnStatusUpdate(DevicePairingDelegate::Status status)
761 : {
762 0 : if (status == DevicePairingDelegate::Status::SecurePairingFailed)
763 : {
764 : // If we're still waiting on discovery, don't propagate this failure
765 : // (which is due to PASE failure with something we discovered, but the
766 : // "something" may not have been the right thing) for now. Wait until
767 : // discovery completes. Then we will either succeed and notify
768 : // accordingly or time out and land in OnStatusUpdate again, but at that
769 : // point we will not be waiting on discovery anymore.
770 0 : if (!mDiscoveredParameters.empty())
771 : {
772 0 : ChipLogProgress(Controller, "Ignoring SecurePairingFailed status for now; we have more discovered devices to try");
773 0 : return;
774 : }
775 :
776 0 : if (DiscoveryInProgress())
777 : {
778 0 : ChipLogProgress(Controller,
779 : "Ignoring SecurePairingFailed status for now; we are waiting to see if we discover more devices");
780 0 : return;
781 : }
782 : }
783 :
784 0 : if (mPairingDelegate)
785 : {
786 0 : mPairingDelegate->OnStatusUpdate(status);
787 : }
788 : }
789 :
790 0 : void SetUpCodePairer::OnPairingComplete(CHIP_ERROR error, const std::optional<RendezvousParameters> & rendezvousParameters,
791 : const std::optional<SetupPayload> & setupPayload)
792 : {
793 : // Save the pairing delegate so we can notify it. We want to notify it
794 : // _after_ we restore the state on the commissioner, in case the delegate
795 : // ends up immediately calling back into the commissioner again when
796 : // notified.
797 0 : auto * pairingDelegate = mPairingDelegate;
798 0 : PASEEstablishmentComplete();
799 :
800 : // Make sure to clear out mCurrentPASEPayload whether we succeeded or failed.
801 0 : std::optional<SetupPayload> pasePayload;
802 0 : pasePayload.swap(mCurrentPASEPayload);
803 :
804 0 : if (CHIP_NO_ERROR == error)
805 : {
806 0 : ChipLogProgress(Controller, "PASE session established with commissionee. Stopping discovery.");
807 0 : ResetDiscoveryState();
808 0 : mRemoteId = kUndefinedNodeId;
809 : MATTER_LOG_METRIC_END(kMetricSetupCodePairerPairDevice, error);
810 0 : if (pairingDelegate != nullptr)
811 : {
812 : // We don't expect to have a setupPayload passed in here.
813 0 : if (setupPayload)
814 : {
815 0 : ChipLogError(Controller,
816 : "Unexpected setupPayload passed to SetUpCodePairer::OnPairingComplete. Where did it come from?");
817 : }
818 0 : pairingDelegate->OnPairingComplete(error, rendezvousParameters, pasePayload);
819 : }
820 0 : return;
821 : }
822 :
823 : // It may happen that there is a stale DNS entry. If so, ReconfirmRecord will flush
824 : // the record from the daemon cache once it determines that it is invalid.
825 : // It may not help for this particular resolve, but may help subsequent resolves.
826 0 : if (CHIP_ERROR_TIMEOUT == error && mCurrentPASEParameters.HasValue())
827 : {
828 0 : const auto & params = mCurrentPASEParameters.Value();
829 0 : const auto & peer = params.GetPeerAddress();
830 0 : const auto & ip = peer.GetIPAddress();
831 0 : auto err = Dnssd::Resolver::Instance().ReconfirmRecord(params.mHostName, ip, params.mInterfaceId);
832 0 : if (CHIP_NO_ERROR != err && CHIP_ERROR_NOT_IMPLEMENTED != err)
833 : {
834 0 : ChipLogError(Controller, "Error when verifying the validity of an address: %" CHIP_ERROR_FORMAT, err.Format());
835 : }
836 : }
837 0 : mCurrentPASEParameters.ClearValue();
838 :
839 : // We failed to establish PASE. Try the next thing we have discovered, if
840 : // any.
841 0 : if (TryNextRendezvousParameters())
842 : {
843 : // Keep waiting until that finishes. Don't call OnPairingComplete yet.
844 0 : mLastPASEError = error;
845 0 : return;
846 : }
847 :
848 : MATTER_LOG_METRIC_END(kMetricSetupCodePairerPairDevice, error);
849 0 : if (pairingDelegate != nullptr)
850 : {
851 0 : pairingDelegate->OnPairingComplete(error, rendezvousParameters, pasePayload);
852 : }
853 0 : }
854 :
855 0 : void SetUpCodePairer::OnPairingDeleted(CHIP_ERROR error)
856 : {
857 0 : if (mPairingDelegate)
858 : {
859 0 : mPairingDelegate->OnPairingDeleted(error);
860 : }
861 0 : }
862 :
863 0 : void SetUpCodePairer::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error)
864 : {
865 : // Not really expecting this, but handle it anyway.
866 0 : if (mPairingDelegate)
867 : {
868 0 : mPairingDelegate->OnCommissioningComplete(deviceId, error);
869 : }
870 0 : }
871 :
872 0 : void SetUpCodePairer::OnDeviceDiscoveredTimeoutCallback(System::Layer * layer, void * context)
873 : {
874 0 : ChipLogError(Controller, "Discovery timed out");
875 0 : auto * pairer = static_cast<SetUpCodePairer *>(context);
876 0 : pairer->StopAllDiscoveryAttempts();
877 0 : if (!pairer->mWaitingForPASE && pairer->mDiscoveredParameters.empty())
878 : {
879 : // We're not waiting on any more PASE attempts, and we're not going to
880 : // discover anything at this point, so we should just notify our
881 : // listener.
882 0 : CHIP_ERROR err = pairer->mLastPASEError;
883 0 : if (err == CHIP_NO_ERROR)
884 : {
885 0 : err = CHIP_ERROR_TIMEOUT;
886 : }
887 : MATTER_LOG_METRIC_END(kMetricSetupCodePairerPairDevice, err);
888 0 : pairer->mCommissioner->OnSessionEstablishmentError(err);
889 : }
890 0 : }
891 :
892 0 : bool SetUpCodePairer::ShouldDiscoverUsing(RendezvousInformationFlag commissioningChannel) const
893 : {
894 0 : for (auto & payload : mSetupPayloads)
895 : {
896 0 : auto & rendezvousInformation = payload.rendezvousInformation;
897 0 : if (!rendezvousInformation.HasValue())
898 : {
899 : // No idea which commissioning channels this device supports, so we
900 : // should be trying using all of them.
901 0 : return true;
902 : }
903 :
904 0 : if (rendezvousInformation.Value().Has(commissioningChannel))
905 : {
906 0 : return true;
907 : }
908 : }
909 :
910 : // None of the payloads claimed support for this commissioning channel.
911 0 : return false;
912 : }
913 :
914 0 : SetUpCodePairerParameters::SetUpCodePairerParameters(const Dnssd::CommonResolutionData & data,
915 0 : std::optional<uint16_t> longDiscriminator, size_t index) :
916 0 : mLongDiscriminator(longDiscriminator)
917 : {
918 0 : mInterfaceId = data.interfaceId;
919 0 : Platform::CopyString(mHostName, data.hostName);
920 :
921 0 : auto & ip = data.ipAddress[index];
922 0 : SetPeerAddress(Transport::PeerAddress::UDP(ip, data.port, ip.IsIPv6LinkLocal() ? data.interfaceId : Inet::InterfaceId::Null()));
923 :
924 0 : if (data.mrpRetryIntervalIdle.has_value())
925 : {
926 0 : SetIdleInterval(*data.mrpRetryIntervalIdle);
927 : }
928 :
929 0 : if (data.mrpRetryIntervalActive.has_value())
930 : {
931 0 : SetActiveInterval(*data.mrpRetryIntervalActive);
932 : }
933 0 : }
934 :
935 : #if CONFIG_NETWORK_LAYER_BLE
936 0 : SetUpCodePairerParameters::SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj, std::optional<uint16_t> longDiscriminator,
937 0 : bool connected) :
938 0 : mLongDiscriminator(longDiscriminator)
939 : {
940 0 : Transport::PeerAddress peerAddress = Transport::PeerAddress::BLE();
941 0 : SetPeerAddress(peerAddress);
942 0 : if (connected)
943 : {
944 0 : SetConnectionObject(connObj);
945 : }
946 : else
947 : {
948 0 : SetDiscoveredObject(connObj);
949 : }
950 0 : }
951 : #endif // CONFIG_NETWORK_LAYER_BLE
952 :
953 : } // namespace Controller
954 : } // namespace chip
|