[transport] Add node ID to address mapping (#3673)

* [transport] Add node ID to address mapping

This change adds mechanism to map node ID to its address using mDNS.

Changes Include:
  - Rename mDNS publisher to DiscoveryManager.
  - Implement mDNS resolve in DiscoveryManager.
  - Modify SecureSessionManager and DeviceController to support using
    node ID only.
  - Publish mDNS service entries in linux sample app.
  - Fix Linux platform mDNS implementation bugs.
  - Test nodeID mapping in cirque.

* fix typo
diff --git a/config/standalone/CHIPProjectConfig.h b/config/standalone/CHIPProjectConfig.h
index f2f2f98..148cb2c 100644
--- a/config/standalone/CHIPProjectConfig.h
+++ b/config/standalone/CHIPProjectConfig.h
@@ -67,4 +67,6 @@
 
 #define CHIP_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL 1
 
+#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 1
+
 #endif /* CHIPPROJECTCONFIG_H */
diff --git a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp
index 5be0d51..db8a59a 100644
--- a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp
+++ b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp
@@ -30,7 +30,7 @@
 #include "WiFiWidget.h"
 #include "esp_heap_caps.h"
 #include "esp_log.h"
-#include <lib/mdns/Publisher.h>
+#include <lib/mdns/DiscoveryManager.h>
 #include <support/CodeUtils.h>
 
 extern "C" {
@@ -94,7 +94,7 @@
     {
         ESP_LOGI(TAG, "Server ready at: %s:%d", event->InternetConnectivityChange.address, CHIP_PORT);
         wifiLED.Set(true);
-        publisher.StartPublishDevice();
+        chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice();
     }
     else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost)
     {
@@ -104,7 +104,7 @@
     if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established)
     {
         ESP_LOGI(TAG, "IPv6 Server ready...");
-        publisher.StartPublishDevice();
+        chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice();
     }
     else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost)
     {
diff --git a/examples/all-clusters-app/esp32/main/Globals.cpp b/examples/all-clusters-app/esp32/main/Globals.cpp
index 5f18629..892b6bb 100644
--- a/examples/all-clusters-app/esp32/main/Globals.cpp
+++ b/examples/all-clusters-app/esp32/main/Globals.cpp
@@ -21,5 +21,4 @@
 LEDWidget statusLED2;
 BluetoothWidget bluetoothLED;
 WiFiWidget wifiLED;
-chip::Protocols::Mdns::Publisher publisher;
 const chip::NodeId kLocalNodeId = 12344321;
diff --git a/examples/all-clusters-app/esp32/main/include/Globals.h b/examples/all-clusters-app/esp32/main/include/Globals.h
index c691654..bee1e90 100644
--- a/examples/all-clusters-app/esp32/main/include/Globals.h
+++ b/examples/all-clusters-app/esp32/main/include/Globals.h
@@ -20,12 +20,10 @@
 #include "BluetoothWidget.h"
 #include "LEDWidget.h"
 #include "WiFiWidget.h"
-#include "lib/mdns/Publisher.h"
 #include "transport/raw/MessageHeader.h"
 
 extern LEDWidget statusLED1;
 extern LEDWidget statusLED2;
 extern BluetoothWidget bluetoothLED;
 extern WiFiWidget wifiLED;
-extern chip::Protocols::Mdns::Publisher publisher;
 extern const chip::NodeId kLocalNodeId;
diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp
index 0993e68..25e4e1c 100644
--- a/examples/all-clusters-app/esp32/main/main.cpp
+++ b/examples/all-clusters-app/esp32/main/main.cpp
@@ -45,7 +45,6 @@
 #include <vector>
 
 #include <crypto/CHIPCryptoPAL.h>
-#include <lib/mdns/Publisher.h>
 #include <platform/CHIPDeviceLayer.h>
 #include <setup_payload/ManualSetupPayloadGenerator.h>
 #include <setup_payload/QRCodeSetupPayloadGenerator.h>
@@ -92,15 +91,6 @@
 static DeviceCallbacks EchoCallbacks;
 RendezvousDeviceDelegate * rendezvousDelegate = nullptr;
 
-namespace chip {
-namespace DeviceLayer {
-namespace Internal {
-const uint64_t TestDeviceId = kLocalNodeId; // For chip::DeviceLayer::GetDeviceId
-const uint64_t TestFabricId = 0;            // For chip::DeviceLayer::GetFabricId
-} // namespace Internal
-} // namespace DeviceLayer
-} // namespace chip
-
 namespace {
 
 #if CONFIG_DEVICE_TYPE_M5STACK
@@ -529,8 +519,6 @@
     }
 
     SetupPretendDevices();
-    publisher.Init();
-    publisher.StopPublishDevice();
 
     statusLED1.Init(STATUS_LED_GPIO_NUM);
     // Our second LED doesn't map to any physical LEDs so far, just to virtual
diff --git a/examples/chip-tool/Dockerfile b/examples/chip-tool/Dockerfile
index 96a3f15..c585f8a 100644
--- a/examples/chip-tool/Dockerfile
+++ b/examples/chip-tool/Dockerfile
@@ -16,7 +16,7 @@
 #
 
 from generic_node_image
-RUN apt-get install -y libglib2.0
+RUN apt-get install -y libglib2.0 avahi-daemon libavahi-client3
 COPY out/debug/chip-tool /usr/bin/
 COPY entrypoint.sh /
 
diff --git a/examples/chip-tool/commands/common/NetworkCommand.h b/examples/chip-tool/commands/common/NetworkCommand.h
index 5ba729c..10893b1 100644
--- a/examples/chip-tool/commands/common/NetworkCommand.h
+++ b/examples/chip-tool/commands/common/NetworkCommand.h
@@ -30,7 +30,9 @@
 class NetworkCommand : public Command
 {
 public:
-    NetworkCommand(const char * commandName, NetworkType type) : Command(commandName), mNetworkType(type) {}
+    NetworkCommand(const char * commandName, NetworkType type) :
+        Command(commandName), mNetworkType(type), mRemoteAddr{ IPAddress::Any, INET_NULL_INTERFACEID }
+    {}
 
     void AddArguments()
     {
diff --git a/examples/chip-tool/entrypoint.sh b/examples/chip-tool/entrypoint.sh
index b31c5bd..2f0bfb3 100755
--- a/examples/chip-tool/entrypoint.sh
+++ b/examples/chip-tool/entrypoint.sh
@@ -2,6 +2,7 @@
 
 service dbus start
 sleep 1
+service avahi-daemon start
 /usr/sbin/otbr-agent -I wpan0 spinel+hdlc+uart:///dev/ttyUSB0 &
 sleep 1
 ot-ctl panid 0x1234
diff --git a/examples/common/chip-app-server/BUILD.gn b/examples/common/chip-app-server/BUILD.gn
index 9028d41..1f9ed65 100644
--- a/examples/common/chip-app-server/BUILD.gn
+++ b/examples/common/chip-app-server/BUILD.gn
@@ -21,11 +21,6 @@
   ]
 }
 
-declare_args() {
-  # By pass provision and secure session
-  bypass_rendezvous = false
-}
-
 static_library("chip-app-server") {
   output_name = "chip-app-server"
 
@@ -39,11 +34,10 @@
     "Server.cpp",
   ]
 
-  if (bypass_rendezvous) {
-    defines = [ "BYPASS_RENDEZVOUS=1" ]
-  }
-
-  deps = [ "${chip_root}/src/lib" ]
+  deps = [
+    "${chip_root}/src/lib",
+    "${chip_root}/src/lib/mdns",
+  ]
 
   public_configs = [ ":includes" ]
 
diff --git a/examples/common/chip-app-server/RendezvousServer.cpp b/examples/common/chip-app-server/RendezvousServer.cpp
index 03d8e4c..a117908 100644
--- a/examples/common/chip-app-server/RendezvousServer.cpp
+++ b/examples/common/chip-app-server/RendezvousServer.cpp
@@ -26,6 +26,7 @@
 #if CHIP_ENABLE_OPENTHREAD
 #include <platform/ThreadStackManager.h>
 #endif
+#include <lib/mdns/DiscoveryManager.h>
 
 using namespace ::chip::Inet;
 using namespace ::chip::Transport;
@@ -72,6 +73,8 @@
         break;
     case RendezvousSessionDelegate::NetworkProvisioningSuccess:
         ChipLogProgress(AppServer, "Device was assigned network credentials");
+        chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice();
+
         break;
     default:
         break;
diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp
index a651db2..5f02f51 100644
--- a/examples/common/chip-app-server/Server.cpp
+++ b/examples/common/chip-app-server/Server.cpp
@@ -25,6 +25,7 @@
 #include <inet/IPAddress.h>
 #include <inet/InetError.h>
 #include <inet/InetLayer.h>
+#include <lib/mdns/DiscoveryManager.h>
 #include <platform/CHIPDeviceLayer.h>
 #include <support/CodeUtils.h>
 #include <support/ErrorStr.h>
@@ -109,7 +110,7 @@
 
     // This flag is used to bypass BLE in the cirque test
     // Only in the cirque test this is enabled with --args='bypass_rendezvous=true'
-#ifndef BYPASS_RENDEZVOUS
+#ifndef CHIP_BYPASS_RENDEZVOUS
     {
         RendezvousParameters params;
         uint32_t pinCode;
@@ -126,6 +127,7 @@
     SuccessOrExit(err);
 
     gSessions.SetDelegate(&gCallbacks);
+    chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice(chip::Inet::kIPAddressType_IPv6);
 
 exit:
     if (err != CHIP_NO_ERROR)
diff --git a/examples/lighting-app/linux/Dockerfile b/examples/lighting-app/linux/Dockerfile
index c2e3a20..4fa5e8b 100644
--- a/examples/lighting-app/linux/Dockerfile
+++ b/examples/lighting-app/linux/Dockerfile
@@ -16,7 +16,7 @@
 #
 
 from generic_node_image
-RUN apt-get install -y libglib2.0
+RUN apt-get install -y libglib2.0 avahi-daemon libavahi-client3
 COPY out/debug/chip-tool-server /usr/bin/
 COPY entrypoint.sh /
 
diff --git a/examples/lighting-app/linux/entrypoint.sh b/examples/lighting-app/linux/entrypoint.sh
index ba0fec3..04dfa2c 100755
--- a/examples/lighting-app/linux/entrypoint.sh
+++ b/examples/lighting-app/linux/entrypoint.sh
@@ -2,6 +2,7 @@
 
 service dbus start
 sleep 1
+service avahi-daemon start
 /usr/sbin/otbr-agent -I wpan0 spinel+hdlc+uart:///dev/ttyUSB0 &
 sleep 1
 ot-ctl panid 0x1234
diff --git a/examples/temperature-measurement-app/esp32/main/main.cpp b/examples/temperature-measurement-app/esp32/main/main.cpp
index 13999ed..0e3bead 100644
--- a/examples/temperature-measurement-app/esp32/main/main.cpp
+++ b/examples/temperature-measurement-app/esp32/main/main.cpp
@@ -55,14 +55,6 @@
 
 static DeviceCallbacks EchoCallbacks;
 RendezvousDeviceDelegate * rendezvousDelegate = nullptr;
-namespace chip {
-namespace DeviceLayer {
-namespace Internal {
-const uint64_t TestDeviceId = kLocalNodeId; // For chip::DeviceLayer::GetDeviceId
-const uint64_t TestFabricId = 0;            // For chip::DeviceLayer::GetFabricId
-} // namespace Internal
-} // namespace DeviceLayer
-} // namespace chip
 
 namespace {
 
diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp
index 45fb319..ab1471b 100644
--- a/src/controller/CHIPDeviceController.cpp
+++ b/src/controller/CHIPDeviceController.cpp
@@ -286,7 +286,6 @@
     CHIP_ERROR err = CHIP_NO_ERROR;
 
     VerifyOrExit(mSecurePairingSession != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
-    VerifyOrExit(mDeviceAddr != IPAddress::Any, err = CHIP_ERROR_INCORRECT_STATE);
 
     mSessionManager = chip::Platform::New<SecureSessionMgr<Transport::UDP>>();
 
@@ -304,7 +303,10 @@
 
     mConState = kConnectionState_SecureConnected;
 
-    SendCachedPackets();
+    if (mDeviceAddr != IPAddress::Any)
+    {
+        SendCachedPackets();
+    } // else wait for mdns discovery
 
 exit:
 
@@ -527,7 +529,7 @@
 
         trySessionResumption = false;
 
-        if (mConState == kConnectionState_SecureConnecting)
+        if (mDeviceAddr == IPAddress::Any || mConState == kConnectionState_SecureConnecting)
         {
             // Cache the packet while connection is being established
             ExitNow(err = CachePacket(buffer));
@@ -617,6 +619,14 @@
 
 void ChipDeviceController::OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) {}
 
+void ChipDeviceController::OnAddressResolved(CHIP_ERROR error, NodeId nodeId, SecureSessionMgrBase * mgr)
+{
+    if (error == CHIP_NO_ERROR && nodeId == mSecurePairingSession->GetPeerNodeId() && mDeviceAddr == IPAddress::Any)
+    {
+        SendCachedPackets();
+    }
+}
+
 void ChipDeviceController::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
                                              Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
                                              SecureSessionMgrBase * mgr)
diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h
index c0611c3..a115288 100644
--- a/src/controller/CHIPDeviceController.h
+++ b/src/controller/CHIPDeviceController.h
@@ -241,6 +241,8 @@
 
     void OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) override;
 
+    void OnAddressResolved(CHIP_ERROR error, NodeId nodeId, SecureSessionMgrBase * mgr) override;
+
     //////////// RendezvousSessionDelegate Implementation ///////////////
     void OnRendezvousError(CHIP_ERROR err) override;
     void OnRendezvousComplete() override;
diff --git a/src/include/platform/CHIPDeviceLayer.h b/src/include/platform/CHIPDeviceLayer.h
index b3333c9..434998b 100644
--- a/src/include/platform/CHIPDeviceLayer.h
+++ b/src/include/platform/CHIPDeviceLayer.h
@@ -20,6 +20,8 @@
 
 #include <platform/CHIPDeviceConfig.h>
 
+#if !CHIP_DEVICE_LAYER_NONE
+
 #include <ble/BleLayer.h>
 #include <core/CHIPCore.h>
 #include <platform/CHIPDeviceError.h>
@@ -44,3 +46,5 @@
 
 } // namespace DeviceLayer
 } // namespace chip
