[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/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt
index 305edd2..c27f4bf 100644
--- a/config/nrfconnect/chip-module/CMakeLists.txt
+++ b/config/nrfconnect/chip-module/CMakeLists.txt
@@ -219,6 +219,7 @@
 chip_gn_arg_bool  ("chip_detail_logging"                    CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 4)
 chip_gn_arg_bool  ("chip_automation_logging"                "false")
 chip_gn_arg_bool  ("chip_malloc_sys_heap"                   CONFIG_CHIP_MALLOC_SYS_HEAP)
+chip_gn_arg_bool  ("chip_enable_wifi"                       CONFIG_WIFI_NRF700X)
 
 if (CONFIG_CHIP_FACTORY_DATA)
     chip_gn_arg_bool  ("chip_use_transitional_commissionable_data_provider"  "false")
@@ -232,8 +233,12 @@
     chip_gn_arg_bool("chip_enable_additional_data_advertising" "true")
 endif()
 
-if (CONFIG_CHIP_ENABLE_DNSSD_SRP)
+if (CONFIG_NET_L2_OPENTHREAD)
     chip_gn_arg_string("chip_mdns" "platform")
+elseif(CONFIG_WIFI_NRF700X)
+    chip_gn_arg_string("chip_mdns" "minimal")
+else()
+    chip_gn_arg_string("chip_mdns" "none")
 endif()
 
 if (CONFIG_CHIP_CRYPTO_PSA)
diff --git a/config/nrfconnect/chip-module/Kconfig.defaults b/config/nrfconnect/chip-module/Kconfig.defaults
index 228dbae..e02d0d2 100644
--- a/config/nrfconnect/chip-module/Kconfig.defaults
+++ b/config/nrfconnect/chip-module/Kconfig.defaults
@@ -213,20 +213,72 @@
     int
     default 512
 
+# Enable OpenThread
+
+config NET_L2_OPENTHREAD
+    bool
+    default y if !WIFI_NRF700X
+
+if NET_L2_OPENTHREAD
+
 # Increase the default RX stack size
 config IEEE802154_NRF5_RX_STACK_SIZE
     int
     default 1024
 
-# Enable OpenThread
+endif
 
-config NET_L2_OPENTHREAD
+if CHIP_WIFI
+
+config NRF_WIFI_LOW_POWER
     bool
-    default y
+    default n
 
-choice OPENTHREAD_STACK_VERSION
-	default OPENTHREAD_THREAD_VERSION_1_3
-endchoice
+config MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+    bool
+    default n
+
+config SYSTEM_WORKQUEUE_STACK_SIZE
+    int
+    default 1120
+
+# align these numbers to match the OpenThread config
+config NET_IF_UNICAST_IPV6_ADDR_COUNT
+    int
+    default 6
+
+config NET_IF_MCAST_IPV6_ADDR_COUNT
+    int
+    default 8
+
+config NET_SOCKETS_POSIX_NAMES
+    bool
+    default n
+
+config MBEDTLS_SSL_OUT_CONTENT_LEN
+    int
+    default 900
+
+# options managed by IP4/IP6 simultaneous support
+# aligned here to match OpenThread config
+config NET_MAX_ROUTERS
+    int
+    default 1
+
+config NET_MAX_CONN
+    int
+    default 4
+
+config SHELL_STACK_SIZE
+    int
+    default 2616
+
+config HEAP_MEM_POOL_SIZE
+    int
+    default 200000
+
+endif
+
 
 # Enable mbedTLS from nrf_security library
 
diff --git a/config/nrfconnect/chip-module/Kconfig.features b/config/nrfconnect/chip-module/Kconfig.features
index 1f12053..6ff4aa5 100644
--- a/config/nrfconnect/chip-module/Kconfig.features
+++ b/config/nrfconnect/chip-module/Kconfig.features
@@ -19,6 +19,31 @@
 
 if CHIP
 
+config CHIP_WIFI
+	bool "Enable nrfconnect Wi-Fi support"
+	default y if SHIELD_NRF7002_EK || BOARD_NRF7002DK_NRF5340_CPUAPP
+	select WIFI_NRF700X
+	select WIFI
+	select WPA_SUPP
+	imply FLASH
+	imply SETTINGS
+	imply NVS
+	imply FLASH_MAP
+	imply NORDIC_SECURITY_BACKEND
+	imply MBEDTLS_ENTROPY_C
+	imply MBEDTLS_PSA_CRYPTO_C
+	imply NET_STATISTICS
+	imply NET_L2_ETHERNET
+	imply NET_PKT_TXTIME
+	imply NET_PKT_TIMESTAMP
+	imply MBEDTLS_PROMPTLESS
+	imply BUILD_OUTPUT_META
+	imply USE_DT_CODE_PARTITION # might be removed when the OTA is enabled
+	imply NET_IPV6_ND # enable Neighbor Discovery to handle Router Advertisements
+	imply NET_IPV6_NBR_CACHE
+	imply NET_STATISTICS_IPV6
+	imply NET_STATISTICS_USER_API
+
 config CHIP_QSPI_NOR
 	bool "Enable QSPI NOR feature set"
 	help
diff --git a/config/nrfconnect/chip-module/Kconfig.hci_rpmsg.defaults b/config/nrfconnect/chip-module/Kconfig.hci_rpmsg.defaults
new file mode 100644
index 0000000..8069d71
--- /dev/null
+++ b/config/nrfconnect/chip-module/Kconfig.hci_rpmsg.defaults
@@ -0,0 +1,99 @@
+#
+#   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.
+#
+
+# The purpose of this file is to define new default values of settings used when building hci_rpmsg child image for Matter samples.
+
+config LOG
+    bool
+    default n
+
+config HEAP_MEM_POOL_SIZE
+    int
+    default 8192
+
+config MAIN_STACK_SIZE
+    int
+    default 2048
+
+config SYSTEM_WORKQUEUE_STACK_SIZE
+    int
+    default 2048
+
+config BT
+    bool
+    default y
+
+config BT_HCI_RAW
+    bool
+    default y
+
+config BT_MAX_CONN
+    int
+    default 1
+
+config BT_PERIPHERAL
+    bool
+    default y
+
+config BT_CENTRAL
+    bool
+    default n
+
+config BT_BUF_ACL_RX_SIZE
+    int
+    default 502
+
+config BT_BUF_ACL_TX_SIZE
+    int
+    default 251
+
+config BT_CTLR_DATA_LENGTH_MAX
+    int
+    default 251
+
+config BT_CTLR_ASSERT_HANDLER
+    bool
+    default y
+
+config BT_HCI_RAW_RESERVE
+    int
+    default 1
+
+# Workaround: Unable to allocate command buffer when using K_NO_WAIT since
+# Host number of completed commands does not follow normal flow control.
+config BT_BUF_CMD_TX_COUNT
+    int
+    default 10
+
+config ASSERT
+    bool
+    default y
+
+config DEBUG_INFO
+    bool
+    default y
+
+config EXCEPTION_STACK_TRACE
+    bool
+    default y
+
+config IPC_SERVICE
+    bool
+    default y
+
+config MBOX
+    bool
+    default y
diff --git a/config/nrfconnect/chip-module/Kconfig.hci_rpmsg.root b/config/nrfconnect/chip-module/Kconfig.hci_rpmsg.root
new file mode 100644
index 0000000..8c4f6ee
--- /dev/null
+++ b/config/nrfconnect/chip-module/Kconfig.hci_rpmsg.root
@@ -0,0 +1,21 @@
+#
+#   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.
+#
+
+# The purpose of this file is to create a wrapper Kconfig file that will be set as
+# hci_rpmsg_KCONFIG_ROOT and processed before any other Kconfig for hci_rpmsg child image.
+
+rsource "Kconfig.hci_rpmsg.defaults"
+source "Kconfig.zephyr"
diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig
index 9928bb3..c7c5b35 100644
--- a/config/zephyr/Kconfig
+++ b/config/zephyr/Kconfig
@@ -112,7 +112,7 @@
 
 config CHIP_ENABLE_DNSSD_SRP
 	bool "Enable support for service registration"
-	default y
+	default y if NET_L2_OPENTHREAD
 	imply OPENTHREAD_ECDSA
 	imply OPENTHREAD_SRP_CLIENT
 	help
diff --git a/docs/guides/images/CHIPTool_device_commissioned.jpg b/docs/guides/images/CHIPTool_device_commissioned.jpg
deleted file mode 100644
index 85bbbdc..0000000
--- a/docs/guides/images/CHIPTool_device_commissioned.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/guides/images/CHIPTool_device_commissioned.png b/docs/guides/images/CHIPTool_device_commissioned.png
new file mode 100644
index 0000000..8756b4d
--- /dev/null
+++ b/docs/guides/images/CHIPTool_device_commissioned.png
Binary files differ
diff --git a/docs/guides/nrfconnect_android_commissioning.md b/docs/guides/nrfconnect_android_commissioning.md
index 7bbc0e3..0e2146b 100644
--- a/docs/guides/nrfconnect_android_commissioning.md
+++ b/docs/guides/nrfconnect_android_commissioning.md
@@ -1,13 +1,14 @@
 # Commissioning nRF Connect Accessory using Android CHIPTool
 
 You can use [CHIPTool](android_building.md) for Android smartphones to
-commission a Nordic Semiconductor device running an nRF Connect platform example
-onto a Matter-enabled Thread network.
+commission a Nordic Semiconductor's development kit programmed with a Matter
+example for the nRF Connect platform into a Matter fabric.
 
-This guide references the nRF52840 DK and the door lock example application
-based on the nRF Connect platform, but the instructions are also valid for the
-nRF Connect lighting example application and can be adapted to other platforms
-and applications as well.
+This guide references the nRF52840 DK and Matter nRF Connect Lighting Example
+Application that communicates with other nodes over a Thread network, but the
+instructions can be adapted to other platforms and applications. In particular,
+some sections of this guide include deviations from the original procedure that
+are needed to test a Wi-Fi device.
 
 <hr>
 
@@ -30,8 +31,8 @@
 
 1.  CHIPTool discovers a Matter accessory device over Bluetooth LE.
 2.  CHIPTool establishes a secure channel to the device over Bluetooth LE, and
-    sends Matter operational credentials and Thread provisioning data.
-3.  The accessory device joins a Matter-enabled Thread network.
+    sends Matter operational credentials and Thread or Wi-Fi credentials.
+3.  The accessory device joins the operational IPv6 network.
 
 CHIPTool uses both Bluetooth LE and the IPv6 connectivity. Bluetooth LE is used
 only during the commissioning phase. Afterwards, only the IPv6 connectivity
@@ -41,13 +42,13 @@
 learn or refresh the address before the controller initiates the IPv6-based
 communication.
 
-Since a typical smartphone does not have a Thread radio built-in, extra effort
-is needed to prepare the fully-fledged testing environment that includes a
-Thread Border Router configured on a Raspberry Pi.
+Since a typical smartphone does not have a Thread radio built-in, preparing the
+fully-fledged testing environment for Matter over Thread requires a Thread
+Border Router configured on a Raspberry Pi.
 
 The following diagram shows the connectivity between network components required
-to allow communication between devices running the CHIPTool and Lock
-applications:
+to allow communication between devices running CHIPTool and Matter nRF Connect
+Lighting Example Application:
 
 ![Matter nodes connectivity](./images/nrfconnect_android_connectivity.png)
 
@@ -60,20 +61,26 @@
 You need the following hardware and software for commissioning the nRF Connect
 accessory using Android CHIPTool:
 
--   Two nRF52840 DK (PCA10056)
-
-    -   One nRF52840 DK is needed for running the
-        [OpenThread Radio Co-Processor](https://openthread.io/platforms/co-processor)
-        firmware. You can replace this DK with another compatible device, such
-        as the nRF52840 Dongle.
-    -   One nRF52840 DK is needed for running the example application. You can
-        replace this DK with another compatible device, such as the nRF5340 DK.
-
--   Smartphone compatible with Android 8.0 or later
--   Raspberry Pi Model 3B+ or newer (along with an SD card with at least 8 GB of
-    memory)
--   Wi-Fi Access Point supporting IPv6 (without the IPv6 Router Advertisement
+-   1x smartphone with Android 8+
+-   1x Wi-Fi Access Point supporting IPv6 (without the IPv6 Router Advertisement
     Guard enabled on the router)
+-   1x nRF52840 DK (PCA10056) for running the example application. You can
+    replace this DK with another compatible device, such as the nRF5340 DK or
+    nRF7002 DK. nRF52840 DK and nRF5340 DK can be used to test Matter over
+    Thread, and nRF7002 DK can be used to test Matter over Wi-Fi.
+-   1x nRF52840 DK for running the
+    [OpenThread Radio Co-Processor](https://openthread.io/platforms/co-processor)
+    firmware. You can replace this DK with another compatible device, such as
+    the nRF52840 Dongle.
+
+    > _Note:_ This piece of hardware is only needed if you're testing a Thread
+    > device. Skip it if the tested device operates in a Wi-Fi network.
+
+-   1x Raspberry Pi Model 3B+ or newer (along with an SD card with at least 8 GB
+    of memory)
+
+    > _Note:_ This piece of hardware is only needed if you're testing a Thread
+    > device. Skip it if the tested device operates in a Wi-Fi network.
 
 <hr>
 
@@ -81,10 +88,15 @@
 
 ## Setting up Thread Border Router
 
+> _Note:_ This step is only needed if you're testing a Thread device. Skip it if
+> the tested device operates in a Wi-Fi network.
+
 Follow the [OpenThread Border Router](openthread_border_router_pi.md) article to
 set up OpenThread Border Router on the Raspberry Pi, with either the nRF52840 DK
 or the nRF52840 Dongle acting as the
 [OpenThread Radio Co-Processor](https://openthread.io/platforms/co-processor).
+During the setup, make sure that the Raspberry Pi is connected to your Wi-Fi
+Access Point.
 
 <hr>
 
@@ -94,8 +106,8 @@
 
 Build and program the example application onto your compatible device.
 
-For this guide, see the documentation for the door lock example application to
-learn how to build and program the example onto an nRF52840 DK.
+For this guide, see the documentation of Matter nRF Connect Lighting Example
+Application to learn how to build and program the example onto an nRF52840 DK.
 
 <hr>
 
@@ -164,24 +176,24 @@
 
 ## Commissioning accessory device
 
-To commission the accessory device onto the Thread network created in the
-[Setting up Thread Border Router](#setting-up-thread-border-router) section,
-complete the following steps:
+To commission the accessory device into the Matter fabric, complete the
+following steps:
 
-1. Enable **Bluetooth** and **Location** services on your smartphone.
-2. Connect the smartphone to the same Wi-Fi network as the Raspberry Pi which
-   runs OpenThread Border Router.
-3. Open the CHIPTool application on your smartphone.
-4. Tap the **PROVISION CHIP DEVICE WITH THREAD** button and scan the
-   commissioning QR code. Several notifications will appear, informing you of
-   commissioning progress with scanning, connection, and pairing. At the end of
-   this process, the Thread network settings screen appears.
-5. In the Thread network settings screen, use the default settings and tap the
-   **SAVE NETWORK** button to send a Thread provisioning message to the
-   accessory device.
+1.  Enable **Bluetooth** and **Location** services on your smartphone.
+2.  Connect the smartphone to your Wi-Fi Access Point.
+3.  Open the CHIPTool application on your smartphone.
+4.  Depending on your testing scenario, tap one of the following buttons and
+    scan the commissioning QR code:
 
-You will see the "Network provisioning completed" message when the accessory
-device successfully joins the Thread network.
+    -   **PROVISION CHIP DEVICE WITH THREAD** for Matter over Thread
+    -   **PROVISION CHIP DEVICE WITH WI-FI** for Matter over Wi-Fi
+
+    The network credentials screen appears.
+
+5.  In the network credentials screen, specify parameters of network and tap the
+    **SAVE NETWORK** button. Several notifications appear, informing you of the
+    progress of scanning, connecting, and pairing with the device. At the end of
+    this process, the application returns to the main menu.
 
 <hr>
 
@@ -195,21 +207,16 @@
 
 1. Tap **LIGHT ON/OFF & LEVEL CLUSTER**. The following screen appears:
 
-    ![CHIPTool device control screen](./images/CHIPTool_device_commissioned.jpg)
+    ![CHIPTool device control screen](./images/CHIPTool_device_commissioned.png)
 
     The two textboxes at the top contain **Fabric ID** and **Node ID** of the
     last commissioned device.
 
-2. Tap **UPDATE ADDRESS** to learn or refresh the IPv6 address of the device.
-   CHIPTool will use a built-in DNS-SD client to resolve **Fabric ID** and
-   **Node ID** of the device to its IPv6 address. The result of the operation,
-   be it the address or an error message, will be displayed at the bottom of the
-   screen.
-3. Tap the following buttons to change the lock state of the nRF Connect door
-   lock example application referenced in this guide:
+2. Tap the following buttons to change the lighting state of the Matter nRF
+   Connect Lighting Example Application referenced in this guide:
 
-    - **ON** and **OFF** buttons lock and unlock the door, respectively.
-    - **TOGGLE** changes the lock state to the opposite.
+    - **ON** and **OFF** buttons turn on and off the light, respectively.
+    - **TOGGLE** changes the lighting state to the opposite.
 
-The **LED 2** on the device turns on or off based on the changes of the lock
+The **LED 2** on the device turns on or off based on the changes of the lighting
 state.
diff --git a/examples/all-clusters-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/all-clusters-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
index b8030f4..4b2eca8 100644
--- a/examples/all-clusters-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
+++ b/examples/all-clusters-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
@@ -25,9 +25,6 @@
 &adc {
 	status = "disabled";
 };
-&gpio1 {
-	status = "disabled";
-};
 &i2c1 {
 	status = "disabled";
 };
diff --git a/examples/all-clusters-app/nrfconnect/main/AppTask.cpp b/examples/all-clusters-app/nrfconnect/main/AppTask.cpp
index 60519e9..40b987b 100644
--- a/examples/all-clusters-app/nrfconnect/main/AppTask.cpp
+++ b/examples/all-clusters-app/nrfconnect/main/AppTask.cpp
@@ -142,6 +142,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -159,6 +160,7 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
         return err;
     }
+#endif
 
     // Initialize LEDs
     LEDWidget::InitGpio();
diff --git a/examples/all-clusters-minimal-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/all-clusters-minimal-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
index b8030f4..4b2eca8 100644
--- a/examples/all-clusters-minimal-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
+++ b/examples/all-clusters-minimal-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
@@ -25,9 +25,6 @@
 &adc {
 	status = "disabled";
 };
-&gpio1 {
-	status = "disabled";
-};
 &i2c1 {
 	status = "disabled";
 };
diff --git a/examples/chef/nrfconnect/main.cpp b/examples/chef/nrfconnect/main.cpp
index fe031e7..8c30619 100644
--- a/examples/chef/nrfconnect/main.cpp
+++ b/examples/chef/nrfconnect/main.cpp
@@ -79,7 +79,8 @@
 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
     ConnectivityManagerImpl().StartWiFiManagement();
 #endif
-#if CHIP_ENABLE_OPENTHREAD
+
+#if defined(CHIP_ENABLE_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -97,7 +98,9 @@
         ChipLogError(AppServer, "ConnectivityMgr().SetThreadDeviceType() failed");
         return 1;
     }
-#endif /* CHIP_ENABLE_OPENTHREAD */
+#elif !defined(CONFIG_WIFI_NRF700X)
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     // Device Attestation & Onboarding codes
     chip::Credentials::SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider());
diff --git a/examples/light-switch-app/nrfconnect/main/AppTask.cpp b/examples/light-switch-app/nrfconnect/main/AppTask.cpp
index dd38827..4eee5a5 100644
--- a/examples/light-switch-app/nrfconnect/main/AppTask.cpp
+++ b/examples/light-switch-app/nrfconnect/main/AppTask.cpp
@@ -113,6 +113,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -130,6 +131,9 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed: %s", ErrorStr(err));
         return err;
     }
+#elif !defined(CONFIG_WIFI_NRF700X)
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     LightSwitch::GetInstance().Init(kLightDimmerSwitchEndpointId, kLightGenericSwitchEndpointId);
 
diff --git a/examples/lighting-app/nrfconnect/main/AppTask.cpp b/examples/lighting-app/nrfconnect/main/AppTask.cpp
index c43a7c1..1ee7586 100644
--- a/examples/lighting-app/nrfconnect/main/AppTask.cpp
+++ b/examples/lighting-app/nrfconnect/main/AppTask.cpp
@@ -124,6 +124,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -138,6 +139,9 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
         return err;
     }
+#elif !defined(CONFIG_WIFI_NRF700X)
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     // Initialize LEDs
     LEDWidget::InitGpio();
diff --git a/examples/lock-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/lock-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
index 5ae48f5..d1d93c9 100644
--- a/examples/lock-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
+++ b/examples/lock-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
@@ -25,9 +25,6 @@
 &adc {
 	status = "disabled";
 };
-&gpio1 {
-	status = "disabled";
-};
 &i2c1 {
 	status = "disabled";
 };
diff --git a/examples/lock-app/nrfconnect/main/AppTask.cpp b/examples/lock-app/nrfconnect/main/AppTask.cpp
index cb46530..b7d4d02 100644
--- a/examples/lock-app/nrfconnect/main/AppTask.cpp
+++ b/examples/lock-app/nrfconnect/main/AppTask.cpp
@@ -103,6 +103,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -120,6 +121,9 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
         return err;
     }
