[nrfconnect] Initial Matter over WiFi implementation. (#23607)

* [nrfconnect] Initial Matter over WiFi implementation.

Some WiFi related features might not work as expected yet.
This will be fixed when the Zephyr NRF WiFi module is improved.
All implementations have been synchronized to sdk-nrf v2.1.1.

Commits included:
- Prepare configuration for hci_rpmsg
- Adapt Android CHIPTool guide to Wi-Fi devices
Make the guide a little bit more aware of the world of
Wi-Fi devices.
- Disable Wi-Fi low-power mode
Noticed Wi-Fi low-power mode causes performance issues,
at least with some APs.
- Implemented the WiFiNetworkIterator.
Replaced dummy implementation of WiFiNetworkIterator
This fixes an issue with infinite loop when using this iterator in Matter core.
- Added including CHIPMemString.h to fix WiFi build

Signed-off-by: Marcin Kajor <marcin.kajor@nordicsemi.no>
Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no>
Signed-off-by: Kamil Kasperczyk <kamil.kasperczyk@nordicsemi.no>
Signed-off-by: Arkadiusz Balys <arkadiusz.balys@nordicsemi.no>

* Restyled by prettier-markdown

Restyled by gn

Signed-off-by: Marcin Kajor <marcin.kajor@nordicsemi.no>
Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no>
Signed-off-by: Kamil Kasperczyk <kamil.kasperczyk@nordicsemi.no>
Signed-off-by: Arkadiusz Balys <arkadiusz.balys@nordicsemi.no>
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/src/platform/Zephyr/BLEManagerImpl.cpp b/src/platform/Zephyr/BLEManagerImpl.cpp
index d65b7a9..88edbd3 100644
--- a/src/platform/Zephyr/BLEManagerImpl.cpp
+++ b/src/platform/Zephyr/BLEManagerImpl.cpp
@@ -28,6 +28,7 @@
 #include <platform/Zephyr/BLEManagerImpl.h>
 
 #include <ble/CHIPBleServiceData.h>
+#include <lib/support/CHIPMemString.h>
 #include <lib/support/CodeUtils.h>
 #include <lib/support/logging/CHIPLogging.h>
 #include <platform/DeviceInstanceInfoProvider.h>
diff --git a/src/platform/Zephyr/ConfigurationManagerImpl.cpp b/src/platform/Zephyr/ConfigurationManagerImpl.cpp
index 107579a..378e35e 100644
--- a/src/platform/Zephyr/ConfigurationManagerImpl.cpp
+++ b/src/platform/Zephyr/ConfigurationManagerImpl.cpp
@@ -27,8 +27,11 @@
 #include <platform/internal/GenericConfigurationManagerImpl.ipp>
 
 #include <lib/core/CHIPVendorIdentifiers.hpp>
+
 #include <platform/Zephyr/ZephyrConfig.h>
 
+#include "InetUtils.h"
+
 #include <lib/support/CodeUtils.h>
 #include <lib/support/logging/CHIPLogging.h>
 
@@ -201,6 +204,21 @@
     PlatformMgr().Shutdown();
 }
 
+CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * buf)
+{
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
+    const net_if * const iface = InetUtils::GetInterface();
+    VerifyOrReturnError(iface != nullptr && iface->if_dev != nullptr, CHIP_ERROR_INTERNAL);
+
+    const auto linkAddrStruct = iface->if_dev->link_addr;
+    memcpy(buf, linkAddrStruct.addr, linkAddrStruct.len);
+
+    return CHIP_NO_ERROR;
+#else
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+#endif
+}
+
 ConfigurationManager & ConfigurationMgrImpl()
 {
     return ConfigurationManagerImpl::GetDefaultInstance();
diff --git a/src/platform/Zephyr/ConfigurationManagerImpl.h b/src/platform/Zephyr/ConfigurationManagerImpl.h
index 166237f..87f9e30 100644
--- a/src/platform/Zephyr/ConfigurationManagerImpl.h
+++ b/src/platform/Zephyr/ConfigurationManagerImpl.h
@@ -94,11 +94,6 @@
     return Internal::ZephyrConfig::WriteConfigValueCounter(key, value);
 }
 
