[nrfconnect] Implemented WiFiNetworkDiagnostics events generation (#32962)

* Added generation of optional events from WiFiNetworkDiagnostics
cluster.
* Improved handler methods to validate the input data size
diff --git a/src/platform/nrfconnect/wifi/WiFiManager.cpp b/src/platform/nrfconnect/wifi/WiFiManager.cpp
index 6e3ff8e..d5783fa 100644
--- a/src/platform/nrfconnect/wifi/WiFiManager.cpp
+++ b/src/platform/nrfconnect/wifi/WiFiManager.cpp
@@ -25,6 +25,7 @@
 #include <crypto/RandUtils.h>
 #include <lib/support/logging/CHIPLogging.h>
 #include <platform/CHIPDeviceLayer.h>
+#include <platform/DiagnosticDataProvider.h>
 #include <platform/Zephyr/InetUtils.h>
 
 #include <zephyr/kernel.h>
@@ -151,7 +152,7 @@
         Platform::UniquePtr<uint8_t> eventData(new uint8_t[cb->info_length]);
         VerifyOrReturn(eventData);
         memcpy(eventData.get(), cb->info, cb->info_length);
-        sEventHandlerMap[mgmtEvent](std::move(eventData));
+        sEventHandlerMap[mgmtEvent](std::move(eventData), cb->info_length);
     }
 }
 
@@ -292,8 +293,11 @@
     return CHIP_NO_ERROR;
 }
 
-void WiFiManager::ScanResultHandler(Platform::UniquePtr<uint8_t> data)
+void WiFiManager::ScanResultHandler(Platform::UniquePtr<uint8_t> data, size_t length)
 {
+    // Validate that input data size matches the expected one.
+    VerifyOrReturn(length == sizeof(wifi_scan_result));
+
     // Contrary to other handlers, offload accumulating of the scan results from the CHIP thread to the caller's thread
     const wifi_scan_result * scanResult = reinterpret_cast<const wifi_scan_result *>(data.get());
 
@@ -337,8 +341,11 @@
     }
 }
 
-void WiFiManager::ScanDoneHandler(Platform::UniquePtr<uint8_t> data)
+void WiFiManager::ScanDoneHandler(Platform::UniquePtr<uint8_t> data, size_t length)
 {
+    // Validate that input data size matches the expected one.
+    VerifyOrReturn(length == sizeof(wifi_status));
+
     CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] {
         Platform::UniquePtr<uint8_t> safePtr(capturedData);
         uint8_t * rawData             = safePtr.get();
@@ -416,8 +423,13 @@
     }
 }
 
-void WiFiManager::ConnectHandler(Platform::UniquePtr<uint8_t> data)
+void WiFiManager::ConnectHandler(Platform::UniquePtr<uint8_t> data, size_t length)
 {
+    using app::Clusters::WiFiNetworkDiagnostics::AssociationFailureCauseEnum;
+
+    // Validate that input data size matches the expected one.
+    VerifyOrReturn(length == sizeof(wifi_status));
+
     CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] {
         Platform::UniquePtr<uint8_t> safePtr(capturedData);
         uint8_t * rawData           = safePtr.get();
@@ -432,6 +444,32 @@
             {
                 Instance().mHandling.mOnConnectionDone(connStatus);
             }
+
+            WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate();
+            if (delegate)
+            {
+                uint16_t reason = Instance().GetLastDisconnectReason();
+                uint8_t associationFailureCause;
+
+                switch (connStatus)
+                {
+                case WIFI_STATUS_CONN_WRONG_PASSWORD:
+                    associationFailureCause = to_underlying(AssociationFailureCauseEnum::kAuthenticationFailed);
+                    break;
+                case WIFI_STATUS_CONN_FAIL:
+                case WIFI_STATUS_CONN_TIMEOUT:
+                    associationFailureCause = to_underlying(AssociationFailureCauseEnum::kAssociationFailed);
+                    break;
+                case WIFI_STATUS_CONN_AP_NOT_FOUND:
+                    associationFailureCause = to_underlying(AssociationFailureCauseEnum::kSsidNotFound);
+                    break;
+                default:
+                    associationFailureCause = to_underlying(AssociationFailureCauseEnum::kUnknown);
+                    break;
+                }
+
+                delegate->OnAssociationFailureDetected(associationFailureCause, reason);
+            }
         }
         else // The connection has been established successfully.
         {
@@ -457,6 +495,13 @@
             {
                 ChipLogError(DeviceLayer, "Cannot post event [error: %s]", ErrorStr(error));
             }
+
+            WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate();
+            if (delegate)
+            {
+                delegate->OnConnectionStatusChanged(
+                    to_underlying(app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kConnected));
+            }
         }
         // cleanup the provisioning data as it is configured per each connect request
         Instance().ClearStationProvisioningData();
@@ -469,13 +514,55 @@
     }
 }
 