+#else
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     // Initialize LEDs
     LEDWidget::InitGpio();
diff --git a/examples/pump-app/nrfconnect/main/AppTask.cpp b/examples/pump-app/nrfconnect/main/AppTask.cpp
index 7ab4702..d8ccc47 100644
--- a/examples/pump-app/nrfconnect/main/AppTask.cpp
+++ b/examples/pump-app/nrfconnect/main/AppTask.cpp
@@ -104,6 +104,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -117,6 +118,9 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
         return err;
     }
+#elif !defined(CONFIG_WIFI_NRF700X)
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     // Initialize LEDs
     LEDWidget::InitGpio();
diff --git a/examples/pump-controller-app/nrfconnect/main/AppTask.cpp b/examples/pump-controller-app/nrfconnect/main/AppTask.cpp
index f473d0f..ea4bf10 100644
--- a/examples/pump-controller-app/nrfconnect/main/AppTask.cpp
+++ b/examples/pump-controller-app/nrfconnect/main/AppTask.cpp
@@ -101,6 +101,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -114,6 +115,9 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
         return err;
     }
+#elif !defined(CONFIG_WIFI_NRF700X)
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     // Initialize LEDs
     LEDWidget::InitGpio();
diff --git a/examples/window-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/window-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
index 5310e26..f455936 100644
--- a/examples/window-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
+++ b/examples/window-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay
@@ -45,9 +45,6 @@
 &adc {
 	status = "disabled";
 };