+
+#endif // !CHIP_DEVICE_LAYER_NONE
diff --git a/src/include/platform/internal/GenericConfigurationManagerImpl.cpp b/src/include/platform/internal/GenericConfigurationManagerImpl.cpp
index 51301da..34ddf8e 100644
--- a/src/include/platform/internal/GenericConfigurationManagerImpl.cpp
+++ b/src/include/platform/internal/GenericConfigurationManagerImpl.cpp
@@ -165,7 +165,7 @@
     err = Impl()->ReadConfigValue(ImplClass::kConfigKey_MfrDeviceId, deviceId);
 
 #if CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
-    if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND)
+    if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || err == CHIP_ERROR_KEY_NOT_FOUND)
     {
         deviceId = TestDeviceId;
         err      = CHIP_NO_ERROR;
@@ -610,7 +610,7 @@
     CHIP_ERROR err = Impl()->ReadConfigValue(ImplClass::kConfigKey_FabricId, fabricId);
 
 #if CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
-    if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND)
+    if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || err == CHIP_ERROR_KEY_NOT_FOUND)
     {
         fabricId = TestFabricId;
         err      = CHIP_NO_ERROR;
@@ -856,6 +856,10 @@
 template <class ImplClass>
 bool GenericConfigurationManagerImpl<ImplClass>::_IsFullyProvisioned()
 {
+#if CHIP_BYPASS_RENDEZVOUS
+    return true;
+#else // CHIP_BYPASS_RENDEZVOUS
+
     return
 #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
         ConnectivityMgr().IsWiFiStationProvisioned() &&
@@ -869,6 +873,7 @@
         // TODO: Add checks regarding fabric membership (IsMemberOfFabric()) and account pairing (IsPairedToAccount()),
         // when functionalities will be implemented.
         true;
+#endif // CHIP_BYPASS_RENDEZVOUS
 }
 
 template <class ImplClass>
diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
index 5a54bef..520a206 100644
--- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
+++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
@@ -142,7 +142,7 @@
     }
 #endif // !(CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK)
 #if CHIP_ENABLE_MDNS
-    chip::Protocols::Mdns::UpdateMdnsDataset(mReadSet, mWriteSet, mErrorSet, mMaxFd, mNextTimeout);
+    chip::Mdns::UpdateMdnsDataset(mReadSet, mWriteSet, mErrorSet, mMaxFd, mNextTimeout);
 #endif
 }
 
@@ -179,7 +179,7 @@
 
     ProcessDeviceEvents();
 #if CHIP_ENABLE_MDNS
-    chip::Protocols::Mdns::ProcessMdns(mReadSet, mWriteSet, mErrorSet);
+    chip::Mdns::ProcessMdns(mReadSet, mWriteSet, mErrorSet);
 #endif
 }
 
diff --git a/src/lib/mdns/BUILD.gn b/src/lib/mdns/BUILD.gn
index 3785e68..60424fc 100644
--- a/src/lib/mdns/BUILD.gn
+++ b/src/lib/mdns/BUILD.gn
@@ -26,7 +26,7 @@
   ]
 
   sources = [
-    "Publisher.cpp",
-    "Publisher.h",
+    "DiscoveryManager.cpp",
+    "DiscoveryManager.h",
   ]
 }