-void WiFiManager::DisconnectHandler(Platform::UniquePtr<uint8_t>)
+void WiFiManager::DisconnectHandler(Platform::UniquePtr<uint8_t> data, size_t length)
 {
-    SystemLayer().ScheduleLambda([] {
+    // Validate that input data size matches the expected one.
+    VerifyOrReturn(length == sizeof(wifi_status));
+
+    CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] {
+        Platform::UniquePtr<uint8_t> safePtr(capturedData);
+        uint8_t * rawData          = safePtr.get();
+        const wifi_status * status = reinterpret_cast<const wifi_status *>(rawData);
+        uint16_t reason;
+
+        switch (status->disconn_reason)
+        {
+        case WIFI_REASON_DISCONN_UNSPECIFIED:
+            reason = WLAN_REASON_UNSPECIFIED;
+            break;
+        case WIFI_REASON_DISCONN_USER_REQUEST:
+            reason = WLAN_REASON_DEAUTH_LEAVING;
+            break;
+        case WIFI_REASON_DISCONN_AP_LEAVING:
+            reason = WLAN_REASON_DEAUTH_LEAVING;
+            break;
+        case WIFI_REASON_DISCONN_INACTIVITY:
+            reason = WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY;
+            break;
+        default:
+            reason = WLAN_REASON_UNSPECIFIED;
+            break;
+        }
+        Instance().SetLastDisconnectReason(reason);
+
         ChipLogProgress(DeviceLayer, "WiFi station disconnected");
         Instance().mWiFiState = WIFI_STATE_DISCONNECTED;
         Instance().PostConnectivityStatusChange(kConnectivity_Lost);
+
+        WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate();
+        if (delegate)
+        {
+            delegate->OnConnectionStatusChanged(
+                to_underlying(app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kNotConnected));
+            delegate->OnDisconnectionDetected(reason);
+        }
     });
+
+    if (CHIP_NO_ERROR == err)
+    {
+        // the ownership has been transferred to the worker thread - release the buffer
+        data.release();
+    }
 }
 
 void WiFiManager::IPv6AddressChangeHandler(const void * data)
@@ -586,5 +673,15 @@
     return CHIP_NO_ERROR;
 }
 
+void WiFiManager::SetLastDisconnectReason(uint16_t reason)
+{
+    mLastDisconnectedReason = reason;
+}
+
+uint16_t WiFiManager::GetLastDisconnectReason()
+{
+    return mLastDisconnectedReason;
+}
+
 } // namespace DeviceLayer
 } // namespace chip
diff --git a/src/platform/nrfconnect/wifi/WiFiManager.h b/src/platform/nrfconnect/wifi/WiFiManager.h
index 2694b05..a4e3a8a 100644
--- a/src/platform/nrfconnect/wifi/WiFiManager.h
+++ b/src/platform/nrfconnect/wifi/WiFiManager.h
@@ -179,9 +179,11 @@
     CHIP_ERROR GetNetworkStatistics(NetworkStatistics & stats) const;
     void AbortConnectionRecovery();
     CHIP_ERROR SetLowPowerMode(bool onoff);
+    void SetLastDisconnectReason(uint16_t reason);
+    uint16_t GetLastDisconnectReason();
 
 private:
-    using NetEventHandler = void (*)(Platform::UniquePtr<uint8_t>);
+    using NetEventHandler = void (*)(Platform::UniquePtr<uint8_t>, size_t);
 
     struct ConnectionParams
     {
@@ -197,10 +199,10 @@
     // Event handling
     static void WifiMgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface);
     static void IPv6MgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface);
-    static void ScanResultHandler(Platform::UniquePtr<uint8_t> data);
-    static void ScanDoneHandler(Platform::UniquePtr<uint8_t> data);
-    static void ConnectHandler(Platform::UniquePtr<uint8_t> data);
-    static void DisconnectHandler(Platform::UniquePtr<uint8_t> data);
+    static void ScanResultHandler(Platform::UniquePtr<uint8_t> data, size_t length);
+    static void ScanDoneHandler(Platform::UniquePtr<uint8_t> data, size_t length);
+    static void ConnectHandler(Platform::UniquePtr<uint8_t> data, size_t length);
+    static void DisconnectHandler(Platform::UniquePtr<uint8_t> data, size_t length);
     static void PostConnectivityStatusChange(ConnectivityChange changeType);
     static void SendRouterSolicitation(System::Layer * layer, void * param);
     static void IPv6AddressChangeHandler(const void * data);
@@ -234,6 +236,7 @@
     uint32_t mConnectionRecoveryCounter{ 0 };
     uint32_t mConnectionRecoveryTimeMs{ kConnectionRecoveryMinIntervalMs };
     bool mApplicationDisconnectRequested{ false };
+    uint16_t mLastDisconnectedReason = WLAN_REASON_UNSPECIFIED;
 
     static const Map<wifi_iface_state, StationStatus, 10> sStatusMap;
     static const Map<uint32_t, NetEventHandler, 5> sEventHandlerMap;