-&gpio1 {
-	status = "disabled";
-};
 &i2c1 {
 	status = "disabled";
 };
diff --git a/examples/window-app/nrfconnect/main/AppTask.cpp b/examples/window-app/nrfconnect/main/AppTask.cpp
index 77ab1af..08df914 100644
--- a/examples/window-app/nrfconnect/main/AppTask.cpp
+++ b/examples/window-app/nrfconnect/main/AppTask.cpp
@@ -105,6 +105,7 @@
         return err;
     }
 
+#if defined(CONFIG_NET_L2_OPENTHREAD)
     err = ThreadStackMgr().InitThreadStack();
     if (err != CHIP_NO_ERROR)
     {
@@ -125,6 +126,9 @@
         LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
         return err;
     }
+#elif !defined(CONFIG_WIFI_NRF700X)
+    return CHIP_ERROR_INTERNAL;
+#endif
 
     // Initialize LEDs
     LEDWidget::InitGpio();
diff --git a/examples/window-app/nrfconnect/prj_no_dfu.conf b/examples/window-app/nrfconnect/prj_no_dfu.conf
index 1a8816e..f2787a7 100644
--- a/examples/window-app/nrfconnect/prj_no_dfu.conf
+++ b/examples/window-app/nrfconnect/prj_no_dfu.conf
@@ -23,6 +23,7 @@
 
 # Add support for LEDs and buttons on Nordic development kits
 CONFIG_DK_LIBRARY=y