-inline CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * /* buf */)
-{
-    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
-}
-
 /**
  * Returns the platform-specific implementation of the ConfigurationManager object.
  *
diff --git a/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp b/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp
index 1eb2439..c1fb842 100644
--- a/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp
+++ b/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp
@@ -116,7 +116,7 @@
     return sInstance;
 }
 
-inline DiagnosticDataProviderImpl::DiagnosticDataProviderImpl() : mBootReason(DetermineBootReason())
+DiagnosticDataProviderImpl::DiagnosticDataProviderImpl() : mBootReason(DetermineBootReason())
 {
     ChipLogDetail(DeviceLayer, "Boot reason: %u", static_cast<uint16_t>(mBootReason));
 }
@@ -328,10 +328,5 @@
     }
 }
 
-DiagnosticDataProvider & GetDiagnosticDataProviderImpl()
-{
-    return DiagnosticDataProviderImpl::GetDefaultInstance();
-}
-
 } // namespace DeviceLayer
 } // namespace chip
diff --git a/src/platform/Zephyr/DiagnosticDataProviderImpl.h b/src/platform/Zephyr/DiagnosticDataProviderImpl.h
index 2b46051..69bbae5 100644
--- a/src/platform/Zephyr/DiagnosticDataProviderImpl.h
+++ b/src/platform/Zephyr/DiagnosticDataProviderImpl.h
@@ -52,9 +52,10 @@
     CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override;
     void ReleaseNetworkInterfaces(NetworkInterface * netifp) override;
 
-private:
+protected:
     DiagnosticDataProviderImpl();
 
+private:
     const BootReasonType mBootReason;
 };
 
diff --git a/src/platform/Zephyr/DiagnosticDataProviderImplGetter.cpp b/src/platform/Zephyr/DiagnosticDataProviderImplGetter.cpp
new file mode 100644
index 0000000..6b920d1
--- /dev/null
+++ b/src/platform/Zephyr/DiagnosticDataProviderImplGetter.cpp
@@ -0,0 +1,29 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "DiagnosticDataProviderImpl.h"
+
+namespace chip {
+namespace DeviceLayer {
+
+DiagnosticDataProvider & GetDiagnosticDataProviderImpl()
+{
+    return DiagnosticDataProviderImpl::GetDefaultInstance();
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Zephyr/InetUtils.cpp b/src/platform/Zephyr/InetUtils.cpp
new file mode 100644
index 0000000..1169cf6
--- /dev/null
+++ b/src/platform/Zephyr/InetUtils.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "InetUtils.h"
+
+namespace chip {
+namespace DeviceLayer {
+namespace InetUtils {
+
+in6_addr ToZephyrAddr(const chip::Inet::IPAddress & address)
+{
+    in6_addr zephyrAddr;
+
+    static_assert(sizeof(zephyrAddr.s6_addr) == sizeof(address.Addr), "Unexpected address size");
+    memcpy(zephyrAddr.s6_addr, address.Addr, sizeof(address.Addr));
+
+    return zephyrAddr;
+}
+
+net_if * GetInterface(chip::Inet::InterfaceId ifaceId)
+{
+    return ifaceId.IsPresent() ? net_if_get_by_index(ifaceId.GetPlatformInterface()) : net_if_get_default();
+}
+
+} // namespace InetUtils
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Zephyr/InetUtils.h b/src/platform/Zephyr/InetUtils.h
new file mode 100644
index 0000000..ad7c5e1
--- /dev/null
+++ b/src/platform/Zephyr/InetUtils.h
@@ -0,0 +1,32 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <inet/InetInterface.h>
+
+struct in6_addr;
+struct net_if;
+
+namespace chip {
+namespace DeviceLayer {
+namespace InetUtils {
+
+in6_addr ToZephyrAddr(const chip::Inet::IPAddress & address);
+net_if * GetInterface(chip::Inet::InterfaceId ifaceId = chip::Inet::InterfaceId::Null());
+
+} // namespace InetUtils
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/BUILD.gn b/src/platform/nrfconnect/BUILD.gn
index a841a2b..186b45e 100644
--- a/src/platform/nrfconnect/BUILD.gn
+++ b/src/platform/nrfconnect/BUILD.gn
@@ -41,6 +41,8 @@
     "ConfigurationManagerImpl.h",
     "ConnectivityManagerImpl.cpp",
     "ConnectivityManagerImpl.h",
+    "DiagnosticDataProviderImplNrf.cpp",
+    "DiagnosticDataProviderImplNrf.h",
     "ExternalFlashManager.h",
     "InetPlatformConfig.h",
     "KeyValueStoreManagerImpl.h",
@@ -80,6 +82,19 @@
     }
   }
 
+  if (chip_enable_wifi) {
+    sources += [
+      "../Zephyr/InetUtils.cpp",
+      "../Zephyr/InetUtils.h",
+      "wifi/ConnectivityManagerImplWiFi.cpp",
+      "wifi/ConnectivityManagerImplWiFi.h",
+      "wifi/NrfWiFiDriver.cpp",
+      "wifi/NrfWiFiDriver.h",
+      "wifi/WiFiManager.cpp",
+      "wifi/WiFiManager.h",
+    ]
+  }
+
   if (chip_enable_nfc) {
     sources += [
       "../Zephyr/NFCManagerImpl.cpp",
diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h
index 3813c86..5a82f16 100644
--- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h
+++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h
@@ -87,10 +87,17 @@
 #define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING
 #endif
 
+#define CHIP_DEVICE_CONFIG_ENABLE_THREAD CONFIG_NET_L2_OPENTHREAD
+
+#define CHIP_DEVICE_CONFIG_ENABLE_WIFI CONFIG_WIFI_NRF700X
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
+#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 1
+#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0
+#else
 #define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0
 #define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0
-
-#define CHIP_DEVICE_CONFIG_ENABLE_THREAD CONFIG_NET_L2_OPENTHREAD
+#endif
 
 #define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE CONFIG_BT
 
diff --git a/src/platform/nrfconnect/ConnectivityManagerImpl.cpp b/src/platform/nrfconnect/ConnectivityManagerImpl.cpp
index c5029f3..504b0d0 100644
--- a/src/platform/nrfconnect/ConnectivityManagerImpl.cpp
+++ b/src/platform/nrfconnect/ConnectivityManagerImpl.cpp
@@ -51,7 +51,9 @@
 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
     GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_Init();
 #endif
-
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
+    ReturnErrorOnFailure(InitWiFi());
+#endif
     return CHIP_NO_ERROR;
 }
 
diff --git a/src/platform/nrfconnect/ConnectivityManagerImpl.h b/src/platform/nrfconnect/ConnectivityManagerImpl.h
index 4c003f2..8ea6c2d 100644
--- a/src/platform/nrfconnect/ConnectivityManagerImpl.h
+++ b/src/platform/nrfconnect/ConnectivityManagerImpl.h
@@ -28,12 +28,18 @@
 #else
 #include <platform/internal/GenericConnectivityManagerImpl_NoBLE.h>
 #endif
+
 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
 #include <platform/internal/GenericConnectivityManagerImpl_Thread.h>
 #else
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
+#include "wifi/ConnectivityManagerImplWiFi.h"
+#else
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
+#endif
 
 #include <lib/support/logging/CHIPLogging.h>
 
@@ -65,7 +71,11 @@
 #else
                                       public Internal::GenericConnectivityManagerImpl_NoThread<ConnectivityManagerImpl>,
 #endif
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
+                                      public ConnectivityManagerImplWiFi
+#else
                                       public Internal::GenericConnectivityManagerImpl_NoWiFi<ConnectivityManagerImpl>
+#endif
 {
     // Allow the ConnectivityManager interface class to delegate method calls to
     // the implementation methods provided by this class.
@@ -100,7 +110,7 @@
  * Returns the platform-specific implementation of the ConnectivityManager singleton object.
  *
  * chip applications can use this to gain access to features of the ConnectivityManager
- * that are specific to the ESP32 platform.
+ * that are specific to the nrfconnect platform.
  */
 inline ConnectivityManagerImpl & ConnectivityMgrImpl(void)
 {
diff --git a/src/platform/nrfconnect/DiagnosticDataProviderImplNrf.cpp b/src/platform/nrfconnect/DiagnosticDataProviderImplNrf.cpp
new file mode 100644
index 0000000..5f7bc1a
--- /dev/null
+++ b/src/platform/nrfconnect/DiagnosticDataProviderImplNrf.cpp
@@ -0,0 +1,136 @@
+/*
+ *
+ *    Copyright (c) 2022 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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the DiagnosticDataProvider object
+ *          for nrfconnect platform.
+ */
+
+#include "DiagnosticDataProviderImplNrf.h"
+
+#ifdef CONFIG_WIFI_NRF700X
+#include <platform/nrfconnect/wifi/WiFiManager.h>
+#endif
+
+namespace chip {
+namespace DeviceLayer {
+
+DiagnosticDataProvider & GetDiagnosticDataProviderImpl()
+{
+    return DiagnosticDataProviderImplNrf::GetDefaultInstance();
+}
+
+DiagnosticDataProviderImplNrf & DiagnosticDataProviderImplNrf::GetDefaultInstance()
+{
+    static DiagnosticDataProviderImplNrf sInstance;
+    return sInstance;
+}
+
+#ifdef CONFIG_WIFI_NRF700X
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiBssId(ByteSpan & value)
+{
+    WiFiManager::WiFiInfo info;
+    CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info);
+    value          = info.mBssId;
+    return err;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiSecurityType(uint8_t & securityType)
+{
+    WiFiManager::WiFiInfo info;
+    CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info);
+    securityType   = info.mSecurityType;
+    return err;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiVersion(uint8_t & wiFiVersion)
+{
+    WiFiManager::WiFiInfo info;
+    CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info);
+    wiFiVersion    = info.mWiFiVersion;
+    return err;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiChannelNumber(uint16_t & channelNumber)
+{
+    WiFiManager::WiFiInfo info;
+    CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info);
+    channelNumber  = info.mChannel;
+    (void) err;
+    // above will return 0 until the wpa_supplicant driver API implementation is refined
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiRssi(int8_t & rssi)
+{
+    WiFiManager::WiFiInfo info;
+    CHIP_ERROR err = WiFiManager::Instance().GetWiFiInfo(info);
+    rssi           = info.mRssi;
+    (void) err;
+    // above will return -128 until the wpa_supplicant driver API implementation is refined
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+// below will be implemented when the WiFi driver exposes Zephyr NET_STATISTICS API
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiBeaconLostCount(uint32_t & beaconLostCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiBeaconRxCount(uint32_t & beaconRxCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiCurrentMaxRate(uint64_t & currentMaxRate)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::GetWiFiOverrunCount(uint64_t & overrunCount)
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+
+CHIP_ERROR DiagnosticDataProviderImplNrf::ResetWiFiNetworkDiagnosticsCounts()
+{
+    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
+}
+#endif
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/DiagnosticDataProviderImplNrf.h b/src/platform/nrfconnect/DiagnosticDataProviderImplNrf.h
new file mode 100644
index 0000000..3b770e6
--- /dev/null
+++ b/src/platform/nrfconnect/DiagnosticDataProviderImplNrf.h
@@ -0,0 +1,60 @@
+/*
+ *
+ *    Copyright (c) 2022 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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the DiagnosticDataProvider object
+ *           for nrfconnect platform.
+ */
+
+#pragma once
+
+#include <platform/Zephyr/DiagnosticDataProviderImpl.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+class DiagnosticDataProviderImplNrf : public DiagnosticDataProviderImpl
+{
+public:
+#ifdef CONFIG_WIFI_NRF700X
+    CHIP_ERROR GetWiFiBssId(ByteSpan & value) override;
+    CHIP_ERROR GetWiFiSecurityType(uint8_t & securityType) override;
+    CHIP_ERROR GetWiFiVersion(uint8_t & wiFiVersion) override;
+    CHIP_ERROR GetWiFiChannelNumber(uint16_t & channelNumber) override;
+    CHIP_ERROR GetWiFiRssi(int8_t & rssi) override;
+    CHIP_ERROR GetWiFiBeaconLostCount(uint32_t & beaconLostCount) override;
+    CHIP_ERROR GetWiFiBeaconRxCount(uint32_t & beaconRxCount) override;
+    CHIP_ERROR GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) override;
+    CHIP_ERROR GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) override;
+    CHIP_ERROR GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) override;
+    CHIP_ERROR GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) override;
+    CHIP_ERROR GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) override;
+    CHIP_ERROR GetWiFiOverrunCount(uint64_t & overrunCount) override;
+    CHIP_ERROR ResetWiFiNetworkDiagnosticsCounts() override;
+#endif
+
+    static DiagnosticDataProviderImplNrf & GetDefaultInstance();
+
+private:
+    DiagnosticDataProviderImplNrf() = default;
+};
+
+DiagnosticDataProvider & GetDiagnosticDataProviderImpl();
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp
new file mode 100644
index 0000000..73e1630
--- /dev/null
+++ b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp
@@ -0,0 +1,228 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/* this file behaves like a config.h, comes first */
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <platform/CommissionableDataProvider.h>
+#include <platform/ConnectivityManager.h>
+
+#include "ConnectivityManagerImplWiFi.h"
+#include "WiFiManager.h"
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
+
+using namespace ::chip;
+using namespace ::chip::Inet;
+using namespace ::chip::System;
+using namespace ::chip::TLV;
+
+namespace chip {
+namespace DeviceLayer {
+
+CHIP_ERROR ConnectivityManagerImplWiFi::InitWiFi()
+{
+    return WiFiManager::Instance().Init();
+}
+
+ConnectivityManager::WiFiStationMode ConnectivityManagerImplWiFi::_GetWiFiStationMode(void)
+{
+    if (mStationMode != ConnectivityManager::WiFiStationMode::kWiFiStationMode_ApplicationControlled)
+    {
+        mStationMode = (WiFiManager::StationStatus::DISABLED == WiFiManager().Instance().GetStationStatus())
+            ? ConnectivityManager::WiFiStationMode::kWiFiStationMode_Disabled
+            : ConnectivityManager::WiFiStationMode::kWiFiStationMode_Enabled;
+    }
+    return mStationMode;
+}
+
+CHIP_ERROR ConnectivityManagerImplWiFi::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode aMode)
+{
+    VerifyOrReturnError(ConnectivityManager::WiFiStationMode::kWiFiStationMode_NotSupported != aMode,
+                        CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
+
+    if (aMode != mStationMode)
+    {
+        mStationMode = aMode;
+        if (mStationMode != ConnectivityManager::WiFiStationMode::kWiFiStationMode_ApplicationControlled)
+        {
+            bool doEnable{ ConnectivityManager::WiFiStationMode::kWiFiStationMode_Enabled == mStationMode };
+            // TODO: when the connection/disconnection callback API is provided
+            // below calls should be used as a base of disconnect callback
+            if (doEnable)
+            {
+                OnStationConnected();
+            }
+            else
+            {
+                OnStationDisconnected();
+            }
+        }
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+bool ConnectivityManagerImplWiFi::_IsWiFiStationEnabled(void)
+{
+    return (WiFiManager::StationStatus::DISABLED <= WiFiManager().Instance().GetStationStatus());
+}
+
+bool ConnectivityManagerImplWiFi::_IsWiFiStationApplicationControlled(void)
+{
+    return (ConnectivityManager::WiFiStationMode::kWiFiStationMode_ApplicationControlled == mStationMode);
+}
+
+bool ConnectivityManagerImplWiFi::_IsWiFiStationConnected(void)
+{
+    return (WiFiManager::StationStatus::FULLY_PROVISIONED == WiFiManager().Instance().GetStationStatus());
+}
+
+System::Clock::Timeout ConnectivityManagerImplWiFi::_GetWiFiStationReconnectInterval(void)
+{
+    return mWiFiStationReconnectInterval;
+}
+
+CHIP_ERROR ConnectivityManagerImplWiFi::_SetWiFiStationReconnectInterval(System::Clock::Timeout val)
+{
+    mWiFiStationReconnectInterval = val;
+    return CHIP_NO_ERROR;
+}
+
+bool ConnectivityManagerImplWiFi::_IsWiFiStationProvisioned(void)
+{
+    // from Matter perspective `provisioned` means that the supplicant has been provided
+    // with SSID and password (doesn't matter if valid or not)
+    return (WiFiManager::StationStatus::CONNECTING <= WiFiManager().Instance().GetStationStatus());
+}
+
+void ConnectivityManagerImplWiFi::_ClearWiFiStationProvision(void)
+{
+    if (_IsWiFiStationProvisioned())
+    {
+        if (CHIP_NO_ERROR != WiFiManager().Instance().ClearStationProvisioningData())
+        {
+            ChipLogError(DeviceLayer, "Cannot clear WiFi station provisioning data");
+        }
+    }
+}
+
+bool ConnectivityManagerImplWiFi::_CanStartWiFiScan()
+{
+    return (WiFiManager::StationStatus::DISABLED != WiFiManager().Instance().GetStationStatus() &&
+            WiFiManager::StationStatus::SCANNING != WiFiManager().Instance().GetStationStatus() &&
+            WiFiManager::StationStatus::CONNECTING != WiFiManager().Instance().GetStationStatus());
+}
+
+void ConnectivityManagerImplWiFi::_OnWiFiStationProvisionChange()
+{
+    // do nothing
+}
+
+void ConnectivityManagerImplWiFi::_OnWiFiScanDone() {}
+
+CHIP_ERROR ConnectivityManagerImplWiFi::_GetAndLogWiFiStatsCounters(void)
+{
+    // TODO: when network statistics are enabled
+    return CHIP_NO_ERROR;
+}
+
+void ConnectivityManagerImplWiFi::OnStationConnected()
+{
+    // ensure the station is connected
+    if (_IsWiFiStationConnected())
+    {
+        ChipDeviceEvent connectEvent{};
+        connectEvent.Type                          = DeviceEventType::kWiFiConnectivityChange;
+        connectEvent.WiFiConnectivityChange.Result = kConnectivity_Established;
+        PlatformMgr().PostEventOrDie(&connectEvent);
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "WiFi Station is not connected!");
+    }
+}
+
+void ConnectivityManagerImplWiFi::OnStationDisconnected()
+{
+    // ensure the station is disconnected
+    if (WiFiManager::StationStatus::DISCONNECTED == WiFiManager().Instance().GetStationStatus())
+    {
+        ChipDeviceEvent disconnectEvent{};
+        disconnectEvent.Type                          = DeviceEventType::kWiFiConnectivityChange;
+        disconnectEvent.WiFiConnectivityChange.Result = kConnectivity_Lost;
+        PlatformMgr().PostEventOrDie(&disconnectEvent);
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "WiFi Station is not disconnected!");
+    }
+}
+
+ConnectivityManager::WiFiAPMode ConnectivityManagerImplWiFi::_GetWiFiAPMode(void)
+{
+    /* AP mode is unsupported */
+    return ConnectivityManager::WiFiAPMode::kWiFiAPMode_NotSupported;
+}
+
+CHIP_ERROR ConnectivityManagerImplWiFi::_SetWiFiAPMode(ConnectivityManager::WiFiAPMode mode)
+{
+    /* AP mode is unsupported */
+    VerifyOrReturnError(ConnectivityManager::WiFiAPMode::kWiFiAPMode_NotSupported == mode ||
+                            ConnectivityManager::WiFiAPMode::kWiFiAPMode_Disabled == mode,
+                        CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
+    return CHIP_NO_ERROR;
+}
+
+bool ConnectivityManagerImplWiFi::_IsWiFiAPActive(void)
+{
+    /* AP mode is unsupported */
+    return false;
+}
+
+bool ConnectivityManagerImplWiFi::_IsWiFiAPApplicationControlled(void)
+{
+    /* AP mode is unsupported */
+    return false;
+}
+
+void ConnectivityManagerImplWiFi::_DemandStartWiFiAP(void)
+{ /* AP mode is unsupported */
+}
+
+void ConnectivityManagerImplWiFi::_StopOnDemandWiFiAP(void)
+{ /* AP mode is unsupported */
+}
+
+void ConnectivityManagerImplWiFi::_MaintainOnDemandWiFiAP(void)
+{ /* AP mode is unsupported */
+}
+
+System::Clock::Timeout ConnectivityManagerImplWiFi::_GetWiFiAPIdleTimeout(void)
+{
+    /* AP mode is unsupported */
+    return System::Clock::kZero;
+}
+
+void ConnectivityManagerImplWiFi::_SetWiFiAPIdleTimeout(System::Clock::Timeout val)
+{ /* AP mode is unsupported */
+}
+
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI
diff --git a/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h
new file mode 100644
index 0000000..8198453
--- /dev/null
+++ b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h
@@ -0,0 +1,82 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <platform/ConnectivityManager.h>
+
+#include <platform/internal/GenericConnectivityManagerImpl_WiFi.h>
+
+#include <lib/support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace Inet {
+class IPAddress;
+} // namespace Inet
+} // namespace chip
+
+namespace chip {
+namespace DeviceLayer {
+
+class ConnectivityManagerImplWiFi
+{
+    friend class ConnectivityManager;
+
+protected:
+    CHIP_ERROR InitWiFi();
+
+private:
+    // Wi-Fi station
+    ConnectivityManager::WiFiStationMode _GetWiFiStationMode(void);
+    CHIP_ERROR _SetWiFiStationMode(ConnectivityManager::WiFiStationMode val);
+    bool _IsWiFiStationEnabled(void);
+    bool _IsWiFiStationApplicationControlled(void);
+    bool _IsWiFiStationConnected(void);
+    System::Clock::Timeout _GetWiFiStationReconnectInterval(void);
+    CHIP_ERROR _SetWiFiStationReconnectInterval(System::Clock::Timeout val);
+    bool _IsWiFiStationProvisioned(void);
+    void _ClearWiFiStationProvision(void);
+    CHIP_ERROR _GetAndLogWiFiStatsCounters(void);
+    bool _CanStartWiFiScan();
+    void _OnWiFiScanDone();
+    void _OnWiFiStationProvisionChange();
+    void OnStationConnected();
+    void OnStationDisconnected();
+
+    // Wi-Fi access point - not supported
+    ConnectivityManager::WiFiAPMode _GetWiFiAPMode(void);
+    CHIP_ERROR _SetWiFiAPMode(ConnectivityManager::WiFiAPMode val);
+    bool _IsWiFiAPActive(void);
+    bool _IsWiFiAPApplicationControlled(void);
+    void _DemandStartWiFiAP(void);
+    void _StopOnDemandWiFiAP(void);
+    void _MaintainOnDemandWiFiAP(void);
+    System::Clock::Timeout _GetWiFiAPIdleTimeout(void);
+    void _SetWiFiAPIdleTimeout(System::Clock::Timeout val);
+
+    ConnectivityManager::WiFiStationMode mStationMode{ ConnectivityManager::WiFiStationMode::kWiFiStationMode_Disabled };
+    ConnectivityManager::WiFiStationState mStationState{ ConnectivityManager::WiFiStationState::kWiFiStationState_NotConnected };
+    System::Clock::Timeout mWiFiStationReconnectInterval{};
+
+    static const char * _WiFiStationModeToStr(ConnectivityManager::WiFiStationMode mode);
+    static const char * _WiFiAPModeToStr(ConnectivityManager::WiFiAPMode mode);
+    static const char * _WiFiStationStateToStr(ConnectivityManager::WiFiStationState state);
+    static const char * _WiFiAPStateToStr(ConnectivityManager::WiFiAPState state);
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp b/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp
new file mode 100644
index 0000000..5092384
--- /dev/null
+++ b/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp
@@ -0,0 +1,284 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "NrfWiFiDriver.h"
+
+#include "WiFiManager.h"
+#include <platform/KeyValueStoreManager.h>
+
+#include <lib/support/CodeUtils.h>
+#include <lib/support/SafeInt.h>
+#include <platform/CHIPDeviceLayer.h>
+
+using namespace ::chip;
+using namespace ::chip::DeviceLayer::Internal;
+using namespace ::chip::DeviceLayer::PersistedStorage;
+
+namespace chip {
+namespace DeviceLayer {
+namespace NetworkCommissioning {
+
+size_t NrfWiFiDriver::WiFiNetworkIterator::Count()
+{
+    VerifyOrReturnValue(mDriver != nullptr, 0);
+    return mDriver->mStagingNetwork.IsConfigured() ? 1 : 0;
+}
+
+bool NrfWiFiDriver::WiFiNetworkIterator::Next(Network & item)
+{
+    // we assume only one network is actually supported
+    // TODO: verify if this can be extended
+    if (mExhausted || 0 == Count())
+    {
+        return false;
+    }
+
+    memcpy(item.networkID, mDriver->mStagingNetwork.ssid, mDriver->mStagingNetwork.ssidLen);
+    item.networkIDLen = mDriver->mStagingNetwork.ssidLen;
+    item.connected    = false;
+
+    mExhausted = true;
+
+    WiFiManager::WiFiInfo wifiInfo;
+    if (CHIP_NO_ERROR == WiFiManager::Instance().GetWiFiInfo(wifiInfo))
+    {
+        if (WiFiManager::StationStatus::CONNECTED <= WiFiManager::Instance().GetStationStatus())
+        {
+            if (wifiInfo.mSsidLen == item.networkIDLen && 0 == memcmp(wifiInfo.mSsid, item.networkID, wifiInfo.mSsidLen))
+            {
+                item.connected = true;
+            }
+        }
+    }
+    return true;
+}
+
+bool NrfWiFiScanResponseIterator::Next(WiFiScanResponse & item)
+{
+    if (mResultId < mResultCount)
+    {
+        item = mResults[mResultId++];
+        return true;
+    }
+    return false;
+}
+
+void NrfWiFiScanResponseIterator::Release()
+{
+    mResultId = mResultCount = 0;
+    Platform::MemoryFree(mResults);
+    mResults = nullptr;
+}
+
+void NrfWiFiScanResponseIterator::Add(const WiFiScanResponse & result)
+{
+    void * newResults = Platform::MemoryRealloc(mResults, (mResultCount + 1) * sizeof(WiFiScanResponse));
+
+    if (newResults)
+    {
+        mResults                 = static_cast<WiFiScanResponse *>(newResults);
+        mResults[mResultCount++] = result;
+    }
+}
+
+CHIP_ERROR NrfWiFiDriver::Init(NetworkStatusChangeCallback * networkStatusChangeCallback)
+{
+    mpNetworkStatusChangeCallback = networkStatusChangeCallback;
+
+    LoadFromStorage();
+
+    if (mStagingNetwork.IsConfigured())
+    {
+        WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); },
+                                                  [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); },
+                                                  System::Clock::Timeout{ 40000 } };
+        ReturnErrorOnFailure(
+            WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling));
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+void NrfWiFiDriver::OnNetworkStatusChanged(Status status)
+{
+    if (status == Status::kSuccess)
+    {
+        ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled);
+    }
+
+    if (mpNetworkStatusChangeCallback)
+        mpNetworkStatusChangeCallback->OnNetworkingStatusChange(status, NullOptional, NullOptional);
+}
+
+void NrfWiFiDriver::Shutdown()
+{
+    mpNetworkStatusChangeCallback = nullptr;
+}
+
+CHIP_ERROR NrfWiFiDriver::CommitConfiguration()
+{
+    ReturnErrorOnFailure(KeyValueStoreMgr().Put(kPassKey, mStagingNetwork.pass, mStagingNetwork.passLen));
+    ReturnErrorOnFailure(KeyValueStoreMgr().Put(kSsidKey, mStagingNetwork.ssid, mStagingNetwork.ssidLen));
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR NrfWiFiDriver::RevertConfiguration()
+{
+    LoadFromStorage();
+
+    if (mStagingNetwork.IsConfigured())
+    {
+        WiFiManager::ConnectionHandling handling{ [] { Instance().OnConnectWiFiNetwork(); },
+                                                  [] { Instance().OnConnectWiFiNetworkFailed(); },
+                                                  System::Clock::Timeout{ 40000 } };
+        ReturnErrorOnFailure(
+            WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling));
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+Status NrfWiFiDriver::AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, MutableCharSpan & outDebugText,
+                                         uint8_t & outNetworkIndex)
+{
+    outDebugText    = {};
+    outNetworkIndex = 0;
+
+    VerifyOrReturnError(!mStagingNetwork.IsConfigured() || ssid.data_equal(mStagingNetwork.GetSsidSpan()), Status::kBoundsExceeded);
+    VerifyOrReturnError(ssid.size() <= sizeof(mStagingNetwork.ssid), Status::kOutOfRange);
+    VerifyOrReturnError(credentials.size() <= sizeof(mStagingNetwork.pass), Status::kOutOfRange);
+
+    memcpy(mStagingNetwork.ssid, ssid.data(), ssid.size());
+    memcpy(mStagingNetwork.pass, credentials.data(), credentials.size());
+    mStagingNetwork.ssidLen = ssid.size();
+    mStagingNetwork.passLen = credentials.size();
+
+    return Status::kSuccess;
+}
+
+Status NrfWiFiDriver::RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex)
+{
+    outDebugText    = {};
+    outNetworkIndex = 0;
+
+    VerifyOrReturnError(networkId.data_equal(mStagingNetwork.GetSsidSpan()), Status::kNetworkIDNotFound);
+    mStagingNetwork.Clear();
+
+    return Status::kSuccess;
+}
+
+Status NrfWiFiDriver::ReorderNetwork(ByteSpan networkId, uint8_t index, MutableCharSpan & outDebugText)
+{
+    outDebugText = {};
+
+    // Only one network is supported for now
+    VerifyOrReturnError(index == 0, Status::kOutOfRange);
+    VerifyOrReturnError(networkId.data_equal(mStagingNetwork.GetSsidSpan()), Status::kNetworkIDNotFound);
+
+    return Status::kSuccess;
+}
+
+void NrfWiFiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callback)
+{
+    Status status = Status::kSuccess;
+    WiFiManager::ConnectionHandling handling{ [] { Instance().OnConnectWiFiNetwork(); },
+                                              [] { Instance().OnConnectWiFiNetworkFailed(); }, System::Clock::Timeout{ 40000 } };
+
+    VerifyOrExit(networkId.data_equal(mStagingNetwork.GetSsidSpan()), status = Status::kNetworkIDNotFound);
+    VerifyOrExit(mpConnectCallback == nullptr, status = Status::kUnknownError);
+
+    mpConnectCallback = callback;
+    WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling);
+
+exit:
+    if (status != Status::kSuccess)
+    {
+        mpConnectCallback = nullptr;
+        callback->OnResult(status, CharSpan(), 0);
+    }
+}
+
+CHIP_ERROR GetConfiguredNetwork(Network & network)
+{
+    return CHIP_NO_ERROR;
+}
+
+void NrfWiFiDriver::OnConnectWiFiNetwork()
+{
+    ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled);
+
+    if (mpConnectCallback)
+    {
+        mpConnectCallback->OnResult(Status::kSuccess, CharSpan(), 0);
+        mpConnectCallback = nullptr;
+    }
+}
+
+void NrfWiFiDriver::OnConnectWiFiNetworkFailed()
+{
+    if (mpConnectCallback)
+    {
+        mpConnectCallback->OnResult(Status::kNetworkNotFound, CharSpan(), 0);
+        mpConnectCallback = nullptr;
+    }
+}
+
+void NrfWiFiDriver::ScanNetworks(ByteSpan ssid, WiFiDriver::ScanCallback * callback)
+{
+    mScanCallback    = callback;
+    CHIP_ERROR error = WiFiManager::Instance().Scan(
+        ssid, [](int status, WiFiScanResponse * response) { Instance().OnScanWiFiNetworkDone(status, response); });
+
+    if (error != CHIP_NO_ERROR)
+    {
+        mScanCallback = nullptr;
+        callback->OnFinished(Status::kUnknownError, CharSpan(), nullptr);
+    }
+}
+
+void NrfWiFiDriver::OnScanWiFiNetworkDone(int status, WiFiScanResponse * response)
+{
+    if (response != nullptr)
+    {
+        StackLock lock;
+        VerifyOrReturn(mScanCallback != nullptr);
+        mScanResponseIterator.Add(*response);
+        return;
+    }
+
+    // Scan complete
+    DeviceLayer::SystemLayer().ScheduleLambda([this, status]() {
+        VerifyOrReturn(mScanCallback != nullptr);
+        mScanCallback->OnFinished(status == 0 ? Status::kSuccess : Status::kUnknownError, CharSpan(), &mScanResponseIterator);
+        mScanCallback = nullptr;
+    });
+}
+
+void NrfWiFiDriver::LoadFromStorage()
+{
+    WiFiNetwork network;
+
+    mStagingNetwork = {};
+    ReturnOnFailure(KeyValueStoreMgr().Get(kSsidKey, network.ssid, sizeof(network.ssid), &network.ssidLen));
+    ReturnOnFailure(KeyValueStoreMgr().Get(kPassKey, network.pass, sizeof(network.pass), &network.passLen));
+    mStagingNetwork = network;
+}
+
+} // namespace NetworkCommissioning
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/wifi/NrfWiFiDriver.h b/src/platform/nrfconnect/wifi/NrfWiFiDriver.h
new file mode 100644
index 0000000..880cce8
--- /dev/null
+++ b/src/platform/nrfconnect/wifi/NrfWiFiDriver.h
@@ -0,0 +1,123 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <platform/NetworkCommissioning.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace NetworkCommissioning {
+
+constexpr uint8_t kMaxWiFiNetworks                  = 1;
+constexpr uint8_t kWiFiScanNetworksTimeOutSeconds   = 10;
+constexpr uint8_t kWiFiConnectNetworkTimeoutSeconds = 120;
+
+class NrfWiFiScanResponseIterator : public Iterator<WiFiScanResponse>
+{
+public:
+    size_t Count() override { return mResultCount; }
+    bool Next(WiFiScanResponse & item) override;
+    void Release() override;
+    void Add(const WiFiScanResponse & result);
+
+private:
+    size_t mResultId            = 0;
+    size_t mResultCount         = 0;
+    WiFiScanResponse * mResults = nullptr;
+};
+
+class NrfWiFiDriver final : public WiFiDriver
+{
+public:
+    // Define non-volatile storage keys for SSID and password.
+    // The naming convention is aligned with DefaultStorageKeyAllocator class.
+    static constexpr const char * kSsidKey = "g/wi/s";
+    static constexpr const char * kPassKey = "g/wi/p";
+
+    class WiFiNetworkIterator final : public NetworkIterator
+    {
+    public:
+        WiFiNetworkIterator(NrfWiFiDriver * aDriver) : mDriver(aDriver) {}
+        size_t Count() override;
+        bool Next(Network & item) override;
+        void Release() override { delete this; }
+        ~WiFiNetworkIterator() = default;
+
+    private:
+        NrfWiFiDriver * mDriver;
+        bool mExhausted{ false };
+    };
+
+    struct WiFiNetwork
+    {
+        uint8_t ssid[DeviceLayer::Internal::kMaxWiFiSSIDLength];
+        size_t ssidLen = 0;
+        uint8_t pass[DeviceLayer::Internal::kMaxWiFiKeyLength];
+        size_t passLen = 0;
+
+        bool IsConfigured() const { return ssidLen > 0; }
+        ByteSpan GetSsidSpan() const { return ByteSpan(ssid, ssidLen); }
+        ByteSpan GetPassSpan() const { return ByteSpan(pass, passLen); }
+        void Clear() { ssidLen = 0; }
+    };
+
+    // BaseDriver
+    NetworkIterator * GetNetworks() override { return new WiFiNetworkIterator(this); }
+    CHIP_ERROR Init(NetworkStatusChangeCallback * networkStatusChangeCallback) override;
+    void Shutdown() override;
+
+    // WirelessDriver
+    uint8_t GetMaxNetworks() override { return kMaxWiFiNetworks; }
+    uint8_t GetScanNetworkTimeoutSeconds() override { return kWiFiScanNetworksTimeOutSeconds; }
+    uint8_t GetConnectNetworkTimeoutSeconds() override { return kWiFiConnectNetworkTimeoutSeconds; }
+
+    CHIP_ERROR CommitConfiguration() override;
+    CHIP_ERROR RevertConfiguration() override;
+
+    Status RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) override;
+    Status ReorderNetwork(ByteSpan networkId, uint8_t index, MutableCharSpan & outDebugText) override;
+    void ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) override;
+
+    // WiFiDriver
+    Status AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, MutableCharSpan & outDebugText,
+                              uint8_t & outNetworkIndex) override;
+    void ScanNetworks(ByteSpan ssid, ScanCallback * callback) override;
+
+    static NrfWiFiDriver & Instance()
+    {
+        static NrfWiFiDriver sInstance;
+        return sInstance;
+    }
+
+    void OnConnectWiFiNetwork();
+    void OnConnectWiFiNetworkFailed();
+    void OnNetworkStatusChanged(Status status);
+    void OnScanWiFiNetworkDone(int status, WiFiScanResponse * result);
+
+private:
+    void LoadFromStorage();
+
+    ConnectCallback * mpConnectCallback{ nullptr };
+    NetworkStatusChangeCallback * mpNetworkStatusChangeCallback{ nullptr };
+    WiFiNetwork mStagingNetwork;
+    NrfWiFiScanResponseIterator mScanResponseIterator;
+    ScanCallback * mScanCallback{ nullptr };
+};
+
+} // namespace NetworkCommissioning
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/wifi/WiFiManager.cpp b/src/platform/nrfconnect/wifi/WiFiManager.cpp
new file mode 100644
index 0000000..0a0e50c
--- /dev/null
+++ b/src/platform/nrfconnect/wifi/WiFiManager.cpp
@@ -0,0 +1,447 @@
+/*
+ *
+ *    Copyright (c) 2022 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.
+ */
+
+/**
+ *    @file
+ *          Provides the wrapper for nRF WiFi API
+ */
+
+#include "WiFiManager.h"
+
+#include <inet/InetInterface.h>
+#include <inet/UDPEndPointImplSockets.h>
+#include <lib/support/logging/CHIPLogging.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <platform/Zephyr/InetUtils.h>
+
+#include <net/net_stats.h>
+#include <zephyr.h>
+
+extern "C" {
+#include <common/defs.h>
+#include <wpa_supplicant/config.h>
+#include <wpa_supplicant/driver_i.h>
+#include <wpa_supplicant/scan.h>
+#include <zephyr/net/wifi_mgmt.h>
+}
+
+extern struct wpa_global * global;
+
+static struct wpa_supplicant * wpa_s;
+
+namespace chip {
+namespace DeviceLayer {
+
+namespace {
+
+NetworkCommissioning::WiFiScanResponse ToScanResponse(wifi_scan_result * result)
+{
+    NetworkCommissioning::WiFiScanResponse response = {};
+
+    if (result != nullptr)
+    {
+        static_assert(sizeof(response.ssid) == sizeof(result->ssid), "SSID length mismatch");
+        static_assert(sizeof(response.bssid) == sizeof(result->mac), "BSSID length mismatch");
+
+        // TODO: Distinguish WPA versions
+        response.security.Set(result->security == WIFI_SECURITY_TYPE_PSK ? NetworkCommissioning::WiFiSecurity::kWpaPersonal
+                                                                         : NetworkCommissioning::WiFiSecurity::kUnencrypted);
+        response.channel = result->channel;
+        response.rssi    = result->rssi;
+        response.ssidLen = result->ssid_length;
+        memcpy(response.ssid, result->ssid, result->ssid_length);
+        // TODO: MAC/BSSID is not filled by the Wi-Fi driver
+        memcpy(response.bssid, result->mac, result->mac_length);
+    }
+
+    return response;
+}
+
+} // namespace
+
+// These enums shall reflect the overall ordered disconnected->connected flow
+const Map<wpa_states, WiFiManager::StationStatus, 10>
+    WiFiManager::sStatusMap({ { WPA_DISCONNECTED, WiFiManager::StationStatus::DISCONNECTED },
+                              { WPA_INTERFACE_DISABLED, WiFiManager::StationStatus::DISABLED },
+                              { WPA_INACTIVE, WiFiManager::StationStatus::DISABLED },
+                              { WPA_SCANNING, WiFiManager::StationStatus::SCANNING },
+                              { WPA_AUTHENTICATING, WiFiManager::StationStatus::CONNECTING },
+                              { WPA_ASSOCIATING, WiFiManager::StationStatus::CONNECTING },
+                              { WPA_ASSOCIATED, WiFiManager::StationStatus::CONNECTED },
+                              { WPA_4WAY_HANDSHAKE, WiFiManager::StationStatus::PROVISIONING },
+                              { WPA_GROUP_HANDSHAKE, WiFiManager::StationStatus::PROVISIONING },
+                              { WPA_COMPLETED, WiFiManager::StationStatus::FULLY_PROVISIONED } });
+
+// Map WiFi center frequency to the corresponding channel number
+const Map<uint16_t, uint8_t, 42> WiFiManager::sFreqChannelMap(
+    { { 4915, 183 }, { 4920, 184 }, { 4925, 185 }, { 4935, 187 }, { 4940, 188 }, { 4945, 189 }, { 4960, 192 },
+      { 4980, 196 }, { 5035, 7 },   { 5040, 8 },   { 5045, 9 },   { 5055, 11 },  { 5060, 12 },  { 5080, 16 },
+      { 5170, 34 },  { 5180, 36 },  { 5190, 38 },  { 5200, 40 },  { 5210, 42 },  { 5220, 44 },  { 5230, 46 },
+      { 5240, 48 },  { 5260, 52 },  { 5280, 56 },  { 5300, 60 },  { 5320, 64 },  { 5500, 100 }, { 5520, 104 },
+      { 5540, 108 }, { 5560, 112 }, { 5580, 116 }, { 5600, 120 }, { 5620, 124 }, { 5640, 128 }, { 5660, 132 },
+      { 5680, 136 }, { 5700, 140 }, { 5745, 149 }, { 5765, 153 }, { 5785, 157 }, { 5805, 161 }, { 5825, 165 } });
+
+CHIP_ERROR WiFiManager::Init()
+{
+    // wpa_supplicant instance is initialized in dedicated supplicant thread, so wait until
+    // the initialization is completed.
+    // TODO: fix thread-safety of the solution.
+    constexpr size_t kInitTimeoutMs = 5000;
+    const int64_t initStartTime     = k_uptime_get();
+    // TODO: Handle multiple VIFs
+    const char * ifname = "wlan0";
+
+    while (!global || !(wpa_s = wpa_supplicant_get_iface(global, ifname)))
+    {
+        if (k_uptime_get() > initStartTime + kInitTimeoutMs)
+        {
+            ChipLogError(DeviceLayer, "wpa_supplicant is not initialized!");
+            return CHIP_ERROR_INTERNAL;
+        }
+
+        k_msleep(200);
+    }
+
+    // TODO: consider moving these to ConnectivityManagerImpl to be prepared for handling multiple interfaces on a single device.
+    Inet::UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) {
+        const in6_addr addr = InetUtils::ToZephyrAddr(address);
+        net_if * iface      = InetUtils::GetInterface(interfaceId);
+        VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE);
+
+        net_if_mcast_addr * maddr = net_if_ipv6_maddr_add(iface, &addr);
+
+        if (maddr && !net_if_ipv6_maddr_is_joined(maddr) && !net_ipv6_is_addr_mcast_link_all_nodes(&addr))
+        {
+            net_if_ipv6_maddr_join(maddr);
+        }
+
+        return CHIP_NO_ERROR;
+    });
+
+    Inet::UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) {
+        const in6_addr addr = InetUtils::ToZephyrAddr(address);
+        net_if * iface      = InetUtils::GetInterface(interfaceId);
+        VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE);
+
+        if (!net_ipv6_is_addr_mcast_link_all_nodes(&addr) && !net_if_ipv6_maddr_rm(iface, &addr))
+        {
+            return CHIP_ERROR_INVALID_ADDRESS;
+        }
+
+        return CHIP_NO_ERROR;
+    });
+
+    ChipLogDetail(DeviceLayer, "wpa_supplicant has been initialized");
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR WiFiManager::AddNetwork(const ByteSpan & ssid, const ByteSpan & credentials)
+{
+    ChipLogDetail(DeviceLayer, "Adding WiFi network");
+    mpWpaNetwork = wpa_supplicant_add_network(wpa_s);
+    if (mpWpaNetwork)
+    {
+        static constexpr size_t kMaxSsidLen{ 32 };
+        mpWpaNetwork->ssid = (u8 *) k_malloc(kMaxSsidLen);
+
+        if (mpWpaNetwork->ssid)
+        {
+            memcpy(mpWpaNetwork->ssid, ssid.data(), ssid.size());
+            mpWpaNetwork->ssid_len    = ssid.size();
+            mpWpaNetwork->key_mgmt    = WPA_KEY_MGMT_NONE;
+            mpWpaNetwork->disabled    = 1;
+            wpa_s->conf->filter_ssids = 1;
+
+            return AddPsk(credentials);
+        }
+    }
+
+    return CHIP_ERROR_INTERNAL;
+}
+
+CHIP_ERROR WiFiManager::Scan(const ByteSpan & ssid, ScanCallback callback)
+{
+    const StationStatus stationStatus = GetStationStatus();
+    VerifyOrReturnError(stationStatus != StationStatus::DISABLED && stationStatus != StationStatus::SCANNING &&
+                            stationStatus != StationStatus::CONNECTING,
+                        CHIP_ERROR_INCORRECT_STATE);
+
+    net_if * const iface = InetUtils::GetInterface();
+    VerifyOrReturnError(iface != nullptr, CHIP_ERROR_INTERNAL);
+
+    const device * dev = net_if_get_device(iface);
+    VerifyOrReturnError(dev != nullptr, CHIP_ERROR_INTERNAL);
+
+    const net_wifi_mgmt_offload * ops = static_cast<const net_wifi_mgmt_offload *>(dev->api);
+    VerifyOrReturnError(ops != nullptr, CHIP_ERROR_INTERNAL);
+
+    mScanCallback = callback;
+
+    // TODO: Use saner API once such exists.
+    // TODO: Take 'ssid' into account.
+    VerifyOrReturnError(ops->scan(dev,
+                                  [](net_if *, int status, wifi_scan_result * result) {
+                                      VerifyOrReturn(Instance().mScanCallback != nullptr);
+                                      NetworkCommissioning::WiFiScanResponse response = ToScanResponse(result);
+                                      Instance().mScanCallback(status, result != nullptr ? &response : nullptr);
+                                  }) == 0,
+                        CHIP_ERROR_INTERNAL);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR WiFiManager::Connect(const ByteSpan & ssid, const ByteSpan & credentials, const ConnectionHandling & handling)
+{
+    ChipLogDetail(DeviceLayer, "Connecting to WiFi network");
+
+    mConnectionSuccessClbk = handling.mOnConnectionSuccess;
+    mConnectionFailedClbk  = handling.mOnConnectionFailed;
+    mConnectionTimeoutMs   = handling.mConnectionTimeoutMs;
+
+    CHIP_ERROR err = AddNetwork(ssid, credentials);
+    if (CHIP_NO_ERROR == err)
+    {
+        EnableStation(true);
+        wpa_supplicant_select_network(wpa_s, mpWpaNetwork);
+        WaitForConnectionAsync();
+    }
+    else
+    {
+        OnConnectionFailed();
+    }
+    return err;
+}
+
+void WiFiManager::OnConnectionSuccess()
+{
+    if (mConnectionSuccessClbk)
+        mConnectionSuccessClbk();
+}
+
+void WiFiManager::OnConnectionFailed()
+{
+    if (mConnectionFailedClbk)
+        mConnectionFailedClbk();
+}
+
+CHIP_ERROR WiFiManager::AddPsk(const ByteSpan & credentials)
+{
+    mpWpaNetwork->key_mgmt = WPA_KEY_MGMT_PSK;
+    str_clear_free(mpWpaNetwork->passphrase);
+    mpWpaNetwork->passphrase = dup_binstr(credentials.data(), credentials.size());
+
+    if (mpWpaNetwork->passphrase)
+    {
+        wpa_config_update_psk(mpWpaNetwork);
+        return CHIP_NO_ERROR;
+    }
+
+    return CHIP_ERROR_INTERNAL;
+}
+
+WiFiManager::StationStatus WiFiManager::GetStationStatus() const
+{
+    if (wpa_s)
+    {
+        return StatusFromWpaStatus(wpa_s->wpa_state);
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "wpa_supplicant is not initialized!");
+        return StationStatus::NONE;
+    }
+}
+
+WiFiManager::StationStatus WiFiManager::StatusFromWpaStatus(const wpa_states & status)
+{
+    ChipLogDetail(DeviceLayer, "WPA internal status: %d", static_cast<int>(status));
+    return WiFiManager::sStatusMap[status];
+}
+
+CHIP_ERROR WiFiManager::EnableStation(bool enable)
+{
+    VerifyOrReturnError(nullptr != wpa_s && nullptr != mpWpaNetwork, CHIP_ERROR_INTERNAL);
+    if (enable)
+    {
+        wpa_supplicant_enable_network(wpa_s, mpWpaNetwork);
+    }
+    else
+    {
+        wpa_supplicant_disable_network(wpa_s, mpWpaNetwork);
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR WiFiManager::ClearStationProvisioningData()
+{
+    VerifyOrReturnError(nullptr != wpa_s && nullptr != mpWpaNetwork, CHIP_ERROR_INTERNAL);
+    wpa_supplicant_cancel_scan(wpa_s);
+    wpa_clear_keys(wpa_s, mpWpaNetwork->bssid);
+    str_clear_free(mpWpaNetwork->passphrase);
+    wpa_config_update_psk(mpWpaNetwork);
+    wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR WiFiManager::DisconnectStation()
+{
+    VerifyOrReturnError(nullptr != wpa_s, CHIP_ERROR_INTERNAL);
+    wpa_supplicant_cancel_scan(wpa_s);
+    wpas_request_disconnection(wpa_s);
+
+    return CHIP_NO_ERROR;
+}
+
+void WiFiManager::WaitForConnectionAsync()
+{
+    chip::DeviceLayer::SystemLayer().StartTimer(
+        static_cast<System::Clock::Timeout>(1000), [](System::Layer *, void *) { Instance().PollTimerCallback(); }, nullptr);
+}
+
+void WiFiManager::PollTimerCallback()
+{
+    const uint32_t kMaxRetriesNumber{ mConnectionTimeoutMs.count() / 1000 };
+    static uint32_t retriesNumber{ 0 };
+
+    if (WiFiManager::StationStatus::FULLY_PROVISIONED == GetStationStatus())
+    {
+        retriesNumber = 0;
+        OnConnectionSuccess();
+    }
+    else
+    {
+        if (retriesNumber++ < kMaxRetriesNumber)
+        {
+            // wait more time
+            WaitForConnectionAsync();
+        }
+        else
+        {
+            // connection timeout
+            retriesNumber = 0;
+            OnConnectionFailed();
+        }
+    }
+}
+
+CHIP_ERROR WiFiManager::GetWiFiInfo(WiFiInfo & info) const
+{
+    VerifyOrReturnError(nullptr != wpa_s, CHIP_ERROR_INTERNAL);
+    VerifyOrReturnError(nullptr != mpWpaNetwork, CHIP_ERROR_INTERNAL);
+
+    static uint8_t sBssid[ETH_ALEN];
+    if (WiFiManager::StationStatus::CONNECTED <= GetStationStatus())
+    {
+        memcpy(sBssid, wpa_s->bssid, ETH_ALEN);
+        info.mBssId        = ByteSpan(sBssid, ETH_ALEN);
+        info.mSecurityType = GetSecurityType();
+        // TODO: this should reflect the real connection compliance
+        // i.e. the AP might support WiFi 5 only even though the station
+        // is WiFi 6 ready (so the connection is WiFi 5 effectively).
+        // For now just return what the station supports.
+        info.mWiFiVersion = EMBER_ZCL_WI_FI_VERSION_TYPE_802__11AX;
+
+        wpa_signal_info signalInfo{};
+        if (0 == wpa_drv_signal_poll(wpa_s, &signalInfo))
+        {
+            info.mRssi    = signalInfo.current_signal; // dBm
+            info.mChannel = FrequencyToChannel(signalInfo.frequency);
+        }
+        else
+        {
+            // this values should be nullable according to the Matter spec
+            info.mRssi    = std::numeric_limits<decltype(info.mRssi)>::min();
+            info.mChannel = std::numeric_limits<decltype(info.mChannel)>::min();
+        }
+
+        memcpy(info.mSsid, mpWpaNetwork->ssid, mpWpaNetwork->ssid_len);
+        info.mSsidLen = mpWpaNetwork->ssid_len;
+
+        return CHIP_NO_ERROR;
+    }
+
+    return CHIP_ERROR_INTERNAL;
+}
+
+uint8_t WiFiManager::GetSecurityType() const
+{
+    VerifyOrReturnValue(nullptr != mpWpaNetwork, EMBER_ZCL_SECURITY_TYPE_UNSPECIFIED);
+
+    if ((mpWpaNetwork->key_mgmt & WPA_KEY_MGMT_NONE) || !wpa_key_mgmt_wpa_any(mpWpaNetwork->key_mgmt))
+    {
+        return EMBER_ZCL_SECURITY_TYPE_NONE;
+    }
+    else if (wpa_key_mgmt_wpa_psk_no_sae(mpWpaNetwork->key_mgmt))
+    {
+        return (mpWpaNetwork->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP)) ? EMBER_ZCL_SECURITY_TYPE_WPA2
+                                                                                     : EMBER_ZCL_SECURITY_TYPE_WPA3;
+    }
+    else if (wpa_key_mgmt_sae(mpWpaNetwork->key_mgmt))
+    {
+        return EMBER_ZCL_SECURITY_TYPE_WPA3;
+    }
+    else
+    {
+        return EMBER_ZCL_SECURITY_TYPE_WEP;
+    }
+
+    return EMBER_ZCL_SECURITY_TYPE_UNSPECIFIED;
+}
+
+uint8_t WiFiManager::FrequencyToChannel(uint16_t freq)
+{
+    static constexpr uint16_t k24MinFreq{ 2401 };
+    static constexpr uint16_t k24MaxFreq{ 2484 };
+    static constexpr uint8_t k24FreqConstDiff{ 5 };
+
+    if (freq >= k24MinFreq && freq < k24MaxFreq)
+    {
+        return static_cast<uint8_t>((freq - k24MinFreq) / k24FreqConstDiff + 1);
+    }
+    else if (freq == k24MaxFreq)
+    {
+        return 14;
+    }
+    else if (freq > k24MaxFreq)
+    {
+        // assume we are in 5GH band
+        return sFreqChannelMap[freq];
+    }
+    return 0;
+}
+
+CHIP_ERROR WiFiManager::GetNetworkStatistics(NetworkStatistics & stats) const
+{
+    // TODO: below will not work (result will be all zeros) until
+    // the get_stats handler is implemented in WiFi driver
+    net_stats_eth data{};
+    net_mgmt(NET_REQUEST_STATS_GET_ETHERNET, InetUtils::GetInterface(), &data, sizeof(data));
+
+    stats.mPacketMulticastRxCount = data.multicast.rx;
+    stats.mPacketMulticastTxCount = data.multicast.tx;
+    stats.mPacketUnicastRxCount   = data.pkts.rx - data.multicast.rx - data.broadcast.rx;
+    stats.mPacketUnicastTxCount   = data.pkts.tx - data.multicast.tx - data.broadcast.tx;
+    stats.mOverruns               = 0; // TODO: clarify if this can be queried from mgmt API (e.g. data.tx_dropped)
+
+    return CHIP_NO_ERROR;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/nrfconnect/wifi/WiFiManager.h b/src/platform/nrfconnect/wifi/WiFiManager.h
new file mode 100644
index 0000000..b068cd9
--- /dev/null
+++ b/src/platform/nrfconnect/wifi/WiFiManager.h
@@ -0,0 +1,171 @@
+/*
+ *
+ *    Copyright (c) 2022 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.
+ */
+
+/**
+ *    @file
+ *          Provides the wrapper for nRF wpa_supplicant API
+ */
+
+#pragma once
+
+#include <lib/core/CHIPError.h>
+#include <lib/support/Span.h>
+#include <platform/NetworkCommissioning.h>
+#include <system/SystemLayer.h>
+
+#include <net/net_if.h>
+
+extern "C" {
+#include <src/utils/common.h>
+#include <wpa_supplicant/wpa_supplicant_i.h>
+}
+
+struct net_if;
+struct wpa_ssid;
+using WpaNetwork = struct wpa_ssid;
+
+namespace chip {
+namespace DeviceLayer {
+
+// emulation of dictionary - might be moved to utils
+template <typename T1, typename T2, std::size_t N>
+class Map
+{
+    struct Pair
+    {
+        T1 key;
+        T2 value;
+    };
+
+public:
+    Map(const Pair (&list)[N])
+    {
+        int idx{ 0 };
+        for (const auto & pair : list)
+        {
+            mMap[idx++] = pair;
+        }
+    }
+
+    T2 operator[](const T1 & key) const
+    {
+        for (const auto & it : mMap)
+        {
+            if (key == it.key)
+                return it.value;
+        }
+
+        return T2{};
+    }
+
+    Map()            = delete;
+    Map(const Map &) = delete;
+    Map(Map &&)      = delete;
+    Map & operator=(const Map &) = delete;
+    Map & operator=(Map &&) = delete;
+    ~Map()                  = default;
+
+private:
+    Pair mMap[N];
+};
+
+class WiFiManager
+{
+    using ConnectionCallback = void (*)();
+
+public:
+    enum class StationStatus : uint8_t
+    {
+        NONE,
+        DISCONNECTED,
+        DISABLED,
+        SCANNING,
+        CONNECTING,
+        CONNECTED,
+        PROVISIONING,
+        FULLY_PROVISIONED
+    };
+
+    static WiFiManager & Instance()
+    {
+        static WiFiManager sInstance;
+        return sInstance;
+    }
+
+    using ScanCallback = void (*)(int /* status */, NetworkCommissioning::WiFiScanResponse *);
+
+    struct ConnectionHandling
+    {
+        ConnectionCallback mOnConnectionSuccess{};
+        ConnectionCallback mOnConnectionFailed{};
+        System::Clock::Timeout mConnectionTimeoutMs{};
+    };
+
+    struct WiFiInfo
+    {
+        ByteSpan mBssId{};
+        uint8_t mSecurityType{};
+        uint8_t mWiFiVersion{};
+        uint16_t mChannel{};
+        int8_t mRssi{};
+        uint8_t mSsid[DeviceLayer::Internal::kMaxWiFiSSIDLength];
+        size_t mSsidLen{ 0 };
+    };
+
+    struct NetworkStatistics
+    {
+        uint32_t mPacketMulticastRxCount{};
+        uint32_t mPacketMulticastTxCount{};
+        uint32_t mPacketUnicastRxCount{};
+        uint32_t mPacketUnicastTxCount{};
+        uint32_t mOverruns{};
+    };
+
+    CHIP_ERROR Init();
+    CHIP_ERROR Scan(const ByteSpan & ssid, ScanCallback callback);
+    CHIP_ERROR Connect(const ByteSpan & ssid, const ByteSpan & credentials, const ConnectionHandling & handling);
+    StationStatus GetStationStatus() const;
+    CHIP_ERROR ClearStationProvisioningData();
+    CHIP_ERROR DisconnectStation();
+    CHIP_ERROR GetWiFiInfo(WiFiInfo & info) const;
+    CHIP_ERROR GetNetworkStatistics(NetworkStatistics & stats) const;
+
+private:
+    CHIP_ERROR AddPsk(const ByteSpan & credentials);
+    CHIP_ERROR EnableStation(bool enable);
+    CHIP_ERROR AddNetwork(const ByteSpan & ssid, const ByteSpan & credentials);
+    void PollTimerCallback();
+    void WaitForConnectionAsync();
+    void OnConnectionSuccess();
+    void OnConnectionFailed();
+    uint8_t GetSecurityType() const;
+
+    WpaNetwork * mpWpaNetwork{ nullptr };
+    ConnectionCallback mConnectionSuccessClbk;
+    ConnectionCallback mConnectionFailedClbk;
+    System::Clock::Timeout mConnectionTimeoutMs;
+    ScanCallback mScanCallback{ nullptr };
+
+    static uint8_t FrequencyToChannel(uint16_t freq);
+    static StationStatus StatusFromWpaStatus(const wpa_states & status);
+
+    static const Map<wpa_states, StationStatus, 10> sStatusMap;
+    static const Map<uint16_t, uint8_t, 42> sFreqChannelMap;
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/telink/BUILD.gn b/src/platform/telink/BUILD.gn
index b13a9d1..1a4c903 100644
--- a/src/platform/telink/BUILD.gn
+++ b/src/platform/telink/BUILD.gn
@@ -26,6 +26,7 @@
     "../Zephyr/ConfigurationManagerImpl.cpp",
     "../Zephyr/DiagnosticDataProviderImpl.cpp",
     "../Zephyr/DiagnosticDataProviderImpl.h",
+    "../Zephyr/DiagnosticDataProviderImplGetter.cpp",
     "../Zephyr/KeyValueStoreManagerImpl.cpp",
     "../Zephyr/Logging.cpp",
     "../Zephyr/PlatformManagerImpl.cpp",