Skip to content

Commit

Permalink
Re-add the setupCommissioningSessionWithPayload API on MTRDeviceContr…
Browse files Browse the repository at this point in the history
…oller.

This is a re-landing of some of the API addition parts of
project-chip#22596 and
project-chip#22566, without including
any of the API changes/removals. The code is nearly identical to what was on
master before Darwin framework changes were reverted in
project-chip#23155; the differences have
to do with the different type and name of MTRSetupPayload's
rendezvousInformation.
  • Loading branch information
bzbarsky-apple committed Oct 13, 2022
1 parent c169bc6 commit 6a446ee
Show file tree
Hide file tree
Showing 13 changed files with 231 additions and 63 deletions.
17 changes: 7 additions & 10 deletions examples/darwin-framework-tool/commands/pairing/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ class PairCodeThread : public PairingCommandBridge
PairCodeThread() : PairingCommandBridge("code-thread", PairingMode::Code, PairingNetworkType::Thread) {}
};

class PairWithIPAddress : public PairingCommandBridge
{
public:
PairWithIPAddress() : PairingCommandBridge("ethernet", PairingMode::Ethernet, PairingNetworkType::Ethernet) {}
};

class PairBleWiFi : public PairingCommandBridge
{
public:
Expand All @@ -70,10 +64,13 @@ void registerCommandsPairing(Commands & commands)
const char * clusterName = "Pairing";

commands_list clusterCommands = {
make_unique<PairCode>(), make_unique<PairWithIPAddress>(),
make_unique<PairCodeWifi>(), make_unique<PairCodeThread>(),
make_unique<PairBleWiFi>(), make_unique<PairBleThread>(),
make_unique<Unpair>(), make_unique<OpenCommissioningWindowCommand>(),
make_unique<PairCode>(),
make_unique<PairCodeWifi>(),
make_unique<PairCodeThread>(),
make_unique<PairBleWiFi>(),
make_unique<PairBleThread>(),
make_unique<Unpair>(),
make_unique<OpenCommissioningWindowCommand>(),
};

commands.Register(clusterName, clusterCommands);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ enum class PairingMode
{
None,
Code,
Ethernet,
Ble,
};

Expand Down Expand Up @@ -64,12 +63,6 @@ class PairingCommandBridge : public CHIPCommandBridge
case PairingMode::Code:
AddArgument("payload", &mOnboardingPayload);
break;
case PairingMode::Ethernet:
AddArgument("setup-pin-code", 0, 134217727, &mSetupPINCode);
AddArgument("discriminator", 0, 4096, &mDiscriminator);
AddArgument("device-remote-ip", &ipAddress);
AddArgument("device-remote-port", 0, UINT16_MAX, &mRemotePort);
break;
case PairingMode::Ble:
AddArgument("setup-pin-code", 0, 134217727, &mSetupPINCode);
AddArgument("discriminator", 0, 4096, &mDiscriminator);
Expand All @@ -84,7 +77,6 @@ class PairingCommandBridge : public CHIPCommandBridge
private:
void PairWithCode(NSError * __autoreleasing * error);
void PairWithPayload(NSError * __autoreleasing * error);
void PairWithIPAddress(NSError * __autoreleasing * error);
void Unpair();
void SetUpPairingDelegate();

Expand All @@ -94,9 +86,7 @@ class PairingCommandBridge : public CHIPCommandBridge
chip::ByteSpan mSSID;
chip::ByteSpan mPassword;
chip::NodeId mNodeId;
uint16_t mRemotePort;
uint16_t mDiscriminator;
uint32_t mSetupPINCode;
char * mOnboardingPayload;
char * ipAddress;
};
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@
case PairingMode::Code:
PairWithPayload(&error);
break;
case PairingMode::Ethernet:
PairWithIPAddress(&error);
break;
case PairingMode::Ble:
PairWithCode(&error);
break;
Expand All @@ -83,28 +80,21 @@
void PairingCommandBridge::PairWithCode(NSError * __autoreleasing * error)
{
SetUpPairingDelegate();
auto * payload = [[MTRSetupPayload alloc] initWithSetupPasscode:@(mSetupPINCode) discriminator:@(mDiscriminator)];
MTRDeviceController * commissioner = CurrentCommissioner();
[commissioner pairDevice:mNodeId discriminator:mDiscriminator setupPINCode:mSetupPINCode error:error];
[commissioner setupCommissioningSessionWithPayload:payload newNodeID:@(mNodeId) error:error];
}

