Skip to content

Commit 3824211

Browse files
pan-applepull[bot]
authored andcommitted
Include VID/PID in ECM commissioning Setup Payload (#11894)
* Include VID/PID in ECM commissioning Setup Payload * address some review comments * use templated ReadAttribute API * address review comments * read VID PID only if asked by the application
1 parent 8c0b1f4 commit 3824211

File tree

4 files changed

+127
-39
lines changed

4 files changed

+127
-39
lines changed

examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ void OpenCommissioningWindowCommand::OnOpenCommissioningWindowResponse(void * co
5353
CHIP_ERROR OpenCommissioningWindowCommand::OpenCommissioningWindow()
5454
{
5555
return CurrentCommissioner().OpenCommissioningWindowWithCallback(
56-
mNodeId, mTimeout, mIteration, mDiscriminator, mCommissioningWindowOption, &mOnOpenCommissioningWindowCallback);
56+
mNodeId, mTimeout, mIteration, mDiscriminator, mCommissioningWindowOption, &mOnOpenCommissioningWindowCallback,
57+
/* readVIDPIDAttributes */ true);
5758
}

src/controller/CHIPDeviceController.cpp

+104-37
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,57 @@ CHIP_ERROR DeviceController::GetPeerAddressAndPort(PeerId peerId, Inet::IPAddres
353353
return CHIP_NO_ERROR;
354354
}
355355

356+
void DeviceController::OnPIDReadResponse(void * context, uint16_t value)
357+
{
358+
ChipLogProgress(Controller, "Received PID for the device. Value %d", value);
359+
DeviceController * controller = static_cast<DeviceController *>(context);
360+
controller->mSetupPayload.productID = value;
361+
362+
if (controller->OpenCommissioningWindowInternal() != CHIP_NO_ERROR)
363+
{
364+
OnOpenPairingWindowFailureResponse(context, 0);
365+
}
366+
}
367+
368+
void DeviceController::OnVIDReadResponse(void * context, uint16_t value)
369+
{
370+
ChipLogProgress(Controller, "Received VID for the device. Value %d", value);
371+
372+
DeviceController * controller = static_cast<DeviceController *>(context);
373+
374+
controller->mSetupPayload.vendorID = value;
375+
376+
OperationalDeviceProxy * device =
377+
controller->mCASESessionManager->FindExistingSession(controller->mDeviceWithCommissioningWindowOpen);
378+
if (device == nullptr)
379+
{
380+
ChipLogError(Controller, "Could not find device for opening commissioning window");
381+
OnOpenPairingWindowFailureResponse(context, 0);
382+
return;
383+
}
384+
385+
constexpr EndpointId kBasicClusterEndpoint = 0;
386+
chip::Controller::BasicCluster cluster;
387+
cluster.Associate(device, kBasicClusterEndpoint);
388+
389+
if (cluster.ReadAttribute<app::Clusters::Basic::Attributes::ProductID::TypeInfo>(context, OnPIDReadResponse,
390+
OnVIDPIDReadFailureResponse) != CHIP_NO_ERROR)
391+
{
392+
ChipLogError(Controller, "Could not read PID for opening commissioning window");
393+
OnOpenPairingWindowFailureResponse(context, 0);
394+
}
395+
}
396+
397+
void DeviceController::OnVIDPIDReadFailureResponse(void * context, EmberAfStatus status)
398+
{
399+
ChipLogProgress(Controller, "Failed to read VID/PID for the device. status %d", status);
400+
OnOpenPairingWindowFailureResponse(context, status);
401+
}
402+
356403
void DeviceController::OnOpenPairingWindowSuccessResponse(void * context)
357404
{
358405
ChipLogProgress(Controller, "Successfully opened pairing window on the device");
359-
DeviceController * controller = reinterpret_cast<DeviceController *>(context);
406+
DeviceController * controller = static_cast<DeviceController *>(context);
360407
if (controller->mCommissioningWindowCallback != nullptr)
361408
{
362409
controller->mCommissioningWindowCallback->mCall(controller->mCommissioningWindowCallback->mContext,
@@ -368,12 +415,11 @@ void DeviceController::OnOpenPairingWindowSuccessResponse(void * context)
368415
void DeviceController::OnOpenPairingWindowFailureResponse(void * context, uint8_t status)
369416
{
370417
ChipLogError(Controller, "Failed to open pairing window on the device. Status %d", status);
371-
DeviceController * controller = reinterpret_cast<DeviceController *>(context);
418+
DeviceController * controller = static_cast<DeviceController *>(context);
372419
if (controller->mCommissioningWindowCallback != nullptr)
373420
{
374421
CHIP_ERROR error = CHIP_ERROR_INVALID_PASE_PARAMETER;
375-
// TODO - Use cluster enum chip::app::Clusters::AdministratorCommissioning::StatusCode::kBusy
376-
if (status == 1)
422+
if (status == EmberAfStatusCode::EMBER_ZCL_STATUS_CODE_BUSY)
377423
{
378424
error = CHIP_ERROR_ANOTHER_COMMISSIONING_IN_PROGRESS;
379425
}
@@ -393,38 +439,60 @@ CHIP_ERROR DeviceController::ComputePASEVerifier(uint32_t iterations, uint32_t s
393439

394440
CHIP_ERROR DeviceController::OpenCommissioningWindowWithCallback(NodeId deviceId, uint16_t timeout, uint16_t iteration,
395441
uint16_t discriminator, uint8_t option,
396-
Callback::Callback<OnOpenCommissioningWindow> * callback)
442+
Callback::Callback<OnOpenCommissioningWindow> * callback,
443+
bool readVIDPIDAttributes)
397444
{
398-
ChipLogProgress(Controller, "OpenCommissioningWindow for device ID %" PRIu64, deviceId);
399-
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
400-
401-
OperationalDeviceProxy * device = mCASESessionManager->FindExistingSession(deviceId);
402-
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
445+
mSetupPayload = SetupPayload();
403446

404-
std::string QRCode;
405-
std::string manualPairingCode;
406-
SetupPayload payload;
407-
CommissioningWindowOption commissioningWindowOption;
408-
ByteSpan salt(reinterpret_cast<const uint8_t *>(kSpake2pKeyExchangeSalt), strlen(kSpake2pKeyExchangeSalt));
447+
mSetupPayload.version = 0;
448+
mSetupPayload.discriminator = discriminator;
449+
mSetupPayload.rendezvousInformation = RendezvousInformationFlags(RendezvousInformationFlag::kOnNetwork);
409450

410-
payload.discriminator = discriminator;
451+
mCommissioningWindowCallback = callback;
452+
mDeviceWithCommissioningWindowOpen = deviceId;
453+
mCommissioningWindowTimeout = timeout;
454+
mCommissioningWindowIteration = iteration;
411455

412456
switch (option)
413457
{
414458
case 0:
415-
commissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode;
459+
mCommissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode;
416460
break;
417461
case 1:
418-
commissioningWindowOption = CommissioningWindowOption::kTokenWithRandomPIN;
462+
mCommissioningWindowOption = CommissioningWindowOption::kTokenWithRandomPIN;
419463
break;
420464
case 2:
421-
commissioningWindowOption = CommissioningWindowOption::kTokenWithProvidedPIN;
465+
mCommissioningWindowOption = CommissioningWindowOption::kTokenWithProvidedPIN;
422466
break;
423467
default:
424468
ChipLogError(Controller, "Invalid Pairing Window option");
425469
return CHIP_ERROR_INVALID_ARGUMENT;
426470
}
427471

472+
if (callback != nullptr && mCommissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode && readVIDPIDAttributes)
473+
{
474+
OperationalDeviceProxy * device = mCASESessionManager->FindExistingSession(mDeviceWithCommissioningWindowOpen);
475+
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
476+
477+
constexpr EndpointId kBasicClusterEndpoint = 0;
478+
chip::Controller::BasicCluster cluster;
479+
cluster.Associate(device, kBasicClusterEndpoint);
480+
481+
return cluster.ReadAttribute<app::Clusters::Basic::Attributes::VendorID::TypeInfo>(this, OnVIDReadResponse,
482+
OnVIDPIDReadFailureResponse);
483+
}
484+
485+
return OpenCommissioningWindowInternal();
486+
}
487+
488+
CHIP_ERROR DeviceController::OpenCommissioningWindowInternal()
489+
{
490+
ChipLogProgress(Controller, "OpenCommissioningWindow for device ID %" PRIu64, mDeviceWithCommissioningWindowOpen);
491+
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
492+
493+
OperationalDeviceProxy * device = mCASESessionManager->FindExistingSession(mDeviceWithCommissioningWindowOpen);
494+
VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
495+
428496
constexpr EndpointId kAdministratorCommissioningClusterEndpoint = 0;
429497

430498
chip::Controller::AdministratorCommissioningCluster cluster;
@@ -433,41 +501,40 @@ CHIP_ERROR DeviceController::OpenCommissioningWindowWithCallback(NodeId deviceId
433501
Callback::Cancelable * successCallback = mOpenPairingSuccessCallback.Cancel();
434502
Callback::Cancelable * failureCallback = mOpenPairingFailureCallback.Cancel();
435503

436-
payload.version = 0;
437-
payload.rendezvousInformation = RendezvousInformationFlags(RendezvousInformationFlag::kOnNetwork);
438-
439-
mCommissioningWindowCallback = callback;
440-
if (commissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode)
504+
if (mCommissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode)
441505
{
442-
bool randomSetupPIN = (commissioningWindowOption == CommissioningWindowOption::kTokenWithRandomPIN);
506+
ByteSpan salt(Uint8::from_const_char(kSpake2pKeyExchangeSalt), strlen(kSpake2pKeyExchangeSalt));
507+
bool randomSetupPIN = (mCommissioningWindowOption == CommissioningWindowOption::kTokenWithRandomPIN);
443508
PASEVerifier verifier;
444509

445-
ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, iteration, salt, randomSetupPIN, payload.setUpPINCode));
510+
ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, mCommissioningWindowIteration, salt, randomSetupPIN,
511+
mSetupPayload.setUpPINCode));
446512

447513
uint8_t serializedVerifier[2 * kSpake2p_WS_Length];
448514
VerifyOrReturnError(sizeof(serializedVerifier) == sizeof(verifier), CHIP_ERROR_INTERNAL);
449515

450516
memcpy(serializedVerifier, verifier.mW0, kSpake2p_WS_Length);
451517
memcpy(&serializedVerifier[kSpake2p_WS_Length], verifier.mL, kSpake2p_WS_Length);
452518

453-
ReturnErrorOnFailure(cluster.OpenCommissioningWindow(successCallback, failureCallback, timeout,
454-
ByteSpan(serializedVerifier, sizeof(serializedVerifier)),
455-
payload.discriminator, iteration, salt, mPAKEVerifierID++));
519+
ReturnErrorOnFailure(cluster.OpenCommissioningWindow(
520+
successCallback, failureCallback, mCommissioningWindowTimeout, ByteSpan(serializedVerifier, sizeof(serializedVerifier)),
521+
mSetupPayload.discriminator, mCommissioningWindowIteration, salt, mPAKEVerifierID++));
522+
523+
char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength];
456524

457-
ReturnErrorOnFailure(ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualPairingCode));
458-
ChipLogProgress(Controller, "Manual pairing code: [%s]", manualPairingCode.c_str());
525+
MutableCharSpan manualCode(payloadBuffer);
526+
ReturnErrorOnFailure(ManualSetupPayloadGenerator(mSetupPayload).payloadDecimalStringRepresentation(manualCode));
527+
ChipLogProgress(Controller, "Manual pairing code: [%s]", payloadBuffer);
459528

460-
ReturnErrorOnFailure(QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(QRCode));
461-
ChipLogProgress(Controller, "SetupQRCode: [%s]", QRCode.c_str());
529+
MutableCharSpan QRCode(payloadBuffer);
530+
ReturnErrorOnFailure(QRCodeBasicSetupPayloadGenerator(mSetupPayload).payloadBase38Representation(QRCode));
531+
ChipLogProgress(Controller, "SetupQRCode: [%s]", payloadBuffer);
462532
}
463533
else
464534
{
465-
ReturnErrorOnFailure(cluster.OpenBasicCommissioningWindow(successCallback, failureCallback, timeout));
535+
ReturnErrorOnFailure(cluster.OpenBasicCommissioningWindow(successCallback, failureCallback, mCommissioningWindowTimeout));
466536
}
467537

468-
mSetupPayload = payload;
469-
mDeviceWithCommissioningWindowOpen = deviceId;
470-
471538
return CHIP_NO_ERROR;
472539
}
473540

src/controller/CHIPDeviceController.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,16 @@ class DLL_EXPORT DeviceController : public SessionReleaseDelegate,
311311
* the PIN code provied in the setupPayload).
312312
* @param[in] callback The function to be called on success or failure of opening of commissioning window.
313313
*
314+
* @param[in] readVIDPIDAttributes Should the API internally read VID and PID from the device while opening the
315+
* commissioning window. VID and PID is only needed for enchanced commissioning mode.
316+
* If this argument is `true`, and enhanced commissioning mode is used, the API will
317+
* read VID and PID from the device.
318+
*
314319
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
315320
*/
316321
CHIP_ERROR OpenCommissioningWindowWithCallback(NodeId deviceId, uint16_t timeout, uint16_t iteration, uint16_t discriminator,
317-
uint8_t option, Callback::Callback<OnOpenCommissioningWindow> * callback);
322+
uint8_t option, Callback::Callback<OnOpenCommissioningWindow> * callback,
323+
bool readVIDPIDAttributes = false);
318324

