mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
mwifiex: channel switch support for mwifiex
This patch adds cfg80211 channel_switch support for mwifiex. Upon receiving channel switch request, driver would parse channel switch announcement IE from beacon_data. If TX is blocked, netdev queues are stopped. IEs from csa_beacon are then parsed and set to FW. Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Qingshui Gao <gaoqs@marvell.com> Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
3b57c1a713
commit
7d652034d1
@ -240,3 +240,40 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is work queue function for channel switch handling.
|
||||||
|
* This function takes care of updating new channel definitin to
|
||||||
|
* bss config structure, restart AP and indicate channel switch success
|
||||||
|
* to cfg80211.
|
||||||
|
*/
|
||||||
|
void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct mwifiex_uap_bss_param *bss_cfg;
|
||||||
|
struct delayed_work *delayed_work =
|
||||||
|
container_of(work, struct delayed_work, work);
|
||||||
|
struct mwifiex_private *priv =
|
||||||
|
container_of(delayed_work, struct mwifiex_private,
|
||||||
|
dfs_chan_sw_work);
|
||||||
|
|
||||||
|
if (WARN_ON(!priv))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bss_cfg = &priv->bss_cfg;
|
||||||
|
if (!bss_cfg->beacon_period) {
|
||||||
|
dev_err(priv->adapter->dev,
|
||||||
|
"channel switch: AP already stopped\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef);
|
||||||
|
|
||||||
|
if (mwifiex_config_start_uap(priv, bss_cfg)) {
|
||||||
|
dev_dbg(priv->adapter->dev,
|
||||||
|
"Failed to start AP after channel switch\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_notice(priv->adapter->dev,
|
||||||
|
"indicating channel switch completion to kernel\n");
|
||||||
|
cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef);
|
||||||
|
}
|
||||||
|
@ -2399,7 +2399,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||||||
struct mwifiex_private *priv;
|
struct mwifiex_private *priv;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
void *mdev_priv;
|
void *mdev_priv;
|
||||||
char dfs_cac_str[MWIFIEX_MAX_WQ_LEN];
|
char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN];
|
||||||
|
|
||||||
if (!adapter)
|
if (!adapter)
|
||||||
return ERR_PTR(-EFAULT);
|
return ERR_PTR(-EFAULT);
|
||||||
@ -2582,6 +2582,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||||||
|
|
||||||
INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
|
INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
|
||||||
|
|
||||||
|
strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW");
|
||||||
|
strcat(dfs_chsw_str, name);
|
||||||
|
priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str,
|
||||||
|
WQ_HIGHPRI | WQ_UNBOUND |
|
||||||
|
WQ_MEM_RECLAIM, 1);
|
||||||
|
if (!priv->dfs_chan_sw_workqueue) {
|
||||||
|
wiphy_err(wiphy, "cannot register virtual network device\n");
|
||||||
|
free_netdev(dev);
|
||||||
|
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||||
|
priv->netdev = NULL;
|
||||||
|
memset(&priv->wdev, 0, sizeof(priv->wdev));
|
||||||
|
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&priv->dfs_chan_sw_work,
|
||||||
|
mwifiex_dfs_chan_sw_work_queue);
|
||||||
|
|
||||||
sema_init(&priv->async_sem, 1);
|
sema_init(&priv->async_sem, 1);
|
||||||
|
|
||||||
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
|
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
|
||||||
@ -2637,6 +2655,11 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||||||
priv->dfs_cac_workqueue = NULL;
|
priv->dfs_cac_workqueue = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->dfs_chan_sw_workqueue) {
|
||||||
|
flush_workqueue(priv->dfs_chan_sw_workqueue);
|
||||||
|
destroy_workqueue(priv->dfs_chan_sw_workqueue);
|
||||||
|
priv->dfs_chan_sw_workqueue = NULL;
|
||||||
|
}
|
||||||
/* Clear the priv in adapter */
|
/* Clear the priv in adapter */
|
||||||
priv->netdev->ieee80211_ptr = NULL;
|
priv->netdev->ieee80211_ptr = NULL;
|
||||||
priv->netdev = NULL;
|
priv->netdev = NULL;
|
||||||
@ -3115,6 +3138,62 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
|||||||
return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK);
|
return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (priv->adapter->scan_processing) {
|
||||||
|
dev_err(priv->adapter->dev,
|
||||||
|
"radar detection: scan in process...\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->wdev.cac_started)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (cfg80211_chandef_identical(¶ms->chandef,
|
||||||
|
&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) {
|
||||||
|
dev_err(priv->adapter->dev,
|
||||||
|
"Could not parse channel switch announcement IE\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_sw = (void *)(chsw_ie + 1);
|
||||||
|
if (channel_sw->mode) {
|
||||||
|
if (netif_carrier_ok(priv->netdev))
|
||||||
|
netif_carrier_off(priv->netdev);
|
||||||
|
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mwifiex_del_mgmt_ies(priv))
|
||||||
|
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
|
||||||
|
|
||||||
|
if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon_csa)) {
|
||||||
|
wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&priv->dfs_chandef, ¶ms->chandef, sizeof(priv->dfs_chandef));
|
||||||
|
memcpy(&priv->beacon_after, ¶ms->beacon_after,
|
||||||
|
sizeof(priv->beacon_after));
|
||||||
|
|
||||||
|
chsw_msec = max(channel_sw->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;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
|
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
@ -3210,6 +3289,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
|||||||
.add_station = mwifiex_cfg80211_add_station,
|
.add_station = mwifiex_cfg80211_add_station,
|
||||||
.change_station = mwifiex_cfg80211_change_station,
|
.change_station = mwifiex_cfg80211_change_station,
|
||||||
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
|
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
|
||||||
|
.channel_switch = mwifiex_cfg80211_channel_switch,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
@ -3313,7 +3393,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||||||
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
|
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
|
||||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
|
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
|
||||||
WIPHY_FLAG_AP_UAPSD |
|
WIPHY_FLAG_AP_UAPSD |
|
||||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||||
|
WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||||
|
|
||||||
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
|
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
|
||||||
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
|
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
|
||||||
|
@ -325,6 +325,7 @@ static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
|
|||||||
{
|
{
|
||||||
struct mwifiex_ie *gen_ie;
|
struct mwifiex_ie *gen_ie;
|
||||||
struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
|
struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
|
||||||
|
struct ieee_types_header *chsw_ie = NULL;
|
||||||
u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
|
u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
|
||||||
const u8 *vendor_ie;
|
const u8 *vendor_ie;
|
||||||
|
|
||||||
@ -356,9 +357,18 @@ static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
|
|||||||
ie_len += wpa_ie->len + 2;
|
ie_len += wpa_ie->len + 2;
|
||||||
gen_ie->ie_length = cpu_to_le16(ie_len);
|
gen_ie->ie_length = cpu_to_le16(ie_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
|
||||||
|
info->tail, info->tail_len);
|
||||||
|
if (chsw_ie) {
|
||||||
|
memcpy(gen_ie->ie_buffer + ie_len,
|
||||||
|
chsw_ie, chsw_ie->len + 2);
|
||||||
|
ie_len += chsw_ie->len + 2;
|
||||||
|
gen_ie->ie_length = cpu_to_le16(ie_len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsn_ie || wpa_ie) {
|
if (rsn_ie || wpa_ie || chsw_ie) {
|
||||||
if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL,
|
if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL,
|
||||||
NULL, NULL, NULL)) {
|
NULL, NULL, NULL)) {
|
||||||
kfree(gen_ie);
|
kfree(gen_ie);
|
||||||
|
@ -591,6 +591,10 @@ struct mwifiex_private {
|
|||||||
struct cfg80211_chan_def dfs_chandef;
|
struct cfg80211_chan_def dfs_chandef;
|
||||||
struct workqueue_struct *dfs_cac_workqueue;
|
struct workqueue_struct *dfs_cac_workqueue;
|
||||||
struct delayed_work dfs_cac_work;
|
struct delayed_work dfs_cac_work;
|
||||||
|
struct timer_list dfs_chan_switch_timer;
|
||||||
|
struct workqueue_struct *dfs_chan_sw_workqueue;
|
||||||
|
struct delayed_work dfs_chan_sw_work;
|
||||||
|
struct cfg80211_beacon_data beacon_after;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum mwifiex_ba_status {
|
enum mwifiex_ba_status {
|
||||||
@ -1394,6 +1398,7 @@ struct sk_buff *
|
|||||||
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
|
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
|
||||||
struct sk_buff *skb, u8 flag, u64 *cookie);
|
struct sk_buff *skb, u8 flag, u64 *cookie);
|
||||||
void mwifiex_dfs_cac_work_queue(struct work_struct *work);
|
void mwifiex_dfs_cac_work_queue(struct work_struct *work);
|
||||||
|
void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work);
|
||||||
void mwifiex_abort_cac(struct mwifiex_private *priv);
|
void mwifiex_abort_cac(struct mwifiex_private *priv);
|
||||||
int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
|
int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
|
||||||
struct sk_buff *skb);
|
struct sk_buff *skb);
|
||||||
|
Loading…
Reference in New Issue
Block a user