diff --git a/src/lib/mdns/DiscoveryManager.cpp b/src/lib/mdns/DiscoveryManager.cpp
new file mode 100644
index 0000000..ab8ea33
--- /dev/null
+++ b/src/lib/mdns/DiscoveryManager.cpp
@@ -0,0 +1,335 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+#include "DiscoveryManager.h"
+
+#include <inttypes.h>
+
+#include "lib/mdns/platform/Mdns.h"
+#include "lib/support/logging/CHIPLogging.h"
+#include "platform/CHIPDeviceConfig.h"
+#include "platform/CHIPDeviceLayer.h"
+#include "support/CodeUtils.h"
+#include "support/ErrorStr.h"
+#include "support/RandUtils.h"
+
+#if CHIP_ENABLE_MDNS
+
+namespace {
+
+uint8_t HexToInt(char c)
+{
+    if ('0' <= c && c <= '9')
+    {
+        return static_cast<uint8_t>(c - '0');
+    }
+    else if ('a' <= c && c <= 'f')
+    {
+        return static_cast<uint8_t>(0x0a + c - 'a');
+    }
+    else if ('A' <= c && c <= 'F')
+    {
+        return static_cast<uint8_t>(0x0a + c - 'A');
+    }
+
+    return UINT8_MAX;
+}
+
+constexpr uint64_t kUndefinedNodeId = 0;
+
+} // namespace
+#endif
+
+namespace chip {
+namespace Mdns {
+
+DiscoveryManager DiscoveryManager::sManager;
+
+CHIP_ERROR DiscoveryManager::Init()
+{
+#if CHIP_ENABLE_MDNS
+    CHIP_ERROR error;
+
+    mUnprovisionedInstanceName = GetRandU64();
+    SuccessOrExit(error = ChipMdnsInit(HandleMdnsInit, HandleMdnsError, this));
+exit:
+    return error;
+#else
+    return CHIP_NO_ERROR;
+#endif // CHIP_ENABLE_MDNS
+}
+
+void DiscoveryManager::HandleMdnsInit(void * context, CHIP_ERROR initError)
+{
+#if CHIP_ENABLE_MDNS
+    DiscoveryManager * publisher = static_cast<DiscoveryManager *>(context);
+
+    if (initError == CHIP_NO_ERROR)
+    {
+        publisher->mMdnsInitialized = true;
+    }
+    else
+    {
+        ChipLogError(Discovery, "mDNS initialization failed with %s", chip::ErrorStr(initError));
+    }
+#endif // CHIP_ENABLE_MDNS
+}
+
+void DiscoveryManager::HandleMdnsError(void * context, CHIP_ERROR error)
+{
+#if CHIP_ENABLE_MDNS
+    DiscoveryManager * publisher = static_cast<DiscoveryManager *>(context);
+    if (error == CHIP_ERROR_FORCED_RESET && publisher->mIsPublishing)
+    {
+        publisher->StartPublishDevice();
+    }
+    else
+    {
+        ChipLogError(Discovery, "mDNS error: %s", chip::ErrorStr(error));
+    }
+#endif // CHIP_ENABLE_MDNS
+}
+
+CHIP_ERROR DiscoveryManager::StartPublishDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface)
+{
+#if CHIP_ENABLE_MDNS
+    CHIP_ERROR error;
+
+    // TODO: after multi-admin is decided we may need to publish both _chipc._udp and _chip._tcp service
+    if (!mIsPublishing)
+    {
+        SuccessOrExit(error = SetupHostname());
+    }
+    else if (chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned() != mIsPublishingProvisionedDevice)
+    {
+        SuccessOrExit(error = StopPublishDevice());
+        // Set hostname again in case the mac address changes when shifting from soft-AP to station
+        SuccessOrExit(error = SetupHostname());
+    }
+    mIsPublishingProvisionedDevice = chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned();
+
+    if (mIsPublishingProvisionedDevice)
+    {
+        error = PublishProvisionedDevice(addressType, interface);
+    }
+    else
+    {
+        error = PublishUnprovisionedDevice(addressType, interface);
+    }
+    mIsPublishing = true;
+exit:
+    return error;
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif // CHIP_ENABLE_MDNS
+}
+
+CHIP_ERROR DiscoveryManager::SetupHostname()
+{
+#if CHIP_ENABLE_MDNS
+    uint8_t mac[6];    // 6 byte wifi mac
+    char hostname[13]; // Hostname will be the hex representation of mac.
+    CHIP_ERROR error;
+
+    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetPrimaryWiFiMACAddress(mac));
+    for (size_t i = 0; i < sizeof(mac); i++)
+    {
+        snprintf(&hostname[i * 2], sizeof(hostname) - i * 2, "%02X", mac[i]);
+    }
+    SuccessOrExit(error = ChipMdnsSetHostname(hostname));
+
+exit:
+    return error;
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif // CHIP_ENABLE_MDNS
+}
+
+CHIP_ERROR DiscoveryManager::PublishUnprovisionedDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface)
+{
+#if CHIP_ENABLE_MDNS
+    uint8_t mac[6]; // 6 byte wifi mac
+    CHIP_ERROR error = CHIP_NO_ERROR;
+    MdnsService service;
+    uint16_t discriminator;
+    uint16_t vendorID;
+    uint16_t productID;
+    char discriminatorBuf[5];  // hex representation of 16-bit discriminator
+    char vendorProductBuf[10]; // "FFFF+FFFF"
+    // TODO: The text entry will be updated in the spec, update accordingly.
+    TextEntry entries[2] = {
+        { "D", nullptr, 0 },
+        { "VP", nullptr, 0 },
+    };
+
+    VerifyOrExit(mMdnsInitialized, error = CHIP_ERROR_INCORRECT_STATE);
+    ChipLogProgress(Discovery, "setup mdns service");
+    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetSetupDiscriminator(discriminator));
+    snprintf(service.mName, sizeof(service.mName), "%016" PRIX64, mUnprovisionedInstanceName);
+    strncpy(service.mType, "_chipc", sizeof(service.mType));
+    service.mProtocol = MdnsServiceProtocol::kMdnsProtocolUdp;
+    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetVendorId(vendorID));
+    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetProductId(productID));
+    snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04X", discriminator);
+    snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%04X+%04X", vendorID, productID);
+    entries[0].mData       = reinterpret_cast<const uint8_t *>(discriminatorBuf);
+    entries[0].mDataSize   = strnlen(discriminatorBuf, sizeof(discriminatorBuf));
+    entries[1].mData       = reinterpret_cast<const uint8_t *>(vendorProductBuf);
+    entries[1].mDataSize   = strnlen(discriminatorBuf, sizeof(vendorProductBuf));
+    service.mTextEntryies  = entries;
+    service.mTextEntrySize = sizeof(entries) / sizeof(TextEntry);
+    service.mPort          = CHIP_PORT;
+    service.mInterface     = interface;
+    service.mAddressType   = addressType;
+    error                  = ChipMdnsPublishService(&service);
+
+exit:
+    return error;
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif // CHIP_ENABLE_MDNS
+}
+
+CHIP_ERROR DiscoveryManager::PublishProvisionedDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface)
+{
+#if CHIP_ENABLE_MDNS
+    uint64_t deviceId;
+    uint64_t fabricId;
+    MdnsService service;
+    CHIP_ERROR error = CHIP_NO_ERROR;
+
+    // TODO: There may be multilple device/fabrid ids after multi-admin.
+    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetFabricId(fabricId));
+    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetDeviceId(deviceId));
+    snprintf(service.mName, sizeof(service.mName), "%" PRIX64 "-%" PRIX64, deviceId, fabricId);
+    strncpy(service.mType, "_chip", sizeof(service.mType));
+    service.mProtocol      = MdnsServiceProtocol::kMdnsProtocolTcp;
+    service.mPort          = CHIP_PORT;
+    service.mTextEntryies  = nullptr;
+    service.mTextEntrySize = 0;
+    service.mInterface     = interface;
+    service.mAddressType   = addressType;
+    error                  = ChipMdnsPublishService(&service);
+
+exit:
+    return error;
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif // CHIP_ENABLE_MDNS
+}
+
+CHIP_ERROR DiscoveryManager::StopPublishDevice()
+{
+#if CHIP_ENABLE_MDNS
+    mIsPublishing = false;
+    return ChipMdnsStopPublish();
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif // CHIP_ENABLE_MDNS
+}
+
+CHIP_ERROR DiscoveryManager::RegisterResolveDelegate(ResolveDelegate * delegate)
+{
+    if (mResolveDelegate != nullptr)
+    {
+        return CHIP_ERROR_INCORRECT_STATE;
+    }
+    else
+    {
+        mResolveDelegate = delegate;
+        return CHIP_NO_ERROR;
+    }
+}
+
+CHIP_ERROR DiscoveryManager::ResolveNodeId(uint64_t nodeId, uint64_t fabricId, Inet::IPAddressType type)
+{
+#if CHIP_ENABLE_MDNS
+    MdnsService service;
+
+    snprintf(service.mName, sizeof(service.mName), "%" PRIX64 "-%" PRIX64, nodeId, fabricId);
+    strncpy(service.mType, "_chip", sizeof(service.mType));
+    service.mProtocol    = MdnsServiceProtocol::kMdnsProtocolTcp;
+    service.mAddressType = type;
+    return ChipMdnsResolve(&service, INET_NULL_INTERFACEID, HandleNodeIdResolve, this);
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif // CHIP_ENABLE_MDNS
+}
+
+void DiscoveryManager::HandleNodeIdResolve(void * context, MdnsService * result, CHIP_ERROR error)
+{
+#if CHIP_ENABLE_MDNS
+    DiscoveryManager * mgr = static_cast<DiscoveryManager *>(context);
+
+    if (mgr->mResolveDelegate == nullptr)
+    {
+        return;
+    }
+    if (error != CHIP_NO_ERROR)
+    {
+        ChipLogError(Discovery, "Node ID resolved failed with %s", chip::ErrorStr(error));
+        mgr->mResolveDelegate->HandleNodeIdResolve(error, kUndefinedNodeId, MdnsService{});
+    }
+    else if (result == nullptr)
+    {
+        ChipLogError(Discovery, "Node ID resolve not found");
+        mgr->mResolveDelegate->HandleNodeIdResolve(CHIP_ERROR_UNKNOWN_RESOURCE_ID, kUndefinedNodeId, MdnsService{});
+    }
+    else
+    {
+        // Parse '%x-%x' from the name
+        uint64_t nodeId       = 0;
+        bool deliminatorFound = false;
+
+        for (size_t i = 0; i < sizeof(result->mName) && result->mName[i] != 0; i++)
+        {
+            if (result->mName[i] == '-')
+            {
+                deliminatorFound = true;
+                break;
+            }
+            else
+            {
+                uint8_t val = HexToInt(result->mName[i]);
+
+                if (val == UINT8_MAX)
+                {
+                    break;
+                }
+                else
+                {
+                    nodeId = nodeId * 16 + val;
+                }
+            }
+        }
+
+        if (deliminatorFound)
+        {
+            ChipLogProgress(Discovery, "Node ID resolved for %" PRIX64, nodeId);
+            mgr->mResolveDelegate->HandleNodeIdResolve(error, nodeId, *result);
+        }
+        else
+        {
+            ChipLogProgress(Discovery, "Invalid service entry from node %" PRIX64, nodeId);
+            mgr->mResolveDelegate->HandleNodeIdResolve(error, kUndefinedNodeId, *result);
+        }
+    }
+#endif // CHIP_ENABLE_MDNS
+}
+
+} // namespace Mdns
+} // namespace chip
diff --git a/src/lib/mdns/DiscoveryManager.h b/src/lib/mdns/DiscoveryManager.h
new file mode 100644
index 0000000..823c33b
--- /dev/null
+++ b/src/lib/mdns/DiscoveryManager.h
@@ -0,0 +1,103 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+#pragma once
+
+#include "core/CHIPError.h"
+#include "inet/InetInterface.h"
+#include "lib/mdns/platform/Mdns.h"
+#include "platform/CHIPDeviceConfig.h"
+
+namespace chip {
+namespace Mdns {
+
+class ResolveDelegate
+{
+public:
+    virtual void HandleNodeIdResolve(CHIP_ERROR error, uint64_t nodeId, const MdnsService & address) = 0;
+    virtual ~ResolveDelegate() {}
+};
+
+class DiscoveryManager
+{
+public:
+    /**
+     * This method initializes the publisher.
+     *
+     */
+    CHIP_ERROR Init();
+
+    /**
+     * This method publishes the device on mDNS.
+     *
+     * This function will fetch device name and other information and publish them
+     * via mDNS. If device meta data has changed, you can call this function again
+     * to update the information.
+     *
+     * @param[in] interface   The interface to send mDNS multicast.
+     *
+     */
+    CHIP_ERROR StartPublishDevice(chip::Inet::IPAddressType addressType = chip::Inet::kIPAddressType_Any,
+                                  chip::Inet::InterfaceId interface     = INET_NULL_INTERFACEID);
+
+    /**
+     * This function stops publishing the device on mDNS.
+     *
+     */
+    CHIP_ERROR StopPublishDevice();
+
+    /**
+     * This function registers the delegate to handle node id resolve results.
+     *
+     */
+    CHIP_ERROR RegisterResolveDelegate(ResolveDelegate * delegate);
+
+    /**
+     * This function resolves a node id to its address.
+     *
+     */
+    CHIP_ERROR ResolveNodeId(uint64_t nodeId, uint64_t fabricId, chip::Inet::IPAddressType type = chip::Inet::kIPAddressType_Any);
+
+    static DiscoveryManager & GetInstance() { return sManager; }
+
+private:
+    DiscoveryManager() = default;
+
+    DiscoveryManager(const DiscoveryManager &) = delete;
+    DiscoveryManager & operator=(const DiscoveryManager &) = delete;
+
+    CHIP_ERROR PublishUnprovisionedDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface);
+    CHIP_ERROR PublishProvisionedDevice(chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface);
+    CHIP_ERROR SetupHostname();
+
+    static void HandleNodeIdResolve(void * context, MdnsService * result, CHIP_ERROR error);
+    static void HandleMdnsInit(void * context, CHIP_ERROR initError);
+    static void HandleMdnsError(void * context, CHIP_ERROR initError);
+
+#if CHIP_ENABLE_MDNS
+    uint64_t mUnprovisionedInstanceName;
+    bool mMdnsInitialized               = false;
+    bool mIsPublishingProvisionedDevice = false;
+    bool mIsPublishing                  = false;
+#endif // CHIP_ENABLE_MDNS
+    ResolveDelegate * mResolveDelegate = nullptr;
+
+    static DiscoveryManager sManager;
+};
+
+} // namespace Mdns
+} // namespace chip
diff --git a/src/lib/mdns/Publisher.cpp b/src/lib/mdns/Publisher.cpp
deleted file mode 100644
index f39fb60..0000000
--- a/src/lib/mdns/Publisher.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- *
- *    Copyright (c) 2020 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.
- */
-
-#include "Publisher.h"
-
-#include <inttypes.h>
-
-#include "lib/mdns/platform/Mdns.h"
-#include "lib/support/logging/CHIPLogging.h"
-#include "platform/CHIPDeviceBuildConfig.h"
-#include "platform/CHIPDeviceLayer.h"
-#include "support/CodeUtils.h"
-#include "support/ErrorStr.h"
-#include "support/RandUtils.h"
-
-namespace chip {
-namespace Protocols {
-namespace Mdns {
-
-CHIP_ERROR Publisher::Init()
-{
-    CHIP_ERROR error;
-
-    mUnprovisionedInstanceName = GetRandU64();
-    SuccessOrExit(error = ChipMdnsInit(HandleMdnsInit, HandleMdnsError, this));
-    SuccessOrExit(error = SetupHostname());
-exit:
-    return error;
-}
-
-void Publisher::HandleMdnsInit(void * context, CHIP_ERROR initError)
-{
-    Publisher * publisher = static_cast<Publisher *>(context);
-
-    if (initError == CHIP_NO_ERROR)
-    {
-        publisher->mInitialized = true;
-    }
-    else
-    {
-        ChipLogError(Discovery, "mDNS initialization failed with %s", chip::ErrorStr(initError));
-    }
-}
-
-void Publisher::HandleMdnsError(void * context, CHIP_ERROR initError)
-{
-    ChipLogError(Discovery, "mDNS error: %s", chip::ErrorStr(initError));
-}
-
-CHIP_ERROR Publisher::StartPublishDevice(chip::Inet::InterfaceId interface)
-{
-    CHIP_ERROR error;
-
-    // TODO: after multi-admin is decided we may need to publish both _chipc._udp and _chip._tcp service
-    if (chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned() != mIsPublishingProvisionedDevice)
-    {
-        SuccessOrExit(error = StopPublishDevice());
-        // Set hostname again in case the mac address changes when shifting from soft-AP to station
-        SuccessOrExit(error = SetupHostname());
-    }
-    mIsPublishingProvisionedDevice = chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned();
-
-    if (mIsPublishingProvisionedDevice)
-    {
-        error = PublishProvisionedDevice(interface);
-    }
-    else
-    {
-        error = PublishUnprovisionedDevice(interface);
-    }
-exit:
-    return error;
-}
-
-CHIP_ERROR Publisher::SetupHostname()
-{
-    uint8_t mac[6];    // 6 byte wifi mac
-    char hostname[13]; // Hostname will be the hex representation of mac.
-    CHIP_ERROR error;
-
-    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetPrimaryWiFiMACAddress(mac));
-    for (size_t i = 0; i < sizeof(mac); i++)
-    {
-        snprintf(&hostname[i * 2], sizeof(hostname) - i * 2, "%02X", mac[i]);
-    }
-    SuccessOrExit(error = ChipMdnsSetHostname(hostname));
-
-exit:
-    return error;
-}
-
-CHIP_ERROR Publisher::PublishUnprovisionedDevice(chip::Inet::InterfaceId interface)
-{
-    CHIP_ERROR error = CHIP_NO_ERROR;
-    MdnsService service;
-    uint16_t discriminator;
-    uint16_t vendorID;
-    uint16_t productID;
-    char discriminatorBuf[5];  // hex representation of 16-bit discriminator
-    char vendorProductBuf[10]; // "FFFF+FFFF"
-    // TODO: The text entry will be updated in the spec, update accordingly.
-    TextEntry entries[2] = {
-        { "D", nullptr, 0 },
-        { "VP", nullptr, 0 },
-    };
-
-    VerifyOrExit(mInitialized, error = CHIP_ERROR_INCORRECT_STATE);
-    ChipLogProgress(Discovery, "setup mdns service");
-    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetSetupDiscriminator(discriminator));
-    snprintf(service.mName, sizeof(service.mName), "%016" PRIX64, mUnprovisionedInstanceName);
-    strncpy(service.mType, "_chipc", sizeof(service.mType));
-    service.mProtocol = MdnsServiceProtocol::kMdnsProtocolUdp;
-    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetVendorId(vendorID));
-    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetProductId(productID));
-    snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04X", discriminator);
-    snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%04X+%04X", vendorID, productID);
-    entries[0].mData       = reinterpret_cast<const uint8_t *>(discriminatorBuf);
-    entries[0].mDataSize   = strnlen(discriminatorBuf, sizeof(discriminatorBuf));
-    entries[1].mData       = reinterpret_cast<const uint8_t *>(vendorProductBuf);
-    entries[1].mDataSize   = strnlen(discriminatorBuf, sizeof(vendorProductBuf));
-    service.mTextEntryies  = entries;
-    service.mTextEntrySize = sizeof(entries) / sizeof(TextEntry);
-    service.mPort          = CHIP_PORT;
-
-    error = ChipMdnsPublishService(&service);
-
-exit:
-    return error;
-}
-
-CHIP_ERROR Publisher::PublishProvisionedDevice(chip::Inet::InterfaceId interface)
-{
-    uint64_t deviceId;
-    uint64_t fabricId;
-    MdnsService service;
-    CHIP_ERROR error = CHIP_NO_ERROR;
-
-    // TODO: There may be multilple device/fabrid ids after multi-admin.
-    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetFabricId(fabricId));
-    SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetDeviceId(deviceId));
-    snprintf(service.mName, sizeof(service.mName), "%" PRIX64 "-%" PRIX64, deviceId, fabricId);
-    strncpy(service.mType, "_chip", sizeof(service.mType));
-    service.mProtocol      = MdnsServiceProtocol::kMdnsProtocolTcp;
-    service.mPort          = CHIP_PORT;
-    service.mTextEntryies  = nullptr;
-    service.mTextEntrySize = 0;
-    error                  = ChipMdnsPublishService(&service);
-exit:
-    return error;
-}
-
-CHIP_ERROR Publisher::StopPublishDevice()
-{
-    return ChipMdnsStopPublish();
-}
-
-} // namespace Mdns
-} // namespace Protocols
-} // namespace chip
diff --git a/src/lib/mdns/Publisher.h b/src/lib/mdns/Publisher.h
deleted file mode 100644
index af9cd53..0000000
--- a/src/lib/mdns/Publisher.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *
- *    Copyright (c) 2020 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.
- */
-
-#pragma once
-
-#include "core/CHIPError.h"
-#include "inet/InetInterface.h"
-
-namespace chip {
-namespace Protocols {
-namespace Mdns {
-
-class Publisher
-{
-public:
-    Publisher() = default;
-
-    /**
-     * This method initializes the publisher.
-     *
-     */
-    CHIP_ERROR Init();
-
-    /**
-     * This method publishes the device on mDNS.
-     *
-     * This function will fetch device name and other information and publish them
-     * via mDNS. If device meta data has changed, you can call this function again
-     * to update the information.
-     *
-     * @param[in] interface   The interface to send mDNS multicast.
-     *
-     */
-    CHIP_ERROR StartPublishDevice(chip::Inet::InterfaceId interface = INET_NULL_INTERFACEID);
-
-    /**
-     * This function stops publishing the device on mDNS.
-     *
-     */
-    CHIP_ERROR StopPublishDevice();
-
-private:
-    Publisher(const Publisher &) = delete;
-    Publisher & operator=(const Publisher &) = delete;
-
-    CHIP_ERROR PublishUnprovisionedDevice(chip::Inet::InterfaceId interface);
-    CHIP_ERROR PublishProvisionedDevice(chip::Inet::InterfaceId interface);
-    CHIP_ERROR SetupHostname();
-
-    static void HandleMdnsInit(void * context, CHIP_ERROR initError);
-    static void HandleMdnsError(void * context, CHIP_ERROR initError);
-
-    uint64_t mUnprovisionedInstanceName;
-    bool mInitialized                   = false;
-    bool mIsPublishingProvisionedDevice = false;
-};
-
-} // namespace Mdns
-} // namespace Protocols
-} // namespace chip
diff --git a/src/lib/mdns/platform/Mdns.h b/src/lib/mdns/platform/Mdns.h
index 13533a8..07c2e83 100644
--- a/src/lib/mdns/platform/Mdns.h
+++ b/src/lib/mdns/platform/Mdns.h
@@ -33,7 +33,6 @@
 #include "lib/core/Optional.h"
 
 namespace chip {
-namespace Protocols {
 namespace Mdns {
 
 static constexpr uint8_t kMdnsNameMaxSize  = 33;
@@ -59,8 +58,9 @@
     char mName[kMdnsNameMaxSize + 1];
     char mType[kMdnsTypeMaxSize + 1];
     MdnsServiceProtocol mProtocol;
+    Inet::IPAddressType mAddressType;
     uint16_t mPort;
-    chip::Inet::InterfaceId interface;
+    chip::Inet::InterfaceId mInterface;
     TextEntry * mTextEntryies;
     size_t mTextEntrySize;
     Optional<chip::Inet::IPAddress> mAddress;
@@ -155,8 +155,8 @@
  * @retval Error code                   The browse fails.
  *
  */
-CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface,
-                          MdnsBrowseCallback callback, void * context);
+CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
+                          chip::Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context);
 
 /**
  * This function resolves the services published by mdns
@@ -174,5 +174,4 @@
                            void * context);
 
 } // namespace Mdns
-} // namespace Protocols
 } // namespace chip
diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn
index 67304c3..fe342f5 100644
--- a/src/platform/BUILD.gn
+++ b/src/platform/BUILD.gn
@@ -41,6 +41,9 @@
 
     # Time the firmware was built.
     chip_device_config_firmware_build_time = ""
+
+    # By pass provision and secure session
+    chip_bypass_rendezvous = false
   }
 
   buildconfig_header("platform_buildconfig") {
@@ -72,6 +75,10 @@
       defines += [ "CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_TIME=\"${chip_device_config_firmware_build_time}\"" ]
     }
 
+    if (chip_bypass_rendezvous) {
+      defines += [ "CHIP_BYPASS_RENDEZVOUS=1" ]
+    }
+
     if (chip_device_platform == "darwin") {
       defines += [
         "CHIP_DEVICE_LAYER_TARGET_DARWIN=1",
@@ -109,6 +116,16 @@
       ]
     }
   }
+} else {
+  buildconfig_header("platform_buildconfig") {
+    header = "CHIPDeviceBuildConfig.h"
+    header_dir = "platform"
+
+    defines = [
+      "CHIP_DEVICE_LAYER_NONE=1",
+      "CHIP_DEVICE_LAYER_TARGET=NONE",
+    ]
+  }
 }
 
 if (chip_device_platform != "none" && chip_device_platform != "external") {
@@ -166,6 +183,7 @@
       "PersistedStorage.cpp",
       "SystemEventSupport.cpp",
       "SystemTimerSupport.cpp",
+      "TestIdentity.cpp",
     ]
 
     cflags = [ "-Wconversion" ]
@@ -440,5 +458,6 @@
   }
 } else {
   group("platform") {
+    public_deps = [ ":platform_buildconfig" ]
   }
 }
diff --git a/src/platform/ESP32/MdnsImpl.cpp b/src/platform/ESP32/MdnsImpl.cpp
index 24fd036..78c2126 100644
--- a/src/platform/ESP32/MdnsImpl.cpp
+++ b/src/platform/ESP32/MdnsImpl.cpp
@@ -35,7 +35,6 @@
 } // namespace
 
 namespace chip {
-namespace Protocols {
 namespace Mdns {
 
 CHIP_ERROR ChipMdnsInit(MdnsAsnycReturnCallback initCallback, MdnsAsnycReturnCallback errorCallback, void * context)
@@ -109,8 +108,8 @@
     return mdns_service_remove_all() == ESP_OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL;
 }
 
-CHIP_ERROR ChipMdnsBrowse(const char * /*type*/, MdnsServiceProtocol /*protocol*/, chip::Inet::InterfaceId /*interface*/,
-                          MdnsBrowseCallback /*callback*/, void * /*context*/)
+CHIP_ERROR ChipMdnsBrowse(const char * /*type*/, MdnsServiceProtocol /*protocol*/, chip::Inet::IPAddressType addressType,
+                          chip::Inet::InterfaceId /*interface*/, MdnsBrowseCallback /*callback*/, void * /*context*/)
 {
     return CHIP_ERROR_NOT_IMPLEMENTED;
 }
