[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240830080719.826142-1-yu-hao.lin@nxp.com>
Date: Fri, 30 Aug 2024 16:07:19 +0800
From: David Lin <yu-hao.lin@....com>
To: linux-wireless@...r.kernel.org
Cc: linux-kernel@...r.kernel.org,
briannorris@...omium.org,
kvalo@...nel.org,
francesco@...cini.it,
tsung-hsien.hsieh@....com,
David Lin <yu-hao.lin@....com>
Subject: [PATCH] wifi: mwifiex: fix firmware crash for AP DFS mode
Firmware crashes when AP works on a DFS channel and radar detection occurs.
This patch fixes the issue, also add "fake_radar_detect" entry to mimic
radar detection for testing purpose.
Signed-off-by: David Lin <yu-hao.lin@....com>
---
drivers/net/wireless/marvell/mwifiex/11h.c | 56 +++++++++++++++----
.../net/wireless/marvell/mwifiex/cfg80211.c | 50 ++++++++---------
.../net/wireless/marvell/mwifiex/cfg80211.h | 4 +-
.../net/wireless/marvell/mwifiex/debugfs.c | 42 ++++++++++++++
drivers/net/wireless/marvell/mwifiex/decl.h | 1 +
drivers/net/wireless/marvell/mwifiex/main.h | 1 +
6 files changed, 115 insertions(+), 39 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c
index b90f922f1cdc..e7e7a154831f 100644
--- a/drivers/net/wireless/marvell/mwifiex/11h.c
+++ b/drivers/net/wireless/marvell/mwifiex/11h.c
@@ -7,7 +7,7 @@
#include "main.h"
#include "fw.h"
-
+#include "cfg80211.h"
void mwifiex_init_11h_params(struct mwifiex_private *priv)
{
@@ -220,8 +220,11 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
cancel_delayed_work_sync(&priv->dfs_cac_work);
cfg80211_cac_event(priv->netdev,
&priv->dfs_chandef,
- NL80211_RADAR_DETECTED,
+ NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
+ cfg80211_radar_event(priv->adapter->wiphy,
+ &priv->dfs_chandef,
+ GFP_KERNEL);
}
break;
default:
@@ -244,9 +247,16 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
mwifiex_dbg(priv->adapter, MSG,
"radar detected; indicating kernel\n");
- if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
- mwifiex_dbg(priv->adapter, ERROR,
- "Failed to stop CAC in FW\n");
+
+ if (priv->wdev.cac_started) {
+ if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to stop CAC in FW\n");
+ cancel_delayed_work_sync(&priv->dfs_cac_work);
+ cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+ }
+
cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
GFP_KERNEL);
mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n",
@@ -267,27 +277,53 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
struct mwifiex_uap_bss_param *bss_cfg;
struct delayed_work *delayed_work = to_delayed_work(work);
struct mwifiex_private *priv =
- container_of(delayed_work, struct mwifiex_private,
- dfs_chan_sw_work);
+ container_of(delayed_work, struct mwifiex_private,
+ dfs_chan_sw_work);
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ if (mwifiex_del_mgmt_ies(priv))
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to delete mgmt IEs!\n");
bss_cfg = &priv->bss_cfg;
if (!bss_cfg->beacon_period) {
- mwifiex_dbg(priv->adapter, ERROR,
+ mwifiex_dbg(adapter, ERROR,
"channel switch: AP already stopped\n");
return;
}
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ mwifiex_dbg(adapter, ERROR,
+ "channel switch: Failed to stop the BSS\n");
+ return;
+ }
+
+ if (mwifiex_cfg80211_change_beacon_data(adapter->wiphy, priv->netdev,
+ &priv->beacon_after)) {
+ mwifiex_dbg(adapter, ERROR,
+ "channel switch: Failed to set beacon\n");
+ return;
+ }
+
mwifiex_uap_set_channel(priv, bss_cfg, priv->dfs_chandef);
if (mwifiex_config_start_uap(priv, bss_cfg)) {
- mwifiex_dbg(priv->adapter, ERROR,
+ mwifiex_dbg(adapter, ERROR,
"Failed to start AP after channel switch\n");
return;
}
- mwifiex_dbg(priv->adapter, MSG,
+ mwifiex_dbg(adapter, MSG,
"indicating channel switch completion to kernel\n");
wiphy_lock(priv->wdev.wiphy);
cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0);
wiphy_unlock(priv->wdev.wiphy);
+
+ if (priv->uap_stop_tx) {
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
+ priv->uap_stop_tx = false;
+ }
}
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 722ead51e912..c5e8f12da0ae 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -1858,16 +1858,12 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
return 0;
}
-/* cfg80211 operation handler for change_beacon.
- * Function retrieves and sets modified management IEs to FW.
- */
-static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
- struct net_device *dev,
- struct cfg80211_ap_update *params)
+int mwifiex_cfg80211_change_beacon_data(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_beacon_data *data)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_adapter *adapter = priv->adapter;
- struct cfg80211_beacon_data *data = ¶ms->beacon;
mwifiex_cancel_scan(adapter);
@@ -1877,12 +1873,6 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
return -EINVAL;
}
- if (!priv->bss_started) {
- mwifiex_dbg(priv->adapter, ERROR,
- "%s: bss not started\n", __func__);
- return -EINVAL;
- }
-
if (mwifiex_set_mgmt_ies(priv, data)) {
mwifiex_dbg(priv->adapter, ERROR,
"%s: setting mgmt ies failed\n", __func__);
@@ -1892,6 +1882,20 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
return 0;
}
+/* cfg80211 operation handler for change_beacon.
+ * Function retrieves and sets modified management IEs to FW.
+ */
+static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ap_update *params)
+{
+ int ret;
+
+ ret = mwifiex_cfg80211_change_beacon_data(wiphy, dev, ¶ms->beacon);
+
+ return ret;
+}
+
/* cfg80211 operation handler for del_station.
* Function deauthenticates station which value is provided in mac parameter.
* If mac is NULL/broadcast, all stations in associated station list are
@@ -4027,10 +4031,8 @@ static int
mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params)
{
- struct ieee_types_header *chsw_ie;
- struct ieee80211_channel_sw_ie *channel_sw;
- int chsw_msec;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ int chsw_msec;
if (priv->adapter->scan_processing) {
mwifiex_dbg(priv->adapter, ERROR,
@@ -4045,20 +4047,11 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
&priv->dfs_chandef))
return -EINVAL;
- chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
- params->beacon_csa.tail,
- params->beacon_csa.tail_len);
- if (!chsw_ie) {
- mwifiex_dbg(priv->adapter, ERROR,
- "Could not parse channel switch announcement IE\n");
- return -EINVAL;
- }
-
- channel_sw = (void *)(chsw_ie + 1);
- if (channel_sw->mode) {
+ if (params->block_tx) {
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+ priv->uap_stop_tx = true;
}
if (mwifiex_del_mgmt_ies(priv))
@@ -4075,7 +4068,7 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
memcpy(&priv->beacon_after, ¶ms->beacon_after,
sizeof(priv->beacon_after));
- chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100);
+ chsw_msec = max(params->count * priv->bss_cfg.beacon_period, 100);
queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work,
msecs_to_jiffies(chsw_msec));
return 0;
@@ -4794,6 +4787,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
WIPHY_FLAG_HAS_CHANNEL_SWITCH |
WIPHY_FLAG_NETNS_OK |
WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ wiphy->max_num_csa_counters = MWIFIEX_MAX_CSA_COUNTERS;
if (adapter->host_mlme_enabled)
wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS;
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.h b/drivers/net/wireless/marvell/mwifiex/cfg80211.h
index 50f7001f5ef0..0a12437f89f2 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.h
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.h
@@ -13,5 +13,7 @@
#include "main.h"
int mwifiex_register_cfg80211(struct mwifiex_adapter *);
-
+int mwifiex_cfg80211_change_beacon_data(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_beacon_data *data);
#endif
diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c
index 9deaf59dcb62..5d575d2918fe 100644
--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c
+++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c
@@ -909,6 +909,46 @@ mwifiex_reset_write(struct file *file,
return count;
}
+static ssize_t
+mwifiex_fake_radar_detect_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv = file->private_data;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ bool result;
+ int rc;
+
+ rc = kstrtobool_from_user(ubuf, count, &result);
+ if (rc)
+ return rc;
+
+ if (!result)
+ return -EINVAL;
+
+ if (priv->wdev.cac_started) {
+ mwifiex_dbg(adapter, MSG,
+ "Generate fake radar detected during CAC\n");
+ if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to stop CAC in FW\n");
+ cancel_delayed_work_sync(&priv->dfs_cac_work);
+ cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+ cfg80211_radar_event(adapter->wiphy, &priv->dfs_chandef,
+ GFP_KERNEL);
+ } else {
+ if (priv->bss_chandef.chan->dfs_cac_ms) {
+ mwifiex_dbg(adapter, MSG,
+ "Generate fake radar detected\n");
+ cfg80211_radar_event(adapter->wiphy,
+ &priv->dfs_chandef,
+ GFP_KERNEL);
+ }
+ }
+
+ return count;
+}
#define MWIFIEX_DFS_ADD_FILE(name) do { \
debugfs_create_file(#name, 0644, priv->dfs_dev_dir, priv, \
&mwifiex_dfs_##name##_fops); \
@@ -945,6 +985,7 @@ MWIFIEX_DFS_FILE_OPS(histogram);
MWIFIEX_DFS_FILE_OPS(debug_mask);
MWIFIEX_DFS_FILE_OPS(timeshare_coex);
MWIFIEX_DFS_FILE_WRITE_OPS(reset);
+MWIFIEX_DFS_FILE_WRITE_OPS(fake_radar_detect);
MWIFIEX_DFS_FILE_OPS(verext);
/*
@@ -971,6 +1012,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
MWIFIEX_DFS_ADD_FILE(debug_mask);
MWIFIEX_DFS_ADD_FILE(timeshare_coex);
MWIFIEX_DFS_ADD_FILE(reset);
+ MWIFIEX_DFS_ADD_FILE(fake_radar_detect);
MWIFIEX_DFS_ADD_FILE(verext);
}
diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h
index 84603f1e7f6e..9ece61743b9c 100644
--- a/drivers/net/wireless/marvell/mwifiex/decl.h
+++ b/drivers/net/wireless/marvell/mwifiex/decl.h
@@ -19,6 +19,7 @@
#define MWIFIEX_BSS_COEX_COUNT 2
#define MWIFIEX_MAX_BSS_NUM (3)
+#define MWIFIEX_MAX_CSA_COUNTERS 5
#define MWIFIEX_DMA_ALIGN_SZ 64
#define MWIFIEX_RX_HEADROOM 64
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 9024bb944e6a..92bc25bf550f 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -678,6 +678,7 @@ struct mwifiex_private {
struct delayed_work dfs_cac_work;
struct workqueue_struct *dfs_chan_sw_workqueue;
struct delayed_work dfs_chan_sw_work;
+ bool uap_stop_tx;
struct cfg80211_beacon_data beacon_after;
struct mwifiex_11h_intf_state state_11h;
struct mwifiex_ds_mem_rw mem_rw;
base-commit: ae98f5c9fd8ba84cd408b41faa77e65bf1b4cdfa
--
2.34.1
Powered by blists - more mailing lists