darwin-framework-tool: Add support for paseonly pairing (#35206)

This includes code-paseonly and by-index-paseonly commands, as as interacting
with devices over PASE by preferring an existing MTRBaseDevice connected over
PASE to creating a new CASE connection when looking up a device by node id.
diff --git a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm
index 97b7c09..47a29f8 100644
--- a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm
+++ b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm
@@ -25,9 +25,10 @@
 
 CHIP_ERROR ModelCommand::RunCommand()
 {
-    MTRDeviceController * commissioner = CurrentCommissioner();
     ChipLogProgress(chipTool, "Sending command to node 0x" ChipLogFormatX64, ChipLogValueX64(mNodeId));
-    auto * device = [MTRBaseDevice deviceWithNodeID:@(mNodeId) controller:commissioner];
+    auto * device = BaseDeviceWithNodeId(mNodeId);
+    VerifyOrReturnError(device != nil, CHIP_ERROR_INCORRECT_STATE);
+
     CHIP_ERROR err = SendCommand(device, mEndPointId);
 
     if (err != CHIP_NO_ERROR) {
diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h
index 6cb580d..9458d30 100644
--- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h
+++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h
@@ -17,6 +17,7 @@
  */
 
 #pragma once
+
 #import <Matter/Matter.h>
 #include <commands/common/Command.h>
 #include <commands/common/CredentialIssuerCommands.h>
@@ -26,8 +27,6 @@
 
 #include "../provider/OTAProviderDelegate.h"
 
-#pragma once
-
 inline constexpr char kIdentityAlpha[] = "alpha";
 inline constexpr char kIdentityBeta[] = "beta";
 inline constexpr char kIdentityGamma[] = "gamma";
@@ -91,6 +90,10 @@
 
     MTRDeviceController * GetCommissioner(const char * identity);
 
+    // Returns the MTRBaseDevice for the specified node ID.
+    // Will utilize an existing PASE connection if the device is being commissioned.
+    MTRBaseDevice * BaseDeviceWithNodeId(chip::NodeId nodeId);
+
     // Will log the given string and given error (as progress if success, error
     // if failure).
     void LogNSError(const char * logString, NSError * error);
diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm
index bb232e3..8b9a5d3 100644
--- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm
+++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm
@@ -195,6 +195,14 @@
 
 MTRDeviceController * CHIPCommandBridge::GetCommissioner(const char * identity) { return mControllers[identity]; }
 
+MTRBaseDevice * CHIPCommandBridge::BaseDeviceWithNodeId(chip::NodeId nodeId)
+{
+    MTRDeviceController * controller = CurrentCommissioner();
+    VerifyOrReturnValue(controller != nil, nil);
+    return [controller deviceBeingCommissionedWithNodeID:@(nodeId) error:nullptr]
+        ?: [MTRBaseDevice deviceWithNodeID:@(nodeId) controller:controller];
+}
+
 void CHIPCommandBridge::StopCommissioners()
 {
     for (auto & pair : mControllers) {
diff --git a/examples/darwin-framework-tool/commands/delay/WaitForCommissioneeCommand.mm b/examples/darwin-framework-tool/commands/delay/WaitForCommissioneeCommand.mm
index 6bc25de..f3c15c9 100644
--- a/examples/darwin-framework-tool/commands/delay/WaitForCommissioneeCommand.mm
+++ b/examples/darwin-framework-tool/commands/delay/WaitForCommissioneeCommand.mm
@@ -22,10 +22,7 @@
 
 CHIP_ERROR WaitForCommissioneeCommand::RunCommand()
 {
-    MTRDeviceController * commissioner = CurrentCommissioner();
-    VerifyOrReturnError(nil != commissioner, CHIP_ERROR_INCORRECT_STATE);
-
-    auto * base_device = [MTRBaseDevice deviceWithNodeID:@(mNodeId) controller:commissioner];
+    auto * base_device = BaseDeviceWithNodeId(mNodeId);
     VerifyOrReturnError(base_device != nil, CHIP_ERROR_INCORRECT_STATE);
 
     if (mExpireExistingSession.ValueOr(true)) {
diff --git a/examples/darwin-framework-tool/commands/pairing/Commands.h b/examples/darwin-framework-tool/commands/pairing/Commands.h
index bc1bccd..4923a55 100644
--- a/examples/darwin-framework-tool/commands/pairing/Commands.h
+++ b/examples/darwin-framework-tool/commands/pairing/Commands.h
@@ -28,38 +28,52 @@
 class PairCode : public PairingCommandBridge
 {
 public:
-    PairCode() : PairingCommandBridge("code", PairingMode::Code, PairingNetworkType::None) {}
+    PairCode() : PairingCommandBridge("code", PairingMode::Code, CommissioningType::NoNetwork) {}
+};
+
+class PairCodePASEOnly : public PairingCommandBridge
+{
+public:
+    PairCodePASEOnly() : PairingCommandBridge("code-paseonly", PairingMode::Code, CommissioningType::None) {}
 };
 
 class PairCodeWifi : public PairingCommandBridge
 {
 public:
-    PairCodeWifi() : PairingCommandBridge("code-wifi", PairingMode::Code, PairingNetworkType::WiFi) {}
+    PairCodeWifi() : PairingCommandBridge("code-wifi", PairingMode::Code, CommissioningType::WiFi) {}
 };
 
 class PairCodeThread : public PairingCommandBridge
 {
 public:
-    PairCodeThread() : PairingCommandBridge("code-thread", PairingMode::Code, PairingNetworkType::Thread) {}
+    PairCodeThread() : PairingCommandBridge("code-thread", PairingMode::Code, CommissioningType::Thread) {}
 };
 
 class PairBleWiFi : public PairingCommandBridge
 {
 public:
-    PairBleWiFi() : PairingCommandBridge("ble-wifi", PairingMode::Ble, PairingNetworkType::WiFi) {}
+    PairBleWiFi() : PairingCommandBridge("ble-wifi", PairingMode::Ble, CommissioningType::WiFi) {}
 };
 
 class PairBleThread : public PairingCommandBridge
 {
 public:
-    PairBleThread() : PairingCommandBridge("ble-thread", PairingMode::Ble, PairingNetworkType::Thread) {}
+    PairBleThread() : PairingCommandBridge("ble-thread", PairingMode::Ble, CommissioningType::Thread) {}
 };
 
 class PairAlreadyDiscoveredByIndex : public PairingCommandBridge
 {
 public:
     PairAlreadyDiscoveredByIndex() :
-        PairingCommandBridge("by-index", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::None)
+        PairingCommandBridge("by-index", PairingMode::AlreadyDiscoveredByIndex, CommissioningType::NoNetwork)
+    {}
+};
+
+class PairAlreadyDiscoveredByIndexPASEOnly : public PairingCommandBridge
+{
+public:
+    PairAlreadyDiscoveredByIndexPASEOnly() :
+        PairingCommandBridge("by-index-paseonly", PairingMode::AlreadyDiscoveredByIndex, CommissioningType::None)
     {}
 };
 
@@ -67,7 +81,7 @@
 {
 public:
     PairAlreadyDiscoveredByIndexWithWiFi() :
-        PairingCommandBridge("by-index-with-wifi", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::WiFi)
+        PairingCommandBridge("by-index-with-wifi", PairingMode::AlreadyDiscoveredByIndex, CommissioningType::WiFi)
     {}
 };
 
@@ -75,14 +89,14 @@
 {
 public:
     PairAlreadyDiscoveredByIndexWithThread() :
-        PairingCommandBridge("by-index-with-thread", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::Thread)
+        PairingCommandBridge("by-index-with-thread", PairingMode::AlreadyDiscoveredByIndex, CommissioningType::Thread)
     {}
 };
 
 class Unpair : public PairingCommandBridge
 {
 public:
-    Unpair() : PairingCommandBridge("unpair", PairingMode::None, PairingNetworkType::None) {}
+    Unpair() : PairingCommandBridge("unpair", PairingMode::Unpair, CommissioningType::None) {}
 };
 
 void registerCommandsPairing(Commands & commands)
@@ -91,11 +105,13 @@
 
     commands_list clusterCommands = {
         make_unique<PairCode>(),
+        make_unique<PairCodePASEOnly>(),
         make_unique<PairCodeWifi>(),
         make_unique<PairCodeThread>(),
         make_unique<PairBleWiFi>(),
         make_unique<PairBleThread>(),
         make_unique<PairAlreadyDiscoveredByIndex>(),
+        make_unique<PairAlreadyDiscoveredByIndexPASEOnly>(),
         make_unique<Unpair>(),
         make_unique<OpenCommissioningWindowCommand>(),
         make_unique<PreWarmCommissioningCommand>(),
diff --git a/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm b/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm
index 52f0fd4..92ff56a 100644
--- a/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm
+++ b/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm
@@ -50,6 +50,11 @@
     }
     ChipLogProgress(chipTool, "Pairing Success");
     ChipLogProgress(chipTool, "PASE establishment successful");
+    if (_params == nil) {
+        _commandBridge->SetCommandExitStatus(nil);
+        return;
+    }
+
     NSError * commissionError;
     [_commissioner commissionNodeWithID:@(_deviceID) commissioningParams:_params error:&commissionError];
     if (commissionError != nil) {
diff --git a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h
index 4ca6c4c..7502ba6 100644
--- a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h
+++ b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.h
@@ -22,15 +22,16 @@
 
 enum class PairingMode
 {
-    None,
+    Unpair,
     Code,
     Ble,
     AlreadyDiscoveredByIndex,
 };
 
-enum class PairingNetworkType
+enum class CommissioningType
 {
-    None,
+    None, // establish PASE only
+    NoNetwork,
     WiFi,
     Thread,
     Ethernet,
@@ -39,27 +40,28 @@
 class PairingCommandBridge : public CHIPCommandBridge
 {
 public:
-    PairingCommandBridge(const char * commandName, PairingMode mode, PairingNetworkType networkType) :
-        CHIPCommandBridge(commandName), mPairingMode(mode), mNetworkType(networkType)
+    PairingCommandBridge(const char * commandName, PairingMode mode, CommissioningType commissioningType) :
+        CHIPCommandBridge(commandName), mPairingMode(mode), mCommissioningType(commissioningType)
     {
         AddArgument("node-id", 0, UINT64_MAX, &mNodeId);
-        switch (networkType)
+        switch (commissioningType)
         {
-        case PairingNetworkType::None:
-        case PairingNetworkType::Ethernet:
+        case CommissioningType::None:
+        case CommissioningType::NoNetwork:
+        case CommissioningType::Ethernet:
             break;
-        case PairingNetworkType::WiFi:
+        case CommissioningType::WiFi:
             AddArgument("ssid", &mSSID);
             AddArgument("password", &mPassword);
             break;
-        case PairingNetworkType::Thread:
+        case CommissioningType::Thread:
             AddArgument("operationalDataset", &mOperationalDataset);
             break;
         }
 
         switch (mode)
         {
-        case PairingMode::None:
+        case PairingMode::Unpair:
             break;
         case PairingMode::Code:
             AddArgument("payload", &mOnboardingPayload);
@@ -74,17 +76,16 @@
             break;
         }
 
-        if (mode != PairingMode::None)
+        if (commissioningType != CommissioningType::None)
         {
             AddArgument("country-code", &mCountryCode,
                         "Country code to use to set the Basic Information cluster's Location attribute");
+            AddArgument("use-device-attestation-delegate", 0, 1, &mUseDeviceAttestationDelegate,
+                        "If true, use a device attestation delegate that always wants to be notified about attestation results.  "
+                        "Defaults to false.");
+            AddArgument("device-attestation-failsafe-time", 0, UINT16_MAX, &mDeviceAttestationFailsafeTime,
+                        "If set, the time to extend the failsafe to before calling the device attestation delegate");
         }
-
-        AddArgument("use-device-attestation-delegate", 0, 1, &mUseDeviceAttestationDelegate,
-                    "If true, use a device attestation delegate that always wants to be notified about attestation results.  "
-                    "Defaults to false.");
-        AddArgument("device-attestation-failsafe-time", 0, UINT16_MAX, &mDeviceAttestationFailsafeTime,
-                    "If set, the time to extend the failsafe to before calling the device attestation delegate");
     }
 
     /////////// CHIPCommandBridge Interface /////////
@@ -99,7 +100,7 @@
     void SetUpDeviceControllerDelegate();
 
     const PairingMode mPairingMode;
-    const PairingNetworkType mNetworkType;
+    const CommissioningType mCommissioningType;
     chip::ByteSpan mOperationalDataset;
     chip::ByteSpan mSSID;
     chip::ByteSpan mPassword;
diff --git a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm
index 2ab95a9..122cb24 100644
--- a/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm
+++ b/examples/darwin-framework-tool/commands/pairing/PairingCommandBridge.mm
@@ -48,40 +48,43 @@
 
 void PairingCommandBridge::SetUpDeviceControllerDelegate()
 {
-    dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.pairing", DISPATCH_QUEUE_SERIAL);
     CHIPToolDeviceControllerDelegate * deviceControllerDelegate = [[CHIPToolDeviceControllerDelegate alloc] init];
-    MTRCommissioningParameters * params = [[MTRCommissioningParameters alloc] init];
-    MTRDeviceController * commissioner = CurrentCommissioner();
-
-    [deviceControllerDelegate setDeviceID:mNodeId];
-    switch (mNetworkType) {
-    case PairingNetworkType::None:
-    case PairingNetworkType::Ethernet:
-        break;
-    case PairingNetworkType::WiFi:
-        [params setWifiSSID:[NSData dataWithBytes:mSSID.data() length:mSSID.size()]];
-        [params setWifiCredentials:[NSData dataWithBytes:mPassword.data() length:mPassword.size()]];
-        break;
-    case PairingNetworkType::Thread:
-        [params setThreadOperationalDataset:[NSData dataWithBytes:mOperationalDataset.data() length:mOperationalDataset.size()]];
-        break;
-    }
-
-    if (mUseDeviceAttestationDelegate.ValueOr(false)) {
-        params.deviceAttestationDelegate = [[NoOpAttestationDelegate alloc] init];
-        if (mDeviceAttestationFailsafeTime.HasValue()) {
-            params.failSafeTimeout = @(mDeviceAttestationFailsafeTime.Value());
-        }
-    }
-
-    if (mCountryCode.HasValue()) {
-        params.countryCode = [NSString stringWithUTF8String:mCountryCode.Value()];
-    }
-
     [deviceControllerDelegate setCommandBridge:this];
-    [deviceControllerDelegate setParams:params];
-    [deviceControllerDelegate setCommissioner:commissioner];
+    [deviceControllerDelegate setDeviceID:mNodeId];
 
+    if (mCommissioningType != CommissioningType::None) {
+        MTRCommissioningParameters * params = [[MTRCommissioningParameters alloc] init];
+        switch (mCommissioningType) {
+        case CommissioningType::None:
+        case CommissioningType::NoNetwork:
+        case CommissioningType::Ethernet:
+            break;
+        case CommissioningType::WiFi:
+            [params setWifiSSID:[NSData dataWithBytes:mSSID.data() length:mSSID.size()]];
+            [params setWifiCredentials:[NSData dataWithBytes:mPassword.data() length:mPassword.size()]];
+            break;
+        case CommissioningType::Thread:
+            [params setThreadOperationalDataset:[NSData dataWithBytes:mOperationalDataset.data() length:mOperationalDataset.size()]];
+            break;
+        }
+
+        if (mUseDeviceAttestationDelegate.ValueOr(false)) {
+            params.deviceAttestationDelegate = [[NoOpAttestationDelegate alloc] init];
+            if (mDeviceAttestationFailsafeTime.HasValue()) {
+                params.failSafeTimeout = @(mDeviceAttestationFailsafeTime.Value());
+            }
+        }
+
+        if (mCountryCode.HasValue()) {
+            params.countryCode = [NSString stringWithUTF8String:mCountryCode.Value()];
+        }
+
+        [deviceControllerDelegate setParams:params];
+    }
+
+    MTRDeviceController * commissioner = CurrentCommissioner();
+    [deviceControllerDelegate setCommissioner:commissioner];
+    dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.pairing", DISPATCH_QUEUE_SERIAL);
     [commissioner setDeviceControllerDelegate:deviceControllerDelegate queue:callbackQueue];
 }
 
@@ -89,7 +92,7 @@
 {
     NSError * error;
     switch (mPairingMode) {
-    case PairingMode::None:
+    case PairingMode::Unpair:
         Unpair();
         break;
     case PairingMode::Code:
@@ -155,8 +158,7 @@
 void PairingCommandBridge::Unpair()
 {
     dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip-tool.command", DISPATCH_QUEUE_SERIAL);
-    MTRDeviceController * commissioner = CurrentCommissioner();
-    auto * device = [MTRBaseDevice deviceWithNodeID:@(mNodeId) controller:commissioner];
+    auto * device = BaseDeviceWithNodeId(mNodeId);
 
     ChipLogProgress(chipTool, "Attempting to unpair device %llu", mNodeId);
     MTRBaseClusterOperationalCredentials * opCredsCluster =