@@ -122,5 +121,4 @@
 }
 
 } // namespace Mdns
-} // namespace Protocols
 } // namespace chip
diff --git a/src/platform/Linux/ConfigurationManagerImpl.cpp b/src/platform/Linux/ConfigurationManagerImpl.cpp
index 6d12c43..57090c6 100644
--- a/src/platform/Linux/ConfigurationManagerImpl.cpp
+++ b/src/platform/Linux/ConfigurationManagerImpl.cpp
@@ -25,11 +25,13 @@
 
 #include <platform/internal/CHIPDeviceLayerInternal.h>
 
+#include <ifaddrs.h>
+#include <netpacket/packet.h>
+
 #include <core/CHIPVendorIdentifiers.hpp>
 #include <platform/ConfigurationManager.h>
 #include <platform/Linux/PosixConfig.h>
 #include <platform/internal/GenericConfigurationManagerImpl.cpp>
-
 #include <support/CodeUtils.h>
 #include <support/logging/CHIPLogging.h>
 
@@ -74,8 +76,29 @@
 
 CHIP_ERROR ConfigurationManagerImpl::_GetPrimaryWiFiMACAddress(uint8_t * buf)
 {
-    // TODO(#739): add WiFi support
-    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+    struct ifaddrs * addresses = NULL;
+    CHIP_ERROR error           = CHIP_NO_ERROR;
+    bool found                 = false;
+
+    VerifyOrExit(getifaddrs(&addresses) == 0, error = CHIP_ERROR_INTERNAL);
+    for (auto addr = addresses; addr != NULL; addr = addr->ifa_next)
+    {
+        if ((addr->ifa_addr) && (addr->ifa_addr->sa_family == AF_PACKET) && strncmp(addr->ifa_name, "lo", IFNAMSIZ) != 0)
+        {
+            struct sockaddr_ll * mac = (struct sockaddr_ll *) addr->ifa_addr;
+            memcpy(buf, mac->sll_addr, mac->sll_halen);
+            found = true;
+            break;
+        }
+    }
+    freeifaddrs(addresses);
+    if (!found)
+    {
+        error = CHIP_ERROR_NO_ENDPOINT;
+    }
+
+exit:
+    return error;
 }
 
 bool ConfigurationManagerImpl::_CanFactoryReset()