+CONFIG_PWM=y
 
 # OpenThread configs
 CONFIG_OPENTHREAD_NORDIC_LIBRARY_MTD=y
diff --git a/examples/window-app/nrfconnect/prj_release.conf b/examples/window-app/nrfconnect/prj_release.conf
index 0a1e773..caf0ee1 100644
--- a/examples/window-app/nrfconnect/prj_release.conf
+++ b/examples/window-app/nrfconnect/prj_release.conf
@@ -23,6 +23,7 @@
 
 # Add support for LEDs and buttons on Nordic development kits
 CONFIG_DK_LIBRARY=y
+CONFIG_PWM=y
 
 # OpenThread configs
 CONFIG_OPENTHREAD_NORDIC_LIBRARY_MTD=y
diff --git a/src/include/platform/internal/GenericConnectivityManagerImpl.h b/src/include/platform/internal/GenericConnectivityManagerImpl.h
index 6315c25..a56e92d 100644
--- a/src/include/platform/internal/GenericConnectivityManagerImpl.h
+++ b/src/include/platform/internal/GenericConnectivityManagerImpl.h
@@ -33,7 +33,7 @@
  *
  * This template contains implementations of select features from the ConnectivityManager abstract
  * interface that are suitable for use on all platforms.  It is intended to be inherited (directly
- * or indirectly) by the ConfigurationManagerImpl class, which also appears as the template's ImplClass
+ * or indirectly) by the ConnectivityManagerImpl class, which also appears as the template's ImplClass
  * parameter.
  */
 template <class ImplClass>
