Skip to content

Commit

Permalink
Add API on Darwin to open commissioning windows without explicitly pr…
Browse files Browse the repository at this point in the history
…oviding a setup code. (#26037)

Fixes #22842
  • Loading branch information
bzbarsky-apple authored Apr 11, 2023
1 parent fd26cd3 commit ed5ebd2
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 16 deletions.
16 changes: 16 additions & 0 deletions src/darwin/Framework/CHIP/MTRBaseDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,22 @@ typedef NS_ENUM(uint8_t, MTRTransportType) {
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
API_AVAILABLE(ios(16.2), macos(13.1), watchos(9.2), tvos(16.2));

/**
* Open a commissioning window on the device, using a random setup passcode.
*
* On success, completion will be called on queue with the MTRSetupPayload that
* can be used to commission the device.
*
* @param discriminator The discriminator to use for the commissionable
* advertisement.
* @param duration Duration, in seconds, during which the commissioning
* window will be open.
*/
- (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion MTR_NEWLY_AVAILABLE;

/**
* Reads events from the device.
*
Expand Down
61 changes: 45 additions & 16 deletions src/darwin/Framework/CHIP/MTRBaseDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,7 @@ - (void)deregisterReportHandlersWithQueue:(dispatch_queue_t)queue completion:(di

public:
static CHIP_ERROR OpenCommissioningWindow(Controller::DeviceController * controller, NodeId nodeID,
System::Clock::Seconds16 timeout, uint16_t discriminator, uint32_t setupPIN, ResultCallback callback);
System::Clock::Seconds16 timeout, uint16_t discriminator, const Optional<uint32_t> & setupPIN, ResultCallback callback);

private:
OpenCommissioningWindowHelper(Controller::DeviceController * controller, ResultCallback callback);
Expand All @@ -1300,7 +1300,7 @@ static CHIP_ERROR OpenCommissioningWindow(Controller::DeviceController * control
}

CHIP_ERROR OpenCommissioningWindowHelper::OpenCommissioningWindow(Controller::DeviceController * controller, NodeId nodeID,
System::Clock::Seconds16 timeout, uint16_t discriminator, uint32_t setupPIN, ResultCallback callback)
System::Clock::Seconds16 timeout, uint16_t discriminator, const Optional<uint32_t> & setupPIN, ResultCallback callback)
{
auto * self = new (std::nothrow) OpenCommissioningWindowHelper(controller, callback);
if (self == nullptr) {
Expand All @@ -1309,7 +1309,7 @@ static CHIP_ERROR OpenCommissioningWindow(Controller::DeviceController * control

SetupPayload unused;
CHIP_ERROR err = self->mOpener.OpenCommissioningWindow(nodeID, timeout, Crypto::kSpake2p_Min_PBKDF_Iterations, discriminator,
MakeOptional(setupPIN), NullOptional, &self->mOnOpenCommissioningWindowCallback, unused);
setupPIN, NullOptional, &self->mOnOpenCommissioningWindowCallback, unused);
if (err != CHIP_NO_ERROR) {
delete self;
}
Expand All @@ -1327,11 +1327,11 @@ static CHIP_ERROR OpenCommissioningWindow(Controller::DeviceController * control

} // anonymous namespace

- (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
discriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
- (void)_openCommissioningWindowWithSetupPasscode:(nullable NSNumber *)setupPasscode
discriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
{
if (self.isPASEDevice) {
MTR_LOG_ERROR("Can't open a commissioning window over PASE");
Expand Down Expand Up @@ -1360,13 +1360,17 @@ - (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
return;
}

unsigned long long passcodeVal = [setupPasscode unsignedLongLongValue];
if (!CanCastTo<uint32_t>(passcodeVal) || !SetupPayload::IsValidSetupPIN(static_cast<uint32_t>(passcodeVal))) {
MTR_LOG_ERROR("Error: Setup passcode %llu is not valid", passcodeVal);
dispatch_async(queue, ^{
completion(nil, [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_INTEGER_VALUE]);
});
return;
Optional<uint32_t> passcode;
if (setupPasscode != nil) {
unsigned long long passcodeVal = [setupPasscode unsignedLongLongValue];
if (!CanCastTo<uint32_t>(passcodeVal) || !SetupPayload::IsValidSetupPIN(static_cast<uint32_t>(passcodeVal))) {
MTR_LOG_ERROR("Error: Setup passcode %llu is not valid", passcodeVal);
dispatch_async(queue, ^{
completion(nil, [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_INTEGER_VALUE]);
});
return;
}
passcode.Emplace(static_cast<uint32_t>(passcodeVal));
}

[self.deviceController
Expand Down Expand Up @@ -1394,7 +1398,7 @@ - (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
SetupPayload setupPayload;
auto errorCode = OpenCommissioningWindowHelper::OpenCommissioningWindow(commissioner, self.nodeID,
chip::System::Clock::Seconds16(static_cast<uint16_t>(durationVal)), static_cast<uint16_t>(discriminatorVal),
static_cast<uint32_t>(passcodeVal), resultCallback);
passcode, resultCallback);

if (errorCode != CHIP_NO_ERROR) {
dispatch_async(queue, ^{
Expand All @@ -1412,6 +1416,31 @@ - (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
}];
}

- (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
discriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
{
[self _openCommissioningWindowWithSetupPasscode:setupPasscode
discriminator:discriminator
duration:duration
queue:queue
completion:completion];
}

- (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
{
[self _openCommissioningWindowWithSetupPasscode:nil
discriminator:discriminator
duration:duration
queue:queue
completion:completion];
}

#ifdef DEBUG
// This method is for unit testing only
- (void)failSubscribers:(dispatch_queue_t)queue completion:(void (^)(void))completion
Expand Down
16 changes: 16 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,22 @@ typedef NS_ENUM(NSUInteger, MTRDeviceState) {
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
API_AVAILABLE(ios(16.2), macos(13.1), watchos(9.2), tvos(16.2));

/**
* Open a commissioning window on the device, using a random setup passcode.
*
* On success, completion will be called on queue with the MTRSetupPayload that
* can be used to commission the device.
*
* @param discriminator The discriminator to use for the commissionable
* advertisement.
* @param duration Duration, in seconds, during which the commissioning
* window will be open.
*/
- (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion MTR_NEWLY_AVAILABLE;

@end

extern NSString * const MTREventNumberKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
Expand Down
9 changes: 9 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,15 @@ - (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
completion:completion];
}

- (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
{
auto * baseDevice = [self newBaseDevice];
[baseDevice openCommissioningWindowWithDiscriminator:discriminator duration:duration queue:queue completion:completion];
}

#pragma mark - Cache management

// assume lock is held
Expand Down
11 changes: 11 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,17 @@ - (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode
});
}

- (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
duration:(NSNumber *)duration
queue:(dispatch_queue_t)queue
completion:(MTRDeviceOpenCommissioningWindowHandler)completion
{
MTR_LOG_ERROR("MTRDevice doesn't support openCommissioningWindowWithDiscriminator over XPC");
dispatch_async(queue, ^{
completion(nil, [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeInvalidState userInfo:nil]);
});
}

- (void)fetchProxyHandleWithQueue:(dispatch_queue_t)queue completion:(MTRFetchProxyHandleCompletion)completion
{
if (self.controllerID != nil) {
Expand Down

0 comments on commit ed5ebd2

Please sign in to comment.