提交 7d652034 编写于 作者: A Avinash Patil 提交者: Kalle Valo

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: NAvinash Patil <patila@marvell.com>
Signed-off-by: NQingshui Gao <gaoqs@marvell.com>
Signed-off-by: NCathy Luo <cluo@marvell.com>
Signed-off-by: NKalle Valo <kvalo@codeaurora.org>
上级 3b57c1a7
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -240,3 +240,40 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
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 net_device *dev;
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)
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);
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);
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;
}
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 */
priv->netdev->ieee80211_ptr = 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);
}
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(&params->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, &params->beacon_csa)) {
wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
return -EFAULT;
}
memcpy(&priv->dfs_chandef, &params->chandef, sizeof(priv->dfs_chandef));
memcpy(&priv->beacon_after, &params->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
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
......@@ -3210,6 +3289,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.add_station = mwifiex_cfg80211_add_station,
.change_station = mwifiex_cfg80211_change_station,
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
.channel_switch = mwifiex_cfg80211_channel_switch,
};
#ifdef CONFIG_PM
......@@ -3313,7 +3393,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
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))
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 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;
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;
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,
NULL, NULL, NULL)) {
kfree(gen_ie);
......
......@@ -591,6 +591,10 @@ struct mwifiex_private {
struct cfg80211_chan_def dfs_chandef;
struct workqueue_struct *dfs_cac_workqueue;
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 {
......@@ -1394,6 +1398,7 @@ struct sk_buff *
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
struct sk_buff *skb, u8 flag, u64 *cookie);
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);
int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
struct sk_buff *skb);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部