void PairingCommandBridge::PairWithPayload(NSError * __autoreleasing * error)
{
NSString * payload = [NSString stringWithUTF8String:mOnboardingPayload];

SetUpPairingDelegate();
MTRDeviceController * commissioner = CurrentCommissioner();
[commissioner pairDevice:mNodeId onboardingPayload:payload error:error];
}

void PairingCommandBridge::PairWithIPAddress(NSError * __autoreleasing * error)
{
NSString * onboardingPayload = [NSString stringWithUTF8String:mOnboardingPayload];
SetUpPairingDelegate();
auto * payload = [MTRSetupPayload setupPayloadWithOnboardingPayload:onboardingPayload error:error];
if (payload == nil) {
return;
}
MTRDeviceController * commissioner = CurrentCommissioner();
[commissioner pairDevice:mNodeId
address:[NSString stringWithUTF8String:ipAddress]
port:mRemotePort
setupPINCode:mSetupPINCode
error:error];
[commissioner setupCommissioningSessionWithPayload:payload newNodeID:@(mNodeId) error:error];
}

void PairingCommandBridge::Unpair()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ class TestCommandBridge : public CHIPCommandBridge,
length:value.payload.size()
encoding:NSUTF8StringEncoding];
NSError * err;
BOOL ok = [controller pairDevice:value.nodeId onboardingPayload:payloadStr error:&err];
auto * payload = [MTRSetupPayload setupPayloadWithOnboardingPayload:payloadStr error:&err];
if (err != nil) {
return MTRErrorToCHIPErrorCode(err);
}
BOOL ok = [controller setupCommissioningSessionWithPayload:payload newNodeID:@(value.nodeId) error:&err];
if (ok == YES) {
return CHIP_NO_ERROR;
}
Expand Down
11 changes: 0 additions & 11 deletions scripts/tests/chiptest/lsan-mac-suppressions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@ leak:drbg_bytes
# TODO: OpenSSL ERR_get_state seems to leak.
leak:ERR_get_state

# TODO: BLE initialization allocates some UUIDs and strings that seem to leak.
leak:[BleConnection initWithDiscriminator:]
leak:[CBXpcConnection initWithDelegate:queue:options:sessionType:]

# TODO: Figure out how we are managing to leak NSData while using ARC!
leak:[CHIPToolKeypair signMessageECDSA_RAW:]

# TODO: Figure out how we are managing to leak NSData while using ARC, though
# this may just be a leak deep inside the CFPreferences stuff somewhere.
leak:[CHIPToolPersistentStorageDelegate storageDataForKey:]

# TODO: https://github.com/project-chip/connectedhomeip/issues/22333
leak:[MTRBaseCluster* subscribeAttribute*WithMinInterval:maxInterval:params:subscriptionEstablished:reportHandler:]

Expand Down
32 changes: 32 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS
*/
@property (readonly, nonatomic, nullable) NSNumber * controllerNodeId;

/**
* Set up a commissioning session for a device, using the provided setup payload
* to discover it and connect to it.
*
* @param payload a setup payload (probably created from a QR code or numeric
* code onboarding payload).
* @param newNodeID the planned node id for the node.
* @error error indication if discovery can't start at all (e.g. because the
* setup payload is invalid).
*
* The IP and port for the device will be discovered automatically based on the
* provided discriminator.
*
* Then a PASE session will be established with the device, unless an error
* occurs. MTRDevicePairingDelegate will be notified as follows:
*
* * Discovery fails: onStatusUpdate with MTRPairingStatusFailed.
*
* * Discovery succeeds but commissioning session setup fails: onPairingComplete
* with an error.
*
* * Commissioning session setup succeeds: onPairingComplete with no error.
*
* Once a commissioning session is set up, getDeviceBeingCommissioned
* can be used to get an MTRBaseDevice and discover what sort of network
* credentials the device might need, and commissionDevice can be used to
* commission the device.
*/
- (BOOL)setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload
newNodeID:(NSNumber *)newNodeID
error:(NSError * __autoreleasing *)error;