diff --git a/src/platform/Linux/MdnsImpl.cpp b/src/platform/Linux/MdnsImpl.cpp
index 498fdff..58b7e02 100644
--- a/src/platform/Linux/MdnsImpl.cpp
+++ b/src/platform/Linux/MdnsImpl.cpp
@@ -28,9 +28,9 @@
 #include "support/CHIPMem.h"
 #include "support/CodeUtils.h"
 
-using chip::Protocols::Mdns::kMdnsTypeMaxSize;
-using chip::Protocols::Mdns::MdnsServiceProtocol;
-using chip::Protocols::Mdns::TextEntry;
+using chip::Mdns::kMdnsTypeMaxSize;
+using chip::Mdns::MdnsServiceProtocol;
+using chip::Mdns::TextEntry;
 using std::chrono::duration_cast;
 using std::chrono::microseconds;
 using std::chrono::seconds;
@@ -38,6 +38,46 @@
 
 namespace {
 
+AvahiProtocol ToAvahiProtocol(chip::Inet::IPAddressType addressType)
+{
+    AvahiProtocol protocol;
+
+    switch (addressType)
+    {
+    case chip::Inet::IPAddressType::kIPAddressType_IPv4:
+        protocol = AVAHI_PROTO_INET;
+        break;
+    case chip::Inet::IPAddressType::kIPAddressType_IPv6:
+        protocol = AVAHI_PROTO_INET6;
+        break;
+    default:
+        protocol = AVAHI_PROTO_UNSPEC;
+        break;
+    }
+
+    return protocol;
+}
+
+chip::Inet::IPAddressType ToAddressType(AvahiProtocol protocol)
+{
+    chip::Inet::IPAddressType type;
+
+    switch (protocol)
+    {
+    case AVAHI_PROTO_INET:
+        type = chip::Inet::IPAddressType::kIPAddressType_IPv4;
+        break;
+    case AVAHI_PROTO_INET6:
+        type = chip::Inet::IPAddressType::kIPAddressType_IPv6;
+        break;
+    default:
+        type = chip::Inet::IPAddressType::kIPAddressType_Unknown;
+        break;
+    }
+
+    return type;
+}
+
 CHIP_ERROR MakeAvahiStringListFromTextEntries(TextEntry * entries, size_t size, AvahiStringList ** strListOut)
 {
     *strListOut = avahi_string_list_new(nullptr, nullptr);
@@ -75,7 +115,6 @@
 } // namespace
 
 namespace chip {
-namespace Protocols {
 namespace Mdns {
 
 MdnsAvahi MdnsAvahi::sInstance;
@@ -309,9 +348,18 @@
 CHIP_ERROR MdnsAvahi::SetHostname(const char * hostname)
 {
     CHIP_ERROR error = CHIP_NO_ERROR;
+    int avahiRet;
 
     VerifyOrExit(mClient != nullptr, error = CHIP_ERROR_INCORRECT_STATE);
-    VerifyOrExit(avahi_client_set_host_name(mClient, hostname) == 0, error = CHIP_ERROR_INTERNAL);
+    avahiRet = avahi_client_set_host_name(mClient, hostname);
+    if (avahiRet == AVAHI_ERR_ACCESS_DENIED)
+    {
+        ChipLogError(DeviceLayer, "Cannot set hostname on this system, continue anyway...");
+    }
+    else if (avahiRet != AVAHI_OK && avahiRet != AVAHI_ERR_NO_CHANGE)
+    {
+        error = CHIP_ERROR_INTERNAL;
+    }
 
 exit:
     return error;
@@ -347,10 +395,21 @@
     case AVAHI_CLIENT_S_COLLISION:
     case AVAHI_CLIENT_S_REGISTERING:
         ChipLogProgress(DeviceLayer, "Avahi re-register required");
-        mErrorCallback(mAsyncReturnContext, CHIP_ERROR_MDNS_COLLISSION);
         if (mGroup != nullptr)
         {
             avahi_entry_group_reset(mGroup);
+            avahi_entry_group_free(mGroup);
+        }
+        mGroup = avahi_entry_group_new(client, HandleGroupState, this);
+        mPublishedServices.clear();
+        if (mGroup == nullptr)
+        {
+            ChipLogError(DeviceLayer, "Failed to create avahi group: %s", avahi_strerror(avahi_client_errno(client)));
+            mErrorCallback(mAsyncReturnContext, CHIP_ERROR_OPEN_FAILED);
+        }
+        else
+        {
+            mErrorCallback(mAsyncReturnContext, CHIP_ERROR_FORCED_RESET);
         }
         break;
     case AVAHI_CLIENT_CONNECTING:
@@ -394,24 +453,27 @@
     CHIP_ERROR error       = CHIP_NO_ERROR;
     AvahiStringList * text = nullptr;
     AvahiIfIndex interface =
-        service.interface == INET_NULL_INTERFACEID ? AVAHI_IF_UNSPEC : static_cast<AvahiIfIndex>(service.interface);
+        service.mInterface == INET_NULL_INTERFACEID ? AVAHI_IF_UNSPEC : static_cast<AvahiIfIndex>(service.mInterface);
 
     keyBuilder << service.mName << "." << type << service.mPort << "." << interface;
     key = keyBuilder.str();
+    ChipLogProgress(DeviceLayer, "PublishService %s", key.c_str());
+
     if (mPublishedServices.find(key) == mPublishedServices.end())
     {
         SuccessOrExit(error = MakeAvahiStringListFromTextEntries(service.mTextEntryies, service.mTextEntrySize, &text));
 
         mPublishedServices.emplace(key);
-        VerifyOrExit(avahi_entry_group_add_service_strlst(mGroup, interface, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0),
-                                                          service.mName, type.c_str(), nullptr, nullptr, service.mPort, text) == 0,
+        VerifyOrExit(avahi_entry_group_add_service_strlst(mGroup, interface, ToAvahiProtocol(service.mAddressType),
+                                                          static_cast<AvahiPublishFlags>(0), service.mName, type.c_str(), nullptr,
+                                                          nullptr, service.mPort, text) == 0,
                      error = CHIP_ERROR_INTERNAL);
     }
     else
     {
         SuccessOrExit(error = MakeAvahiStringListFromTextEntries(service.mTextEntryies, service.mTextEntrySize, &text));
 
-        VerifyOrExit(avahi_entry_group_update_service_txt_strlst(mGroup, interface, AVAHI_PROTO_UNSPEC,
+        VerifyOrExit(avahi_entry_group_update_service_txt_strlst(mGroup, interface, ToAvahiProtocol(service.mAddressType),
                                                                  static_cast<AvahiPublishFlags>(0), service.mName, type.c_str(),
                                                                  nullptr, text) == 0,
                      error = CHIP_ERROR_INTERNAL);
@@ -436,17 +498,17 @@
     CHIP_ERROR error = CHIP_NO_ERROR;
 
     VerifyOrExit(avahi_entry_group_reset(mGroup) == 0, error = CHIP_ERROR_INTERNAL);
-    VerifyOrExit(avahi_entry_group_commit(mGroup) == 0, error = CHIP_ERROR_INTERNAL);
 exit:
     return error;
 }
 
-CHIP_ERROR MdnsAvahi::Browse(const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface,
-                             MdnsBrowseCallback callback, void * context)
+CHIP_ERROR MdnsAvahi::Browse(const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
+                             chip::Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context)
 {
     AvahiServiceBrowser * browser;
     BrowseContext * browseContext = static_cast<BrowseContext *>(chip::Platform::MemoryAlloc(sizeof(BrowseContext)));
     AvahiIfIndex avahiInterface   = static_cast<AvahiIfIndex>(interface);
+    AvahiProtocol avahiProtocol;
 
     browseContext->mInstance = this;
     browseContext->mContext  = context;
@@ -455,8 +517,9 @@
     {
         avahiInterface = AVAHI_IF_UNSPEC;
     }
-    browser = avahi_service_browser_new(mClient, avahiInterface, AVAHI_PROTO_UNSPEC, GetFullType(type, protocol).c_str(), nullptr,
-                                        static_cast<AvahiLookupFlags>(0), HandleBrowse, browseContext);
+
+    browser = avahi_service_browser_new(mClient, avahiInterface, ToAvahiProtocol(addressType), GetFullType(type, protocol).c_str(),
+                                        nullptr, static_cast<AvahiLookupFlags>(0), HandleBrowse, browseContext);
     // Otherwise the browser will be freed in the callback
     if (browser == nullptr)
     {
@@ -511,6 +574,7 @@
             service.mName[kMdnsNameMaxSize] = 0;
             service.mType[kMdnsTypeMaxSize] = 0;
             service.mProtocol               = TruncateProtocolInType(service.mType);
+            service.mAddressType            = ToAddressType(protocol);
             context->mServices.push_back(service);
         }
         break;
@@ -535,7 +599,8 @@
     }
 }
 
-CHIP_ERROR MdnsAvahi::Resolve(const char * name, const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface,
+CHIP_ERROR MdnsAvahi::Resolve(const char * name, const char * type, MdnsServiceProtocol protocol,
+                              chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface,
                               MdnsResolveCallback callback, void * context)
 {
     AvahiServiceResolver * resolver;
@@ -550,9 +615,9 @@
     {
         avahiInterface = AVAHI_IF_UNSPEC;
     }
-    resolver =
-        avahi_service_resolver_new(mClient, avahiInterface, AVAHI_PROTO_UNSPEC, name, GetFullType(type, protocol).c_str(), nullptr,
-                                   AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), HandleResolve, resolveContext);
+    resolver = avahi_service_resolver_new(mClient, avahiInterface, ToAvahiProtocol(addressType), name,
+                                          GetFullType(type, protocol).c_str(), nullptr, ToAvahiProtocol(addressType),
+                                          static_cast<AvahiLookupFlags>(0), HandleResolve, resolveContext);
     // Otherwise the resolver will be freed in the callback
     if (resolver == nullptr)
     {
@@ -588,6 +653,7 @@
         result.mType[kMdnsTypeMaxSize] = 0;
         result.mProtocol               = TruncateProtocolInType(result.mType);
         result.mPort                   = port;
+        result.mAddressType            = ToAddressType(protocol);
 
         if (address)
         {
@@ -680,10 +746,10 @@
     return MdnsAvahi::GetInstance().StopPublish();
 }
 
-CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface,
-                          MdnsBrowseCallback callback, void * context)
+CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
+                          chip::Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context)
 {
-    return MdnsAvahi::GetInstance().Browse(type, protocol, interface, callback, context);
+    return MdnsAvahi::GetInstance().Browse(type, protocol, addressType, interface, callback, context);
 }
 
 CHIP_ERROR ChipMdnsResolve(MdnsService * browseResult, chip::Inet::InterfaceId interface, MdnsResolveCallback callback,
@@ -694,8 +760,8 @@
 
     if (browseResult != nullptr)
     {
-        error = MdnsAvahi::GetInstance().Resolve(browseResult->mName, browseResult->mType, browseResult->mProtocol, interface,
-                                                 callback, context);
+        error = MdnsAvahi::GetInstance().Resolve(browseResult->mName, browseResult->mType, browseResult->mProtocol,
+                                                 browseResult->mAddressType, interface, callback, context);
     }
     else
     {
@@ -705,5 +771,4 @@
 }
 
 } // namespace Mdns
-} // namespace Protocols
 } // namespace chip
diff --git a/src/platform/Linux/MdnsImpl.h b/src/platform/Linux/MdnsImpl.h
index b5f3506..9524bc0 100644
--- a/src/platform/Linux/MdnsImpl.h
+++ b/src/platform/Linux/MdnsImpl.h
@@ -55,7 +55,6 @@
 };
 
 namespace chip {
-namespace Protocols {
 namespace Mdns {
 
 class Poller
@@ -105,10 +104,10 @@
     CHIP_ERROR SetHostname(const char * hostname);
     CHIP_ERROR PublishService(const MdnsService & service);
     CHIP_ERROR StopPublish();
-    CHIP_ERROR Browse(const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface,
-                      MdnsBrowseCallback callback, void * context);
-    CHIP_ERROR Resolve(const char * name, const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface,
-                       MdnsResolveCallback callback, void * context);
+    CHIP_ERROR Browse(const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
+                      chip::Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context);
+    CHIP_ERROR Resolve(const char * name, const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
+                       chip::Inet::InterfaceId interface, MdnsResolveCallback callback, void * context);
 
     Poller & GetPoller() { return mPoller; }
 
@@ -164,5 +163,4 @@
 void ProcessMdns(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet);
 
 } // namespace Mdns
-} // namespace Protocols
 } // namespace chip
diff --git a/examples/shell/test_identity.cpp b/src/platform/TestIdentity.cpp
similarity index 95%
rename from examples/shell/test_identity.cpp
rename to src/platform/TestIdentity.cpp
index 4ac035b..1020601 100644
--- a/examples/shell/test_identity.cpp
+++ b/src/platform/TestIdentity.cpp
@@ -24,7 +24,7 @@
 namespace Internal {
 
 #if CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
-const uint64_t TestDeviceId                       = 0x1235;
+const uint64_t TestDeviceId                       = 12344321;
 const uint64_t TestFabricId                       = 0;
 const uint8_t TestDeviceCert[]                    = { 0 };
 const uint8_t TestDeviceIntermediateCACert[]      = { 0 };
diff --git a/src/platform/tests/TestMdns.cpp b/src/platform/tests/TestMdns.cpp
index bb031ed..58477d3 100644
--- a/src/platform/tests/TestMdns.cpp
+++ b/src/platform/tests/TestMdns.cpp
@@ -8,9 +8,9 @@
 #include "platform/CHIPDeviceLayer.h"
 #include "support/CHIPMem.h"
 
-using chip::Protocols::Mdns::MdnsService;
-using chip::Protocols::Mdns::MdnsServiceProtocol;
-using chip::Protocols::Mdns::TextEntry;
+using chip::Mdns::MdnsService;
+using chip::Mdns::MdnsServiceProtocol;
+using chip::Mdns::TextEntry;
 
 static void HandleResolve(void * context, MdnsService * result, CHIP_ERROR error)
 {
@@ -52,8 +52,8 @@
 
     NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR);
 
-    service.interface = INET_NULL_INTERFACEID;
-    service.mPort     = 80;
+    service.mInterface = INET_NULL_INTERFACEID;
+    service.mPort      = 80;
     strcpy(service.mName, "test");
     strcpy(service.mType, "_mock");
     service.mProtocol      = MdnsServiceProtocol::kMdnsProtocolTcp;
@@ -64,7 +64,8 @@
     service.mTextEntrySize = 1;
 
     NL_TEST_ASSERT(suite, ChipMdnsPublishService(&service) == CHIP_NO_ERROR);
-    ChipMdnsBrowse("_mock", MdnsServiceProtocol::kMdnsProtocolTcp, INET_NULL_INTERFACEID, HandleBrowse, suite);
+    ChipMdnsBrowse("_mock", MdnsServiceProtocol::kMdnsProtocolTcp, chip::Inet::kIPAddressType_Any, INET_NULL_INTERFACEID,
+                   HandleBrowse, suite);
 }
 
 static void ErrorCallback(void * context, CHIP_ERROR error)
@@ -80,7 +81,7 @@
 {
     chip::Platform::MemoryInit();
     chip::DeviceLayer::PlatformMgr().InitChipStack();
-    NL_TEST_ASSERT(inSuite, chip::Protocols::Mdns::ChipMdnsInit(InitCallback, ErrorCallback, inSuite) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, chip::Mdns::ChipMdnsInit(InitCallback, ErrorCallback, inSuite) == CHIP_NO_ERROR);
 
     ChipLogProgress(DeviceLayer, "Start EventLoop");
     chip::DeviceLayer::PlatformMgr().RunEventLoop();
diff --git a/src/test_driver/linux-cirque/OnOffClusterTest.sh b/src/test_driver/linux-cirque/OnOffClusterTest.sh
index 67979fb..c423593 100755
--- a/src/test_driver/linux-cirque/OnOffClusterTest.sh
+++ b/src/test_driver/linux-cirque/OnOffClusterTest.sh
@@ -32,16 +32,16 @@
     cd "$chip_tool_dir"
     gn gen out/debug >/dev/null
     run_ninja -C out/debug
-    docker build -t chip_tool -f Dockerfile . >/dev/null 2>&1
+    docker build -t chip_tool -f Dockerfile . 2>&1
 }
 
 function build_chip_lighting() {
     source "$REPO_DIR/scripts/activate.sh" >/dev/null
     set -x
     cd "$chip_light_dir"
-    gn gen out/debug --args='bypass_rendezvous=true' >/dev/null
+    gn gen out/debug --args='bypass_rendezvous=true'
     run_ninja -C out/debug
-    docker build -t chip_server -f Dockerfile . >/dev/null 2>&1
+    docker build -t chip_server -f Dockerfile . 2>&1
     set +x
 }
 
diff --git a/src/test_driver/linux-cirque/test-on-off-cluster.py b/src/test_driver/linux-cirque/test-on-off-cluster.py
index 341c1be..92c01fc 100644
--- a/src/test_driver/linux-cirque/test-on-off-cluster.py
+++ b/src/test_driver/linux-cirque/test-on-off-cluster.py
@@ -76,6 +76,7 @@
 
         for device_id in server_ids:
             server_ip_address.add(self.get_device_thread_ip(device_id))
+        server_ip_address.add("::")
 
         command = "chip-tool onoff {} {} {} 1"
 
diff --git a/src/transport/BUILD.gn b/src/transport/BUILD.gn
index 79828d5..f6e05ba 100644
--- a/src/transport/BUILD.gn
+++ b/src/transport/BUILD.gn
@@ -48,6 +48,7 @@
     "${chip_root}/src/crypto",
     "${chip_root}/src/inet",
     "${chip_root}/src/lib/core",
+    "${chip_root}/src/lib/mdns",
     "${chip_root}/src/lib/support",
     "${chip_root}/src/platform",
     "${chip_root}/src/transport/raw",
diff --git a/src/transport/PeerConnections.h b/src/transport/PeerConnections.h
index 139e7df..f69a4c1 100644
--- a/src/transport/PeerConnections.h
+++ b/src/transport/PeerConnections.h
@@ -131,23 +131,30 @@
      * Get a peer connection state given a Peer address.
      *
      * @param address is the connection to find (based on address)
-     * @param state [out] the connection if found, null otherwise. MUST not be null.
+     * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
      *
-     * @return true if a corresponding state was found.
+     * @return the state found, nullptr if not found
      */
     CHECK_RETURN_VALUE
-    bool FindPeerConnectionState(const PeerAddress & address, PeerConnectionState ** state)
+    PeerConnectionState * FindPeerConnectionState(const PeerAddress & address, PeerConnectionState * begin)
     {
-        *state = nullptr;
-        for (size_t i = 0; i < kMaxConnectionCount; i++)
+        PeerConnectionState * state = nullptr;
+        PeerConnectionState * iter  = &mStates[0];
+
+        if (begin >= iter && begin <= &mStates[kMaxConnectionCount])
         {
-            if (mStates[i].GetPeerAddress() == address)
+            iter = begin + 1;
+        }
+
+        for (; iter <= &mStates[kMaxConnectionCount]; iter++)
+        {
+            if (iter->GetPeerAddress() == address)
             {
-                *state = &mStates[i];
+                state = iter;
                 break;
             }
         }
-        return *state != nullptr;
+        return state;
     }
 
     /**
@@ -155,27 +162,34 @@
      *
      * @param nodeId is the connection to find (based on nodeId). Note that initial connections
      *        do not have a node id set. Use this if you know the node id should be set.
-     * @param state [out] the connection if found, null otherwise. MUST not be null.
+     * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
      *
-     * @return true if a corresponding state was found.
+     * @return the state found, nullptr if not found
      */
     CHECK_RETURN_VALUE
-    bool FindPeerConnectionState(NodeId nodeId, PeerConnectionState ** state)
+    PeerConnectionState * FindPeerConnectionState(NodeId nodeId, PeerConnectionState * begin)
     {
-        *state = nullptr;
-        for (size_t i = 0; i < kMaxConnectionCount; i++)
+        PeerConnectionState * state = nullptr;
+        PeerConnectionState * iter  = &mStates[0];
+
+        if (begin >= iter && begin <= &mStates[kMaxConnectionCount])
         {
-            if (!mStates[i].IsInitialized())
+            iter = begin + 1;
+        }
+
+        for (; iter <= &mStates[kMaxConnectionCount]; iter++)
+        {
+            if (!iter->IsInitialized())
             {
                 continue;
             }
-            if (mStates[i].GetPeerNodeId() == nodeId)
+            if (iter->GetPeerNodeId() == nodeId)
             {
-                *state = &mStates[i];
+                state = iter;
                 break;
             }
         }
-        return *state != nullptr;
+        return state;
     }
 
     /**
@@ -184,31 +198,37 @@
      * @param nodeId is the connection to find (based on nodeId). Note that initial connections
      *        do not have a node id set. Use this if you know the node id should be set.
      * @param peerKeyId Encryption key ID used by the peer node.
-     * @param state [out] the connection if found, null otherwise. MUST not be null.
+     * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
      *
-     * @return true if a corresponding state was found.
+     * @return the state found, nullptr if not found
      */
     CHECK_RETURN_VALUE
-    bool FindPeerConnectionState(Optional<NodeId> nodeId, uint16_t peerKeyId, PeerConnectionState ** state)
+    PeerConnectionState * FindPeerConnectionState(Optional<NodeId> nodeId, uint16_t peerKeyId, PeerConnectionState * begin)
     {
-        *state = nullptr;
-        for (size_t i = 0; i < kMaxConnectionCount; i++)
+        PeerConnectionState * state = nullptr;
+        PeerConnectionState * iter  = &mStates[0];
+
+        if (begin >= iter && begin <= &mStates[kMaxConnectionCount])
         {
-            if (!mStates[i].IsInitialized())
+            iter = begin + 1;
+        }
+
+        for (; iter <= &mStates[kMaxConnectionCount]; iter++)
+        {
+            if (!iter->IsInitialized())
             {
                 continue;
             }
-            if (mStates[i].GetPeerKeyID() == peerKeyId)
+            if (iter->GetPeerKeyID() == peerKeyId)
             {
-                if (!nodeId.HasValue() || mStates[i].GetPeerNodeId() == kUndefinedNodeId ||
-                    mStates[i].GetPeerNodeId() == nodeId.Value())
+                if (!nodeId.HasValue() || iter->GetPeerNodeId() == kUndefinedNodeId || iter->GetPeerNodeId() == nodeId.Value())
                 {
-                    *state = &mStates[i];
+                    state = iter;
                     break;
                 }
             }
         }
-        return *state != nullptr;
+        return state;
     }
 
     /**
@@ -217,31 +237,38 @@
      * @param nodeId is the connection to find (based on peer nodeId). Note that initial connections
      *        do not have a node id set. Use this if you know the node id should be set.
      * @param localKeyId Encryption key ID used by the local node.
-     * @param state [out] the connection if found, null otherwise. MUST not be null.
+     * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
      *
-     * @return true if a corresponding state was found.
+     * @return the state found, nullptr if not found
      */
     CHECK_RETURN_VALUE
-    bool FindPeerConnectionStateByLocalKey(Optional<NodeId> nodeId, uint16_t localKeyId, PeerConnectionState ** state)
+    PeerConnectionState * FindPeerConnectionStateByLocalKey(Optional<NodeId> nodeId, uint16_t localKeyId,
+                                                            PeerConnectionState * begin)
     {
-        *state = nullptr;
-        for (size_t i = 0; i < kMaxConnectionCount; i++)
+        PeerConnectionState * state = nullptr;
+        PeerConnectionState * iter  = &mStates[0];
+
+        if (begin >= iter && begin <= &mStates[kMaxConnectionCount])
         {
-            if (!mStates[i].IsInitialized())
+            iter = begin + 1;
+        }
+
+        for (; iter <= &mStates[kMaxConnectionCount]; iter++)
+        {
+            if (!iter->IsInitialized())
             {
                 continue;
             }
-            if (mStates[i].GetLocalKeyID() == localKeyId)
+            if (iter->GetLocalKeyID() == localKeyId)
             {
-                if (!nodeId.HasValue() || mStates[i].GetPeerNodeId() == kUndefinedNodeId ||
-                    mStates[i].GetPeerNodeId() == nodeId.Value())
+                if (!nodeId.HasValue() || iter->GetPeerNodeId() == kUndefinedNodeId || iter->GetPeerNodeId() == nodeId.Value())
                 {
-                    *state = &mStates[i];
+                    state = iter;
                     break;
                 }
             }
         }
-        return *state != nullptr;
+        return state;
     }
 
     /// Convenience method to mark a peer connection state as active
diff --git a/src/transport/SecureSessionMgr.cpp b/src/transport/SecureSessionMgr.cpp
index f94aefb..4e41dc4 100644
--- a/src/transport/SecureSessionMgr.cpp
+++ b/src/transport/SecureSessionMgr.cpp
@@ -24,14 +24,16 @@
  *
  */
 
+#include "SecureSessionMgr.h"
+
+#include <inttypes.h>
 #include <string.h>
+
+#include <platform/CHIPDeviceLayer.h>
 #include <support/CodeUtils.h>
 #include <support/SafeInt.h>
 #include <support/logging/CHIPLogging.h>
 #include <transport/SecurePairingSession.h>
-#include <transport/SecureSessionMgr.h>
-
-#include <inttypes.h>
 
 namespace chip {
 
@@ -66,6 +68,9 @@
     mTransport->SetMessageReceiveHandler(HandleDataReceived, this);
     mPeerConnections.SetConnectionExpiredHandler(HandleConnectionExpired, this);
 
+    Mdns::DiscoveryManager::GetInstance().Init();
+    Mdns::DiscoveryManager::GetInstance().RegisterResolveDelegate(this);
+
     ScheduleExpiryTimer();
 
 exit:
@@ -82,7 +87,7 @@
 CHIP_ERROR SecureSessionMgrBase::SendMessage(PayloadHeader & payloadHeader, NodeId peerNodeId, System::PacketBuffer * msgBuf)
 {
     CHIP_ERROR err              = CHIP_NO_ERROR;
-    PeerConnectionState * state = nullptr;
+    PeerConnectionState * state = mPeerConnections.FindPeerConnectionState(peerNodeId, nullptr);
 
     VerifyOrExit(mState == State::kInitialized, err = CHIP_ERROR_INCORRECT_STATE);
 
@@ -91,7 +96,7 @@
     VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
 
     // Find an active connection to the specified peer node
-    VerifyOrExit(mPeerConnections.FindPeerConnectionState(peerNodeId, &state), err = CHIP_ERROR_INVALID_DESTINATION_NODE_ID);
+    VerifyOrExit(state != nullptr, err = CHIP_ERROR_INVALID_DESTINATION_NODE_ID);
 
     // This marks any connection where we send data to as 'active'
     mPeerConnections.MarkConnectionActive(state);
@@ -168,13 +173,13 @@
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
 
-    PeerConnectionState * state = nullptr;
     Optional<NodeId> peerNodeId = Optional<NodeId>::Value(pairing->GetPeerNodeId());
     uint16_t peerKeyId          = pairing->GetPeerKeyId();
     uint16_t localKeyId         = pairing->GetLocalKeyId();
+    PeerConnectionState * state = mPeerConnections.FindPeerConnectionState(peerNodeId, peerKeyId, nullptr);
 
     // Find any existing connection with the same node and key ID
-    if (mPeerConnections.FindPeerConnectionState(peerNodeId, peerKeyId, &state))
+    if (state)
     {
         mPeerConnections.MarkConnectionExpired(state);
     }
@@ -184,10 +189,21 @@
     err   = mPeerConnections.CreateNewPeerConnectionState(peerNodeId, peerKeyId, localKeyId, &state);
     SuccessOrExit(err);
 
-    if (peerAddr.HasValue())
+    if (peerAddr.HasValue() && peerAddr.Value().GetIPAddress() != Inet::IPAddress::Any)
     {
         state->SetPeerAddress(peerAddr.Value());
     }
+    else if (peerAddr.HasValue() &&
+             (peerAddr.Value().GetTransportType() == Transport::Type::kTcp ||
+              peerAddr.Value().GetTransportType() == Transport::Type::kUdp))
+    {
+        uint64_t fabricId = 0;
+
+#if !CHIP_DEVICE_LAYER_NONE
+        SuccessOrExit(err = chip::DeviceLayer::ConfigurationMgr().GetFabricId(fabricId));
+#endif
+        SuccessOrExit(err = Mdns::DiscoveryManager::GetInstance().ResolveNodeId(pairing->GetPeerNodeId(), fabricId));
+    }
 
     if (state != nullptr)
     {
@@ -199,6 +215,40 @@
     return err;
 }
 
+void SecureSessionMgrBase::HandleNodeIdResolve(CHIP_ERROR error, NodeId nodeId, const Mdns::MdnsService & service)
+{
+    if (error != CHIP_NO_ERROR && mCB != nullptr)
+    {
+        mCB->OnAddressResolved(error, kUndefinedNodeId, this);
+    }
+    else if (nodeId == kUndefinedNodeId && mCB != nullptr)
+    {
+        mCB->OnAddressResolved(CHIP_ERROR_UNKNOWN_RESOURCE_ID, kUndefinedNodeId, this);
+    }
+    else if (error == CHIP_NO_ERROR && nodeId != kUndefinedNodeId)
+    {
+        PeerConnectionState * state = nullptr;
+        PeerAddress addr;
+        bool hasAddressUpdate = false;
+
+        // Though the spec says the service name is _chip._tcp, we are not supporting tcp for now.
+        addr.SetTransportType(Transport::Type::kUdp).SetIPAddress(service.mAddress.Value()).SetPort(service.mPort);
+
+        while ((state = mPeerConnections.FindPeerConnectionState(nodeId, state)) != nullptr)
+        {
+            if (state->GetPeerAddress().GetIPAddress() == Inet::IPAddress::Any)
+            {
+                hasAddressUpdate = true;
+                state->SetPeerAddress(addr);
+            }
+        }
+        if (hasAddressUpdate)
+        {
+            mCB->OnAddressResolved(CHIP_NO_ERROR, nodeId, this);
+        }
+    }
+}
+
 void SecureSessionMgrBase::ScheduleExpiryTimer()
 {
     CHIP_ERROR err =
@@ -221,12 +271,12 @@
 {
     CHIP_ERROR err                 = CHIP_NO_ERROR;
     System::PacketBuffer * origMsg = nullptr;
-    PeerConnectionState * state    = nullptr;
+    PeerConnectionState * state    = connection->mPeerConnections.FindPeerConnectionState(packetHeader.GetSourceNodeId(),
+                                                                                       packetHeader.GetEncryptionKeyID(), nullptr);
 
     VerifyOrExit(msg != nullptr, ChipLogError(Inet, "Secure transport received NULL packet, discarding"));
 
-    if (!connection->mPeerConnections.FindPeerConnectionState(packetHeader.GetSourceNodeId(), packetHeader.GetEncryptionKeyID(),
-                                                              &state))
+    if (state == nullptr)
     {
         ChipLogError(Inet, "Data received on an unknown connection (%d). Dropping it!!", packetHeader.GetEncryptionKeyID());
         ExitNow(err = CHIP_ERROR_KEY_NOT_FOUND_FROM_PEER);
diff --git a/src/transport/SecureSessionMgr.h b/src/transport/SecureSessionMgr.h
index 88330d1..ac66baf 100644
--- a/src/transport/SecureSessionMgr.h
+++ b/src/transport/SecureSessionMgr.h
@@ -30,6 +30,7 @@
 #include <core/CHIPCore.h>
 #include <inet/IPAddress.h>
 #include <inet/IPEndPointBasis.h>
+#include <lib/mdns/DiscoveryManager.h>
 #include <support/CodeUtils.h>
 #include <support/DLLUtil.h>
 #include <transport/PeerConnections.h>
@@ -80,17 +81,27 @@
 
     /**
      * @brief
-     *   Called when a new connection is being established
+     *   Called when a new pairing is being established
      *
      * @param state   connection state
      * @param mgr     A pointer to the SecureSessionMgr
      */
     virtual void OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) {}
 
+    /**
+     * @brief
+     *   Called when the peer address is resolved from NodeID.
+     *
+     * @param error   The resolution resolve error code
+     * @param nodeId  The node ID resolved, 0 on error
+     * @param mgr     A pointer to the SecureSessionMgr
+     */
+    virtual void OnAddressResolved(CHIP_ERROR error, NodeId nodeId, SecureSessionMgrBase * mgr) {}
+
     virtual ~SecureSessionMgrDelegate() {}
 };
 
-class DLL_EXPORT SecureSessionMgrBase
+class DLL_EXPORT SecureSessionMgrBase : public Mdns::ResolveDelegate
 {
 public:
     /**
@@ -104,7 +115,7 @@
     CHIP_ERROR SendMessage(NodeId peerNodeId, System::PacketBuffer * msgBuf);
     CHIP_ERROR SendMessage(PayloadHeader & payloadHeader, NodeId peerNodeId, System::PacketBuffer * msgBuf);
     SecureSessionMgrBase();
-    virtual ~SecureSessionMgrBase();
+    ~SecureSessionMgrBase() override;
 
     /**
      * @brief
@@ -179,6 +190,8 @@
      * Callback for timer expiry check
      */
     static void ExpiryTimerCallback(System::Layer * layer, void * param, System::Error error);
+
+    void HandleNodeIdResolve(CHIP_ERROR error, NodeId nodeId, const Mdns::MdnsService & service) override;
 };
 
 /**
diff --git a/src/transport/tests/TestPeerConnections.cpp b/src/transport/tests/TestPeerConnections.cpp
index 955a061..0601abb 100644
--- a/src/transport/tests/TestPeerConnections.cpp
+++ b/src/transport/tests/TestPeerConnections.cpp
@@ -78,32 +78,43 @@
 {
     CHIP_ERROR err;
     PeerConnectionState * statePtr;
-    PeerConnections<2, Time::Source::kTest> connections;
+    PeerConnections<3, Time::Source::kTest> connections;
 
     PeerConnectionState * state1 = nullptr;
     PeerConnectionState * state2 = nullptr;
+    PeerConnectionState * state3 = nullptr;
 
     err = connections.CreateNewPeerConnectionState(kPeer1Addr, &state1);
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
 
-    err = connections.CreateNewPeerConnectionState(kPeer2Addr, &state2);
+    err = connections.CreateNewPeerConnectionState(kPeer1Addr, &state2);
+    NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+
+    err = connections.CreateNewPeerConnectionState(kPeer2Addr, &state3);
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
 
     NL_TEST_ASSERT(inSuite, state1 != state2);
+    NL_TEST_ASSERT(inSuite, state1 != state3);
+    NL_TEST_ASSERT(inSuite, state2 != state3);
 
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer1Addr, &statePtr));
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1Addr, nullptr));
     NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer1Addr);
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, &statePtr));
+
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1Addr, statePtr));
+    NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer1Addr);
+
+    NL_TEST_ASSERT(inSuite, (statePtr = connections.FindPeerConnectionState(kPeer1Addr, statePtr)) == nullptr);
+
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer2Addr, nullptr));
     NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
 }
 
 void TestFindByNodeId(nlTestSuite * inSuite, void * inContext)
 {
     CHIP_ERROR err;
     PeerConnectionState * statePtr;
-    PeerConnections<2, Time::Source::kTest> connections;
+    PeerConnections<3, Time::Source::kTest> connections;
 
     err = connections.CreateNewPeerConnectionState(kPeer1Addr, &statePtr);
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
@@ -113,16 +124,28 @@
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
     statePtr->SetPeerNodeId(kPeer2NodeId);
 
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer1NodeId, &statePtr));
+    err = connections.CreateNewPeerConnectionState(kPeer2Addr, &statePtr);
+    NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+    statePtr->SetPeerNodeId(kPeer1NodeId);
+
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1NodeId, nullptr));
+    char buf[100];
+    statePtr->GetPeerAddress().ToString(buf, sizeof(buf));
     NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer1Addr);
     NL_TEST_ASSERT(inSuite, statePtr->GetPeerNodeId() == kPeer1NodeId);
 
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2NodeId, &statePtr));
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1NodeId, statePtr));
+    statePtr->GetPeerAddress().ToString(buf, sizeof(buf));
+    NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
+    NL_TEST_ASSERT(inSuite, statePtr->GetPeerNodeId() == kPeer1NodeId);
+
+    NL_TEST_ASSERT(inSuite, (statePtr = connections.FindPeerConnectionState(kPeer1NodeId, statePtr)) == nullptr);
+
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer2NodeId, nullptr));
     NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
     NL_TEST_ASSERT(inSuite, statePtr->GetPeerNodeId() == kPeer2NodeId);
 
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3NodeId, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3NodeId, nullptr));
 }
 
 void TestFindByKeyId(nlTestSuite * inSuite, void * inContext)
@@ -136,45 +159,39 @@
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
 
     // Lookup using no node, and peer key
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 1, &statePtr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 1, nullptr));
     // Lookup using no node, and local key
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 2, &statePtr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 2, nullptr));
 
     // Lookup using no node, and incorrect peer key
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 2, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 2, nullptr));
 
     // Lookup using no node, and incorrect local key
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 1, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 1, nullptr));
 
     // Lookup using a node ID, and peer key
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 1, &statePtr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 1, nullptr));
 
     // Lookup using a node ID, and local key
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 2, &statePtr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 2, nullptr));
 
     // Some Node ID, peer key 3, local key 4
     err = connections.CreateNewPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 3, 4, &statePtr);
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
 
     // Lookup using correct node (or no node), and correct keys
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 3, &statePtr));
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 4, &statePtr));
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 3, &statePtr));
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 4, &statePtr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 3, nullptr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 4, nullptr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 3, nullptr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 4, nullptr));
 
     // Lookup using incorrect keys
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 4, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 3, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 4, nullptr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 3, nullptr));
 
     // Lookup using incorrect node, but correct keys
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer2NodeId), 3, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer2NodeId), 4, &statePtr));
-    NL_TEST_ASSERT(inSuite, statePtr == nullptr);
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer2NodeId), 3, nullptr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer2NodeId), 4, nullptr));
 }
 
 struct ExpiredCallInfo
@@ -220,7 +237,7 @@
     NL_TEST_ASSERT(inSuite, callInfo.callCount == 1);
     NL_TEST_ASSERT(inSuite, callInfo.lastCallNodeId == kUndefinedNodeId);
     NL_TEST_ASSERT(inSuite, callInfo.lastCallPeerAddress == kPeer1Addr);
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1NodeId, &statePtr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1NodeId, nullptr));
 
     // now that the connections were expired, we can add peer3
     connections.GetTimeSource().SetCurrentMonotonicTimeMs(300);
@@ -229,7 +246,7 @@
     statePtr->SetPeerNodeId(kPeer3NodeId);
 
     connections.GetTimeSource().SetCurrentMonotonicTimeMs(400);
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2NodeId, &statePtr));
+    NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer2NodeId, nullptr));
 
     connections.MarkConnectionActive(statePtr);
     NL_TEST_ASSERT(inSuite, statePtr->GetLastActivityTimeMs() == connections.GetTimeSource().GetCurrentMonotonicTimeMs());
@@ -246,24 +263,24 @@
     NL_TEST_ASSERT(inSuite, callInfo.callCount == 1);
     NL_TEST_ASSERT(inSuite, callInfo.lastCallNodeId == kPeer3NodeId);
     NL_TEST_ASSERT(inSuite, callInfo.lastCallPeerAddress == kPeer3Addr);
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, &statePtr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1Addr, nullptr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, nullptr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
 
     err = connections.CreateNewPeerConnectionState(kPeer1Addr, nullptr);
     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer1Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, &statePtr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer1Addr, nullptr));
+    NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, nullptr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
 
     // peer 1 and 2 are active
     connections.GetTimeSource().SetCurrentMonotonicTimeMs(1000);
     callInfo.callCount = 0;
     connections.ExpireInactiveConnections(100);
     NL_TEST_ASSERT(inSuite, callInfo.callCount == 2); // everything expired
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer2Addr, &statePtr));
-    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, &statePtr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1Addr, nullptr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer2Addr, nullptr));
+    NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
 }
 
 } // namespace