[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;