diff --git a/src/inet/InetConfig.h b/src/inet/InetConfig.h
index d209328..0631a7e 100644
--- a/src/inet/InetConfig.h
+++ b/src/inet/InetConfig.h
@@ -250,4 +250,26 @@
 #ifndef INET_CONFIG_IP_MULTICAST_HOP_LIMIT
 #define INET_CONFIG_IP_MULTICAST_HOP_LIMIT                 (64)
 #endif // INET_CONFIG_IP_MULTICAST_HOP_LIMIT
+
+/**
+ *  @def INET_CONFIG_UDP_SOCKET_PKTINFO
+ *
+ *  @brief
+ *    Use IP_PKTINFO and IPV6_PKTINFO control messages to specify the network
+ *    interface and the source address of a sent UDP packet.
+ *
+ *  @details
+ *    When this flag is set, the socket-based implementation of UDP endpoints
+ *    requires that IP_PKTINFO and IPV6_PKTINFO be supported. Otherwise, it is
+ *    left to the operating system to select the network interface and the
+ *    source address.
+ */
+#ifndef INET_CONFIG_UDP_SOCKET_PKTINFO
+#ifndef __ZEPHYR__
+#define INET_CONFIG_UDP_SOCKET_PKTINFO 1
+#else
+#define INET_CONFIG_UDP_SOCKET_PKTINFO 0
+#endif
+#endif // INET_CONFIG_UDP_SOCKET_PKTINFO
+
 // clang-format on