319325
#if CHIP_DEVICE_CONFIG_ENABLE_DNSSD
320326
void RegisterDeviceAddressUpdateDelegate(DeviceAddressUpdateDelegate * delegate) { mDeviceAddressUpdateDelegate = delegate; }
@@ -396,11 +402,22 @@ class DLL_EXPORT DeviceController : public SessionReleaseDelegate,
396402
Callback::Callback<DefaultSuccessCallback> mOpenPairingSuccessCallback;
397403
Callback::Callback<DefaultFailureCallback> mOpenPairingFailureCallback;
398404

405+
static void OnPIDReadResponse(void * context, uint16_t value);
406+
static void OnVIDReadResponse(void * context, uint16_t value);
407+
static void OnVIDPIDReadFailureResponse(void * context, EmberAfStatus status);
408+
409+
CHIP_ERROR OpenCommissioningWindowInternal();
410+
399411
// TODO - Support opening commissioning window simultaneously on multiple devices
400412
Callback::Callback<OnOpenCommissioningWindow> * mCommissioningWindowCallback = nullptr;
401413
SetupPayload mSetupPayload;
402414
NodeId mDeviceWithCommissioningWindowOpen;
403415

416+
uint16_t mCommissioningWindowTimeout;
417+
uint16_t mCommissioningWindowIteration;
418+
419+
CommissioningWindowOption mCommissioningWindowOption;
420+
404421
static void OnOpenPairingWindowSuccessResponse(void * context);
405422
static void OnOpenPairingWindowFailureResponse(void * context, uint8_t status);
406423

src/setup_payload/QRCodeSetupPayloadGenerator.h

+3
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ class QRCodeBasicSetupPayloadGenerator
114114
* producing the requested string.
115115
*/
116116
CHIP_ERROR payloadBase38Representation(MutableCharSpan & outBuffer);
117+
118+
// TODO - Find the optimal value for maximum length of QR Code Base38 string
119+
static constexpr uint16_t kMaxQRCodeBase38RepresentationLength = 128;
117120
};
118121

119122
} // namespace chip

0 commit comments

Comments
 (0)