/**
* Start pairing for a device with the given ID, using the provided setup PIN
* to establish a PASE connection.
Expand Down
30 changes: 30 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,36 @@ - (NSNumber *)controllerNodeId
return nodeID;
}

- (BOOL)setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload
newNodeID:(NSNumber *)newNodeID
error:(NSError * __autoreleasing *)error
{
VerifyOrReturnValue([self checkIsRunning:error], NO);

__block BOOL success = NO;
dispatch_sync(_chipWorkQueue, ^{
VerifyOrReturn([self checkIsRunning:error]);

// Try to get a QR code if possible (because it has a better
// discriminator, etc), then fall back to manual code if that fails.
NSString * pairingCode = [payload qrCodeString];
if (pairingCode == nil) {
pairingCode = [payload manualEntryCode];
}
if (pairingCode == nil) {
success = ![self checkForError:CHIP_ERROR_INVALID_ARGUMENT logMsg:kErrorSetupCodeGen error:error];
return;
}

chip::NodeId nodeId = [newNodeID unsignedLongLongValue];
_operationalCredentialsDelegate->SetDeviceID(nodeId);
CHIP_ERROR errorCode = self.cppCommissioner->EstablishPASEConnection(nodeId, [pairingCode UTF8String]);
success = ![self checkForError:errorCode logMsg:kErrorPairDevice error:error];
});

return success;
}

- (BOOL)pairDevice:(uint64_t)deviceID
discriminator:(uint16_t)discriminator
setupPINCode:(uint32_t)setupPINCode
Expand Down
11 changes: 11 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ + (MTRDeviceControllerOverXPC *)sharedControllerWithId:(id<NSCopying> _Nullable)
connectBlock:connectBlock];
}

- (BOOL)setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload
newNodeID:(NSNumber *)newNodeID
error:(NSError * __autoreleasing *)error
{
MTR_LOG_ERROR("MTRDeviceController doesn't support setupCommissioningSessionWithPayload over XPC");
if (error != nil) {
*error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeInvalidState userInfo:nil];
}
return NO;
}

- (BOOL)pairDevice:(uint64_t)deviceID
discriminator:(uint16_t)discriminator
setupPINCode:(uint32_t)setupPINCode
Expand Down
22 changes: 22 additions & 0 deletions src/darwin/Framework/CHIP/MTRSetupPayload.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,31 @@ typedef NS_ENUM(NSUInteger, MTROptionalQRCodeInfoType) {
*/
+ (NSNumber *)generateRandomSetupPasscode;

/**
* Create an MTRSetupPayload with the given onboarding payload.
*
* Will return nil on errors (e.g. if the onboarding payload cannot be parsed).
*/
+ (MTRSetupPayload * _Nullable)setupPayloadWithOnboardingPayload:(NSString *)onboardingPayload
error:(NSError * __autoreleasing *)error;

/**
* Initialize an MTRSetupPayload with the given passcode and discriminator.
* This will pre-set version, product id, and vendor id to 0.
*/
- (instancetype)initWithSetupPasscode:(NSNumber *)setupPasscode discriminator:(NSNumber *)discriminator;

/** Get 11 digit manual entry code from the setup payload. */
- (nullable NSString *)manualEntryCode;

/**
* Get a QR code from the setup payload.
*
* Returns nil on failure (e.g. if the setup payload does not have all the
* information a QR code needs).
*/
- (NSString * _Nullable)qrCodeString;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 6a446ee

Please sign in to comment.