diff --git a/src/inet/UDPEndPointImplSockets.cpp b/src/inet/UDPEndPointImplSockets.cpp
index cd12fe4..6c85906 100644
--- a/src/inet/UDPEndPointImplSockets.cpp
+++ b/src/inet/UDPEndPointImplSockets.cpp
@@ -66,7 +66,7 @@
 #define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
 #elif defined(IPV6_JOIN_GROUP)
 #define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
-#elif !__ZEPHYR__
+#elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
 #error                                                                                                                             \
     "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
 #endif // IPV6_ADD_MEMBERSHIP
@@ -75,7 +75,7 @@
 #define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
 #elif defined(IPV6_LEAVE_GROUP)
 #define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
-#elif !__ZEPHYR__
+#elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
 #error                                                                                                                             \
     "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
 #endif // IPV6_DROP_MEMBERSHIP
@@ -337,6 +337,7 @@
         intf = mBoundIntfId;
     }
 
+#if INET_CONFIG_UDP_SOCKET_PKTINFO
     // If the packet should be sent over a specific interface, or with a specific source
     // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
     // add add it to the message header.  If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
@@ -401,6 +402,7 @@
         return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
 #endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
     }
+#endif // INET_CONFIG_UDP_SOCKET_PKTINFO
 
     // Send IP packet.
     const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
@@ -565,7 +567,8 @@
     System::PacketBufferHandle lBuffer;
 
     lPacketInfo.Clear();
-    lPacketInfo.DestPort = mBoundPort;
+    lPacketInfo.DestPort  = mBoundPort;
+    lPacketInfo.Interface = mBoundIntfId;
 
     lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
 
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",