diff --git a/examples/darwin-framework-tool/BUILD.gn b/examples/darwin-framework-tool/BUILD.gn index b920356a29b3a3..80c3daaae8a6a6 100644 --- a/examples/darwin-framework-tool/BUILD.gn +++ b/examples/darwin-framework-tool/BUILD.gn @@ -166,6 +166,9 @@ executable("darwin-framework-tool") { "commands/common/MTRError.mm", "commands/common/MTRError_Utils.h", "commands/common/MTRLogging.h", + "commands/discover/Commands.h", + "commands/discover/DiscoverCommissionablesCommand.h", + "commands/discover/DiscoverCommissionablesCommand.mm", "commands/pairing/Commands.h", "commands/pairing/DeviceControllerDelegateBridge.mm", "commands/pairing/GetCommissionerNodeIdCommand.h", diff --git a/examples/darwin-framework-tool/commands/discover/Commands.h b/examples/darwin-framework-tool/commands/discover/Commands.h new file mode 100644 index 00000000000000..d1d54eac255ddb --- /dev/null +++ b/examples/darwin-framework-tool/commands/discover/Commands.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#import + +#include "DiscoverCommissionablesCommand.h" + +void registerCommandsDiscover(Commands & commands) +{ + const char * clusterName = "Discover"; + + commands_list clusterCommands = { + make_unique(), + make_unique(), + make_unique(), + }; + + commands.Register(clusterName, clusterCommands); +} diff --git a/examples/darwin-framework-tool/commands/discover/DiscoverCommissionablesCommand.h b/examples/darwin-framework-tool/commands/discover/DiscoverCommissionablesCommand.h new file mode 100644 index 00000000000000..dc70254f32a103 --- /dev/null +++ b/examples/darwin-framework-tool/commands/discover/DiscoverCommissionablesCommand.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "../common/CHIPCommandBridge.h" + +class DiscoverCommissionablesStartCommand : public CHIPCommandBridge +{ +public: + DiscoverCommissionablesStartCommand() : CHIPCommandBridge("start") {} + +protected: + /////////// CHIPCommandBridge Interface ///////// + CHIP_ERROR RunCommand() override; + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(30); } +}; + +class DiscoverCommissionablesStopCommand : public CHIPCommandBridge +{ +public: + DiscoverCommissionablesStopCommand() : CHIPCommandBridge("stop") {} + +protected: + /////////// CHIPCommandBridge Interface ///////// + CHIP_ERROR RunCommand() override; + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } +}; + +class DiscoverCommissionablesListCommand : public CHIPCommandBridge +{ +public: + DiscoverCommissionablesListCommand() : CHIPCommandBridge("list") {} + +protected: + /////////// CHIPCommandBridge Interface ///////// + CHIP_ERROR RunCommand() override; + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } +}; diff --git a/examples/darwin-framework-tool/commands/discover/DiscoverCommissionablesCommand.mm b/examples/darwin-framework-tool/commands/discover/DiscoverCommissionablesCommand.mm new file mode 100644 index 00000000000000..beaf43a954aea0 --- /dev/null +++ b/examples/darwin-framework-tool/commands/discover/DiscoverCommissionablesCommand.mm @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "DiscoverCommissionablesCommand.h" + +NSMutableArray * gDiscoveredDevices = [[NSMutableArray alloc] init]; +auto gDispatchQueue = dispatch_queue_create("com.chip.discover", DISPATCH_QUEUE_SERIAL); + +@interface DeviceScannerDelegate : NSObject +- (void)didDiscoverCommissionable:(MTRCommissionableBrowserResult *)device; +- (void)commissionableUnavailable:(MTRCommissionableBrowserResult *)device; +@end + +@implementation DeviceScannerDelegate +- (void)didDiscoverCommissionable:(MTRCommissionableBrowserResult *)device +{ + auto serviceName = device.serviceName; + auto vendorId = device.vendorId; + auto productId = device.productId; + auto discriminator = device.discriminator; + [gDiscoveredDevices addObject:device]; + + NSLog(@"Found Device (%@) with discriminator: %@ (vendor: %@, product: %@)", serviceName, discriminator, vendorId, productId); +} + +- (void)commissionableUnavailable:(MTRCommissionableBrowserResult *)device +{ + auto serviceName = device.serviceName; + auto vendorId = device.vendorId; + auto productId = device.productId; + auto discriminator = device.discriminator; + [gDiscoveredDevices removeObjectIdenticalTo:device]; + + NSLog(@"Removed Device (%@) with discriminator: %@ (vendor: %@, product: %@)", serviceName, discriminator, vendorId, productId); +} +@end + +CHIP_ERROR DiscoverCommissionablesStartCommand::RunCommand() +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + + dispatch_sync(gDispatchQueue, ^{ + [gDiscoveredDevices removeAllObjects]; + }); + + auto delegate = [[DeviceScannerDelegate alloc] init]; + auto success = [CurrentCommissioner() startScan:delegate queue:gDispatchQueue]; + VerifyOrReturnError(success, CHIP_ERROR_INTERNAL); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiscoverCommissionablesStopCommand::RunCommand() +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + + auto success = [CurrentCommissioner() stopScan]; + VerifyOrReturnError(success, CHIP_ERROR_INTERNAL); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiscoverCommissionablesListCommand::RunCommand() +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + + dispatch_sync(gDispatchQueue, ^{ + auto resultsCount = [gDiscoveredDevices count]; + VerifyOrReturn(resultsCount > 0, ChipLogProgress(chipTool, "No device discovered.")); + + uint16_t index = 0; + for (id device in gDiscoveredDevices) { + auto serviceName = [device serviceName]; + auto vendorId = [device vendorId]; + auto productId = [device productId]; + auto discriminator = [device discriminator]; + + NSLog( + @"\t %u %@ - Discriminator: %@ - Vendor: %@ - Product: %@", index, serviceName, discriminator, vendorId, productId); + + index++; + } + }); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; +} diff --git a/examples/darwin-framework-tool/commands/pairing/Commands.h b/examples/darwin-framework-tool/commands/pairing/Commands.h index 69eb9f39352e51..f15524833a0e31 100644 --- a/examples/darwin-framework-tool/commands/pairing/Commands.h +++ b/examples/darwin-framework-tool/commands/pairing/Commands.h @@ -55,6 +55,30 @@ class PairBleThread : public PairingCommandBridge PairBleThread() : PairingCommandBridge("ble-thread", PairingMode::Ble, PairingNetworkType::Thread) {} }; +class PairAlreadyDiscoveredByIndex : public PairingCommandBridge +{ +public: + PairAlreadyDiscoveredByIndex() : + PairingCommandBridge("by-index", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::None) + {} +}; + +class PairAlreadyDiscoveredByIndexWithWiFi : public PairingCommandBridge +{ +public: + PairAlreadyDiscoveredByIndexWithWiFi() : + PairingCommandBridge("by-index-with-wifi", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::WiFi) + {} +}; + +class PairAlreadyDiscoveredByIndexWithThread : public PairingCommandBridge +{ +public: + PairAlreadyDiscoveredByIndexWithThread() : + PairingCommandBridge("by-index-with-thread", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::Thread) + {} +}; + class Unpair : public PairingCommandBridge { public: @@ -71,6 +95,7 @@ void registerCommandsPairing(Commands & commands) make_unique(), make_unique(), make_unique(), + make_unique(), make_unique(), make_unique(), make_unique(), diff --git a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h index d1cdc4b6efecc5..34ad517075fb36 100644 --- a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h +++ b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h @@ -25,6 +25,7 @@ enum class PairingMode None, Code, Ble, + AlreadyDiscoveredByIndex, }; enum class PairingNetworkType @@ -67,6 +68,10 @@ class PairingCommandBridge : public CHIPCommandBridge AddArgument("setup-pin-code", 0, 134217727, &mSetupPINCode); AddArgument("discriminator", 0, 4096, &mDiscriminator); break; + case PairingMode::AlreadyDiscoveredByIndex: + AddArgument("payload", &mOnboardingPayload); + AddArgument("index", 0, UINT16_MAX, &mIndex); + break; } AddArgument("use-device-attestation-delegate", 0, 1, &mUseDeviceAttestationDelegate, @@ -82,6 +87,7 @@ class PairingCommandBridge : public CHIPCommandBridge private: void PairWithCode(NSError * __autoreleasing * error); + void PairWithIndex(NSError * __autoreleasing * error); void PairWithPayload(NSError * __autoreleasing * error); void Unpair(); void SetUpDeviceControllerDelegate(); @@ -94,6 +100,7 @@ class PairingCommandBridge : public CHIPCommandBridge chip::NodeId mNodeId; uint16_t mDiscriminator; uint32_t mSetupPINCode; + uint16_t mIndex; char * mOnboardingPayload; chip::Optional mUseDeviceAttestationDelegate; chip::Optional mDeviceAttestationFailsafeTime; diff --git a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm index a8efcc2a44635b..316f1705e91363 100644 --- a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm +++ b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm @@ -28,6 +28,8 @@ using namespace ::chip; using namespace ::chip::Controller; +extern NSMutableArray * gDiscoveredDevices; + // A no-op MTRDeviceAttestationDelegate which lets us test (by default, in CI) // commissioning flows that have such a delegate. @interface NoOpAttestationDelegate : NSObject @@ -92,6 +94,9 @@ - (void)deviceAttestationCompletedForController:(MTRDeviceController *)controlle case PairingMode::Ble: PairWithCode(&error); break; + case PairingMode::AlreadyDiscoveredByIndex: + PairWithIndex(&error); + break; } if (error != nil) { @@ -108,6 +113,29 @@ - (void)deviceAttestationCompletedForController:(MTRDeviceController *)controlle [commissioner setupCommissioningSessionWithPayload:payload newNodeID:@(mNodeId) error:error]; } +void PairingCommandBridge::PairWithIndex(NSError * __autoreleasing * error) +{ + SetUpDeviceControllerDelegate(); + MTRDeviceController * commissioner = CurrentCommissioner(); + + if (mIndex >= [gDiscoveredDevices count]) { + auto errorString = [NSString stringWithFormat:@"Error retrieving discovered device at index %@", @(mIndex)]; + *error = [[NSError alloc] initWithDomain:@"PairingDomain" + code:MTRErrorCodeGeneralError + userInfo:@ { NSLocalizedDescriptionKey : NSLocalizedString(errorString, nil) }]; + return; + } + + NSString * onboardingPayload = [NSString stringWithUTF8String:mOnboardingPayload]; + auto * payload = [MTRSetupPayload setupPayloadWithOnboardingPayload:onboardingPayload error:error]; + if (payload == nil) { + return; + } + + auto discoveredDevice = (MTRCommissionableBrowserResult *) gDiscoveredDevices[mIndex]; + [commissioner setupCommissioningSessionWithDiscoveredDevice:discoveredDevice payload:payload newNodeID:@(mNodeId) error:error]; +} + void PairingCommandBridge::PairWithPayload(NSError * __autoreleasing * error) { NSString * onboardingPayload = [NSString stringWithUTF8String:mOnboardingPayload]; diff --git a/examples/darwin-framework-tool/main.mm b/examples/darwin-framework-tool/main.mm index dd191d39e441e1..51325001e59c2e 100644 --- a/examples/darwin-framework-tool/main.mm +++ b/examples/darwin-framework-tool/main.mm @@ -21,6 +21,7 @@ #import "logging/logging.h" #include "commands/common/Commands.h" +#include "commands/discover/Commands.h" #include "commands/interactive/Commands.h" #include "commands/pairing/Commands.h" #include "commands/payload/Commands.h" @@ -37,6 +38,7 @@ int main(int argc, const char * argv[]) Commands commands; registerCommandsPairing(commands); + registerCommandsDiscover(commands); registerCommandsInteractive(commands); registerCommandsPayload(commands); registerClusterOtaSoftwareUpdateProviderInteractive(commands); diff --git a/src/controller/SetUpCodePairer.cpp b/src/controller/SetUpCodePairer.cpp index 27272caebf1fd4..e1ab5e778dd6df 100644 --- a/src/controller/SetUpCodePairer.cpp +++ b/src/controller/SetUpCodePairer.cpp @@ -36,19 +36,10 @@ constexpr uint32_t kDeviceDiscoveredTimeout = CHIP_CONFIG_SETUP_CODE_PAIRER_DISC namespace chip { namespace Controller { -CHIP_ERROR SetUpCodePairer::PairDevice(NodeId remoteId, const char * setUpCode, SetupCodePairerBehaviour commission, - DiscoveryType discoveryType, Optional resolutionData) -{ - VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE); - if (resolutionData.HasValue()) - { - VerifyOrReturnError(discoveryType != DiscoveryType::kAll, CHIP_ERROR_INVALID_ARGUMENT); - } - - SetupPayload payload; - mConnectionType = commission; - mDiscoveryType = discoveryType; +namespace { +CHIP_ERROR GetPayload(const char * setUpCode, SetupPayload & payload) +{ bool isQRCode = strncmp(setUpCode, kQRCodePrefix, strlen(kQRCodePrefix)) == 0; if (isQRCode) { @@ -61,8 +52,33 @@ CHIP_ERROR SetUpCodePairer::PairDevice(NodeId remoteId, const char * setUpCode, VerifyOrReturnError(payload.isValidManualCode(), CHIP_ERROR_INVALID_ARGUMENT); } - mRemoteId = remoteId; - mSetUpPINCode = payload.setUpPINCode; + return CHIP_NO_ERROR; +} +} // namespace + +CHIP_ERROR SetUpCodePairer::PairDevice(NodeId remoteId, const char * setUpCode, SetupCodePairerBehaviour commission, + DiscoveryType discoveryType, Optional resolutionData) +{ + VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE); + + SetupPayload payload; + ReturnErrorOnFailure(GetPayload(setUpCode, payload)); + + if (resolutionData.HasValue()) + { + VerifyOrReturnError(discoveryType != DiscoveryType::kAll, CHIP_ERROR_INVALID_ARGUMENT); + if (mRemoteId == remoteId && mSetUpPINCode == payload.setUpPINCode && mConnectionType == commission && + mDiscoveryType == discoveryType) + { + NotifyCommissionableDeviceDiscovered(resolutionData.Value()); + return CHIP_NO_ERROR; + } + } + + mConnectionType = commission; + mDiscoveryType = discoveryType; + mRemoteId = remoteId; + mSetUpPINCode = payload.setUpPINCode; ResetDiscoveryState(); diff --git a/src/controller/SetUpCodePairer.h b/src/controller/SetUpCodePairer.h index b6a93f4eeedfc8..04177ec313182a 100644 --- a/src/controller/SetUpCodePairer.h +++ b/src/controller/SetUpCodePairer.h @@ -51,6 +51,7 @@ class DeviceCommissioner; class SetUpCodePairerParameters : public RendezvousParameters { public: + SetUpCodePairerParameters() = default; SetUpCodePairerParameters(const Dnssd::CommonResolutionData & data, size_t index); #if CONFIG_NETWORK_LAYER_BLE SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj, bool connected = true); diff --git a/src/darwin/Framework/CHIP/MTRCommissionableBrowser.h b/src/darwin/Framework/CHIP/MTRCommissionableBrowser.h new file mode 100644 index 00000000000000..9b6a639133fcea --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissionableBrowser.h @@ -0,0 +1,32 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol MTRCommissionableBrowserDelegate; + +@interface MTRCommissionableBrowser : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue; +- (BOOL)start; +- (BOOL)stop; +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissionableBrowser.mm b/src/darwin/Framework/CHIP/MTRCommissionableBrowser.mm new file mode 100644 index 00000000000000..3d1359895e23c6 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissionableBrowser.mm @@ -0,0 +1,273 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "MTRCommissionableBrowser.h" +#import "MTRCommissionableBrowserDelegate.h" +#import "MTRCommissionableBrowserResult_Internal.h" +#import "MTRLogging_Internal.h" + +#include +#include +#include + +using namespace chip::Dnssd; +using namespace chip::DeviceLayer; + +#if CONFIG_NETWORK_LAYER_BLE +#include +using namespace chip::Ble; +constexpr const char * kBleKey = "BLE"; +#endif // CONFIG_NETWORK_LAYER_BLE + +@implementation MTRCommissionableBrowserResultInterfaces +@end + +@interface MTRCommissionableBrowserResult () +@property (nonatomic) NSString * serviceName; +@property (nonatomic) NSNumber * vendorId; +@property (nonatomic) NSNumber * productId; +@property (nonatomic) NSNumber * discriminator; +@end + +@implementation MTRCommissionableBrowserResult +@end + +class CommissionableBrowserInternal : public CommissioningResolveDelegate, + public DnssdBrowseDelegate +#if CONFIG_NETWORK_LAYER_BLE + , + public BleScannerDelegate +#endif // CONFIG_NETWORK_LAYER_BLE +{ +public: + CHIP_ERROR Start(id delegate, dispatch_queue_t queue) + { + VerifyOrReturnError(mDelegate == nil, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mDispatchQueue == nil, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mDiscoveredResults == nil, CHIP_ERROR_INCORRECT_STATE); + + mDelegate = delegate; + mDispatchQueue = queue; + mDiscoveredResults = [[NSMutableDictionary alloc] init]; + +#if CONFIG_NETWORK_LAYER_BLE + ReturnErrorOnFailure(PlatformMgrImpl().StartBleScan(this)); +#endif // CONFIG_NETWORK_LAYER_BLE + + ReturnErrorOnFailure(Resolver::Instance().Init(chip::DeviceLayer::UDPEndPointManager())); + + char serviceName[kMaxCommissionableServiceNameSize]; + auto filter = DiscoveryFilterType::kNone; + ReturnErrorOnFailure(MakeServiceTypeName(serviceName, sizeof(serviceName), filter, DiscoveryType::kCommissionableNode)); + + return ChipDnssdBrowse(serviceName, DnssdServiceProtocol::kDnssdProtocolUdp, chip::Inet::IPAddressType::kAny, + chip::Inet::InterfaceId::Null(), this); + } + + CHIP_ERROR Stop() + { + VerifyOrReturnError(mDelegate != nil, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mDispatchQueue != nil, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mDiscoveredResults != nil, CHIP_ERROR_INCORRECT_STATE); + + mDelegate = nil; + mDispatchQueue = nil; + mDiscoveredResults = nil; + +#if CONFIG_NETWORK_LAYER_BLE + ReturnErrorOnFailure(PlatformMgrImpl().StopBleScan()); +#endif // CONFIG_NETWORK_LAYER_BLE + + return ChipDnssdStopBrowse(this); + } + + /////////// CommissioningResolveDelegate Interface ///////// + void OnNodeDiscovered(const DiscoveredNodeData & nodeData) override + { + auto & commissionData = nodeData.commissionData; + auto key = [NSString stringWithUTF8String:commissionData.instanceName]; + if ([mDiscoveredResults objectForKey:key] == nil) { + // It should not happens. + return; + } + + auto result = mDiscoveredResults[key]; + result.serviceName = key; + result.vendorId = @(static_cast(commissionData.vendorId)); + result.productId = @(commissionData.productId); + result.discriminator = @(commissionData.longDiscriminator); + + auto & resolutionData = nodeData.resolutionData; + auto interfaces = result.interfaces; + interfaces[@(resolutionData.interfaceId.GetPlatformInterface())].resolutionData = chip::MakeOptional(resolutionData); + + // Check if any interface for the advertised service has been resolved already. If so, + // we don't need to inform the delegate about it since it already knows that something + // is available. + auto shouldDispatchToDelegate = YES; + for (id interfaceKey in interfaces) { + if (![interfaceKey isEqual:@(resolutionData.interfaceId.GetPlatformInterface())] + && interfaces[interfaceKey].resolutionData.HasValue()) { + shouldDispatchToDelegate = NO; + break; + } + } + + if (!shouldDispatchToDelegate) { + return; + } + + dispatch_async(mDispatchQueue, ^{ + [mDelegate didDiscoverCommissionable:result]; + }); + } + + /////////// DnssdBrowseDelegate Interface ///////// + void OnBrowseAdd(DnssdService service) override + { + auto key = [NSString stringWithUTF8String:service.mName]; + if ([mDiscoveredResults objectForKey:key] == nil) { + mDiscoveredResults[key] = [[MTRCommissionableBrowserResult alloc] init]; + mDiscoveredResults[key].interfaces = [[NSMutableDictionary alloc] init]; + } + + auto interfaces = mDiscoveredResults[key].interfaces; + auto interfaceKey = @(service.mInterface.GetPlatformInterface()); + interfaces[interfaceKey] = [[MTRCommissionableBrowserResultInterfaces alloc] init]; + + LogErrorOnFailure(ChipDnssdResolve(&service, service.mInterface, this)); + } + + void OnBrowseRemove(DnssdService service) override + { + auto key = [NSString stringWithUTF8String:service.mName]; + if ([mDiscoveredResults objectForKey:key] == nil) { + // It should not happens. + return; + } + + auto result = mDiscoveredResults[key]; + auto interfaces = result.interfaces; + auto interfaceKey = @(service.mInterface.GetPlatformInterface()); + + // Check if the interface data has been resolved already, otherwise, just inform the + // back end that we may not need it anymore. + if (!interfaces[interfaceKey].resolutionData.HasValue()) { + ChipDnssdResolveNoLongerNeeded(service.mName); + } + + // Delete the interface placeholder. + interfaces[interfaceKey] = nil; + + // If there is nothing else to resolve for the given instance name, just remove it + // too and informs the delegate that it is gone. + if ([interfaces count] == 0) { + dispatch_async(mDispatchQueue, ^{ + [mDelegate commissionableUnavailable:result]; + }); + + mDiscoveredResults[key] = nil; + } + } + + void OnBrowseStop(CHIP_ERROR error) override + { + for (id key in mDiscoveredResults) { + auto interfaces = mDiscoveredResults[key].interfaces; + for (id interfaceKey in interfaces) { + // Check if the interface data has been resolved already, otherwise, just inform the + // back end that we may not need it anymore. + if (!interfaces[interfaceKey].resolutionData.HasValue()) { + ChipDnssdResolveNoLongerNeeded([key UTF8String]); + } + } + } + } + +#if CONFIG_NETWORK_LAYER_BLE + /////////// BleScannerDelegate Interface ///////// + void OnBleScanAdd(BLE_CONNECTION_OBJECT connObj, const ChipBLEDeviceIdentificationInfo & info) override + { + auto result = [[MTRCommissionableBrowserResult alloc] init]; + result.serviceName = [NSString stringWithUTF8String:kBleKey]; + result.vendorId = @(static_cast(info.GetVendorId())); + result.productId = @(info.GetProductId()); + result.discriminator = @(info.GetDeviceDiscriminator()); + result.params = chip::MakeOptional(chip::Controller::SetUpCodePairerParameters(connObj, false /* connected */)); + + auto key = [NSString stringWithFormat:@"%@", connObj]; + mDiscoveredResults[key] = result; + + dispatch_async(mDispatchQueue, ^{ + [mDelegate didDiscoverCommissionable:result]; + }); + } + + void OnBleScanRemove(BLE_CONNECTION_OBJECT connObj) override + { + auto key = [NSString stringWithFormat:@"%@", connObj]; + if ([mDiscoveredResults objectForKey:key] == nil) { + // It should not happens. + return; + } + + auto result = mDiscoveredResults[key]; + mDiscoveredResults[key] = nil; + + dispatch_async(mDispatchQueue, ^{ + [mDelegate commissionableUnavailable:result]; + }); + } +#endif // CONFIG_NETWORK_LAYER_BLE + +private: + dispatch_queue_t mDispatchQueue; + id mDelegate; + NSMutableDictionary * mDiscoveredResults; +}; + +@interface MTRCommissionableBrowser () +@property (strong, nonatomic) dispatch_queue_t queue; +@property (nonatomic, readonly) id delegate; +@property (unsafe_unretained, nonatomic) CommissionableBrowserInternal browser; +@end + +@implementation MTRCommissionableBrowser +- (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue +{ + if (self = [super init]) { + _delegate = delegate; + _queue = queue; + } + return self; +} + +- (BOOL)start +{ + VerifyOrReturnValue(CHIP_NO_ERROR == _browser.Start(_delegate, _queue), NO); + return YES; +} + +- (BOOL)stop +{ + VerifyOrReturnValue(CHIP_NO_ERROR == _browser.Stop(), NO); + _delegate = nil; + _queue = nil; + return YES; +} + +@end diff --git a/src/darwin/Framework/CHIP/MTRCommissionableBrowserDelegate.h b/src/darwin/Framework/CHIP/MTRCommissionableBrowserDelegate.h new file mode 100644 index 00000000000000..38ed6d3ad8bda6 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissionableBrowserDelegate.h @@ -0,0 +1,37 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class MTRCommissionableBrowserResult; + +NS_ASSUME_NONNULL_BEGIN + +MTR_NEWLY_AVAILABLE +@protocol MTRCommissionableBrowserDelegate +/** + * Tells the delegate the commissionable manager discovered a device while scanning for devices. + */ +- (void)didDiscoverCommissionable:(MTRCommissionableBrowserResult *)device; + +/** + * Tells the delegate a previously discovered device is is no longer available. + */ +- (void)commissionableUnavailable:(MTRCommissionableBrowserResult *)device; +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissionableBrowserResult.h b/src/darwin/Framework/CHIP/MTRCommissionableBrowserResult.h new file mode 100644 index 00000000000000..b83a314aa4c8cd --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissionableBrowserResult.h @@ -0,0 +1,32 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +MTR_NEWLY_AVAILABLE +@interface MTRCommissionableBrowserResult : NSObject + +@property (readonly, nonatomic) NSString * serviceName; +@property (readonly, nonatomic) NSNumber * vendorId; +@property (readonly, nonatomic) NSNumber * productId; +@property (readonly, nonatomic) NSNumber * discriminator; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissionableBrowserResult_Internal.h b/src/darwin/Framework/CHIP/MTRCommissionableBrowserResult_Internal.h new file mode 100644 index 00000000000000..f60f50f74521fd --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissionableBrowserResult_Internal.h @@ -0,0 +1,39 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "MTRCommissionableBrowserResult.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface MTRCommissionableBrowserResultInterfaces : NSObject + +@property (nonatomic, readwrite) chip::Optional resolutionData; + +@end + +@interface MTRCommissionableBrowserResult () + +@property (nonatomic, readwrite) NSMutableDictionary * interfaces; +@property (nonatomic, readwrite) chip::Optional params; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.h b/src/darwin/Framework/CHIP/MTRDeviceController.h index c479442ab22582..84882c65257638 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController.h @@ -17,6 +17,7 @@ #import +#import #import @class MTRBaseDevice; @@ -27,6 +28,7 @@ MTR_DEPRECATED("Please use MTRBaseDevice deviceWithNodeID", ios(16.1, 16.4), mac typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NSError * _Nullable error); @class MTRCommissioningParameters; +@class MTRCommissionableBrowserResult; @class MTRSetupPayload; @protocol MTRDevicePairingDelegate; @protocol MTRDeviceControllerDelegate; @@ -84,6 +86,39 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS error:(NSError * __autoreleasing *)error API_AVAILABLE(ios(16.2), macos(13.1), watchos(9.2), tvos(16.2)); +/** + * Set up a commissioning session for a device, using the provided discovered + * result to connect to it. + * + * @param discoveredDevice a previously discovered device. + * @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 the commissioning session establishment can't start at all. + * + * The connection information for the device will be retrieved from the discovered device. + * A device discovered over MDNS will use the discovered IPs/ports, while a device discovered + * over BLE will use the underlying CBPeripheral. + * + * Then a PASE session will be established with the device, unless an error + * occurs. MTRDeviceControllerDelegate will be notified as follows: + * + * * Invalid connection information: onStatusUpdate with MTRCommissioningStatusFailed. + * + * * 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)setupCommissioningSessionWithDiscoveredDevice:(MTRCommissionableBrowserResult *)discoveredDevice + payload:(MTRSetupPayload *)payload + newNodeID:(NSNumber *)newNodeID + error:(NSError * __autoreleasing *)error MTR_NEWLY_AVAILABLE; + /** * Commission the node with the given node ID. The node ID must match the node * ID that was used to set up the commissioning session. @@ -139,6 +174,20 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS - (void)setDeviceControllerDelegate:(id)delegate queue:(dispatch_queue_t)queue API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); +/** + * Start scanning for commissionable devices. + * + * This method will fail if the controller factory is not running. + */ +- (BOOL)startScan:(id)delegate queue:(dispatch_queue_t)queue MTR_NEWLY_AVAILABLE; + +/** + * Stop scanning for commissionable devices. + * + * This method will fail if the controller factory is not running or the scan has not been started. + */ +- (BOOL)stopScan MTR_NEWLY_AVAILABLE; + /** * Return the attestation challenge for the secure session of the device being commissioned. * diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 2f01e499ad55db..5c4ae26c1f92b6 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -17,6 +17,8 @@ #import "MTRDeviceController_Internal.h" #import "MTRBaseDevice_Internal.h" +#import "MTRCommissionableBrowser.h" +#import "MTRCommissionableBrowserResult_Internal.h" #import "MTRCommissioningParameters.h" #import "MTRDeviceControllerDelegateBridge.h" #import "MTRDeviceControllerFactory_Internal.h" @@ -104,6 +106,7 @@ @interface MTRDeviceController () { @property (readonly) MTRDeviceControllerFactory * factory; @property (readonly) NSMutableDictionary * nodeIDToDeviceMap; @property (readonly) os_unfair_lock deviceMapLock; // protects nodeIDToDeviceMap +@property (readonly) MTRCommissionableBrowser * commissionableBrowser; @end @implementation MTRDeviceController @@ -161,6 +164,7 @@ - (void)cleanupAfterStartup [device invalidate]; } [self.nodeIDToDeviceMap removeAllObjects]; + [self stopScan]; [_factory controllerShuttingDown:self]; } @@ -449,6 +453,53 @@ - (BOOL)setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload return [self syncRunOnWorkQueueWithBoolReturnValue:block error:error]; } +- (BOOL)setupCommissioningSessionWithDiscoveredDevice:(MTRCommissionableBrowserResult *)discoveredDevice + payload:(MTRSetupPayload *)payload + newNodeID:(NSNumber *)newNodeID + error:(NSError * __autoreleasing *)error +{ + auto block = ^BOOL { + chip::NodeId nodeId = [newNodeID unsignedLongLongValue]; + self->_operationalCredentialsDelegate->SetDeviceID(nodeId); + + auto errorCode = CHIP_ERROR_INVALID_ARGUMENT; + if (discoveredDevice.params.HasValue()) { + auto params = discoveredDevice.params.Value(); + auto pinCode = static_cast([[payload setupPasscode] unsignedLongValue]); + params.SetSetupPINCode(pinCode); + + errorCode = self.cppCommissioner->EstablishPASEConnection(nodeId, params); + } else { + // 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:nil]; + if (pairingCode == nil) { + pairingCode = [payload manualEntryCode]; + } + if (pairingCode == nil) { + return ![MTRDeviceController checkForError:CHIP_ERROR_INVALID_ARGUMENT logMsg:kErrorSetupCodeGen error:error]; + } + + for (id key in discoveredDevice.interfaces) { + auto resolutionData = discoveredDevice.interfaces[key].resolutionData; + if (!resolutionData.HasValue()) { + continue; + } + + errorCode = self.cppCommissioner->EstablishPASEConnection( + nodeId, [pairingCode UTF8String], chip::Controller::DiscoveryType::kDiscoveryNetworkOnly, resolutionData); + if (CHIP_NO_ERROR != errorCode) { + break; + } + } + } + + return ![MTRDeviceController checkForError:errorCode logMsg:kErrorPairDevice error:error]; + }; + + return [self syncRunOnWorkQueueWithBoolReturnValue:block error:error]; +} + - (BOOL)commissionNodeWithID:(NSNumber *)nodeID commissioningParams:(MTRCommissioningParameters *)commissioningParams error:(NSError * __autoreleasing *)error @@ -535,6 +586,28 @@ - (BOOL)cancelCommissioningForNodeID:(NSNumber *)nodeID error:(NSError * __autor return [self syncRunOnWorkQueueWithBoolReturnValue:block error:error]; } +- (BOOL)startScan:(id)delegate queue:(dispatch_queue_t)queue +{ + auto block = ^BOOL { + self->_commissionableBrowser = [[MTRCommissionableBrowser alloc] initWithDelegate:delegate queue:queue]; + return [self.commissionableBrowser start]; + }; + + return [self syncRunOnWorkQueueWithBoolReturnValue:block error:nil]; +} + +- (BOOL)stopScan +{ + auto block = ^BOOL { + auto commissionableBrowser = self.commissionableBrowser; + VerifyOrReturnValue(commissionableBrowser, NO); + self->_commissionableBrowser = nil; + return [commissionableBrowser stop]; + }; + + return [self syncRunOnWorkQueueWithBoolReturnValue:block error:nil]; +} + - (void)preWarmCommissioningSession { auto block = ^{ diff --git a/src/darwin/Framework/CHIP/Matter.h b/src/darwin/Framework/CHIP/Matter.h index a9da6744c08285..9a5ce73864f2c2 100644 --- a/src/darwin/Framework/CHIP/Matter.h +++ b/src/darwin/Framework/CHIP/Matter.h @@ -29,6 +29,8 @@ #import #import #import +#import +#import #import #import #import diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index d2d7f3ae8d3cd2..0d07b1e07129a1 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -79,6 +79,10 @@ 03F430A7299410C000166449 /* ExamplePersistentStorage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F430A6299410C000166449 /* ExamplePersistentStorage.cpp */; }; 03F430A82994112B00166449 /* editline.c in Sources */ = {isa = PBXBuildFile; fileRef = 0395470B2992DB37006D42A8 /* editline.c */; }; 03F430AA2994113500166449 /* sysunix.c in Sources */ = {isa = PBXBuildFile; fileRef = 03F430A92994113500166449 /* sysunix.c */; }; + 1E4D654E29C208DD00BC3478 /* MTRCommissionableBrowserResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E4D654B29C208DD00BC3478 /* MTRCommissionableBrowserResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4D654F29C208DD00BC3478 /* MTRCommissionableBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E4D654C29C208DD00BC3478 /* MTRCommissionableBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4D655029C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E4D654D29C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4D655229C30A8700BC3478 /* MTRCommissionableBrowser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1E4D655129C30A8700BC3478 /* MTRCommissionableBrowser.mm */; }; 1E5801C328941C050033A199 /* MTRTestOTAProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E748B3828941A44008A1BE8 /* MTRTestOTAProvider.m */; }; 1EC3238D271999E2002A8BF0 /* cluster-objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1EC3238C271999E2002A8BF0 /* cluster-objects.cpp */; }; 1EC4CE5D25CC26E900D7304F /* MTRBaseClusters.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1EC4CE5925CC26E900D7304F /* MTRBaseClusters.mm */; }; @@ -347,6 +351,10 @@ 0395470C2992DB37006D42A8 /* complete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = complete.c; path = repo/src/complete.c; sourceTree = ""; }; 03F430A6299410C000166449 /* ExamplePersistentStorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExamplePersistentStorage.cpp; sourceTree = ""; }; 03F430A92994113500166449 /* sysunix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sysunix.c; path = repo/src/sysunix.c; sourceTree = ""; }; + 1E4D654B29C208DD00BC3478 /* MTRCommissionableBrowserResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRCommissionableBrowserResult.h; sourceTree = ""; }; + 1E4D654C29C208DD00BC3478 /* MTRCommissionableBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRCommissionableBrowser.h; sourceTree = ""; }; + 1E4D654D29C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRCommissionableBrowserDelegate.h; sourceTree = ""; }; + 1E4D655129C30A8700BC3478 /* MTRCommissionableBrowser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCommissionableBrowser.mm; sourceTree = ""; }; 1E748B3828941A44008A1BE8 /* MTRTestOTAProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRTestOTAProvider.m; sourceTree = ""; }; 1E748B3928941A45008A1BE8 /* MTRTestOTAProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRTestOTAProvider.h; sourceTree = ""; }; 1EC3238C271999E2002A8BF0 /* cluster-objects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "cluster-objects.cpp"; path = "../../../../../zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp"; sourceTree = ""; }; @@ -944,6 +952,10 @@ B202528F2459E34F00F97062 /* CHIP */ = { isa = PBXGroup; children = ( + 1E4D655129C30A8700BC3478 /* MTRCommissionableBrowser.mm */, + 1E4D654C29C208DD00BC3478 /* MTRCommissionableBrowser.h */, + 1E4D654D29C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h */, + 1E4D654B29C208DD00BC3478 /* MTRCommissionableBrowserResult.h */, 1E857311265519DE0050A4D9 /* app */, 3D843718294984AF0070D20A /* templates */, 1EC4CE5825CC26AB00D7304F /* zap-generated */, @@ -1216,15 +1228,18 @@ 3DECCB742934C21B00585AEC /* MTRDefines.h in Headers */, 2C5EEEF6268A85C400CAE3D3 /* MTRDeviceConnectionBridge.h in Headers */, 2C8C8FC0253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.h in Headers */, + 1E4D654F29C208DD00BC3478 /* MTRCommissionableBrowser.h in Headers */, 51E4D121291D0EB400C8C535 /* MTRBaseClusterUtils.h in Headers */, 51E51FC0282AD37A00FC978D /* MTRDeviceControllerStartupParams_Internal.h in Headers */, 3DECCB702934AECD00585AEC /* MTRLogging.h in Headers */, + 1E4D654E29C208DD00BC3478 /* MTRCommissionableBrowserResult.h in Headers */, 998F286F26D55EC5001846C6 /* MTRP256KeypairBridge.h in Headers */, 2C222ADF255C811800E446B9 /* MTRBaseDevice_Internal.h in Headers */, 511913FC28C100EF009235E9 /* MTRBaseSubscriptionCallback.h in Headers */, 51E0310027EA20D20083DC9C /* MTRControllerAccessControl.h in Headers */, 3D843713294977000070D20A /* NSDataSpanConversion.h in Headers */, 991DC08B247704DC00C13860 /* MTRLogging_Internal.h in Headers */, + 1E4D655029C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h in Headers */, 7596A84828762783004DAE0E /* MTRAsyncCallbackWorkQueue.h in Headers */, 5A7947E527C0129F00434CF2 /* MTRDeviceController+XPC.h in Headers */, B2E0D7B4245B0B5C003C5B48 /* MTRError_Internal.h in Headers */, @@ -1471,6 +1486,7 @@ 88EBF8CF27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm in Sources */, 5A6FEC9827B5C6AF00F25F42 /* MTRDeviceOverXPC.mm in Sources */, 51431AF927D2973E008A7943 /* MTRIMDispatch.mm in Sources */, + 1E4D655229C30A8700BC3478 /* MTRCommissionableBrowser.mm in Sources */, 51431AFB27D29CA4008A7943 /* ota-provider.cpp in Sources */, 3DECCB722934AFE200585AEC /* MTRLogging.mm in Sources */, 7596A84528762729004DAE0E /* MTRDevice.mm in Sources */, diff --git a/src/lib/dnssd/platform/Dnssd.h b/src/lib/dnssd/platform/Dnssd.h index d2d834d00f7034..778e9bc05f1d9c 100644 --- a/src/lib/dnssd/platform/Dnssd.h +++ b/src/lib/dnssd/platform/Dnssd.h @@ -304,7 +304,7 @@ void ChipDnssdResolveNoLongerNeeded(const char * instanceName); * * @param[in] hostname The hostname the address belongs to. * @param[in] address The address to reconfirm. - * @param[in] interfaceId The interfaceId of the address. + * @param[in] interface The interfaceId of the address. * */ CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress address, chip::Inet::InterfaceId interface);