From: Avinash Patil <patila@marvell.com>
To: <linux-wireless@vger.kernel.org>
Cc: <akarwar@marvell.com>, <cluo@marvell.com>, <gaoqs@marvell.com>,
Avinash Patil <patila@marvell.com>
Subject: [PATCH v2 09/10] mwifiex: channel switch support for mwifiex
Date: Wed, 28 Jan 2015 15:54:24 +0530 [thread overview]
Message-ID: <1422440665-3940-10-git-send-email-patila@marvell.com> (raw)
In-Reply-To: <1422440665-3940-1-git-send-email-patila@marvell.com>
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>
---
drivers/net/wireless/mwifiex/11h.c | 37 ++++++++++++++
drivers/net/wireless/mwifiex/cfg80211.c | 85 ++++++++++++++++++++++++++++++++-
drivers/net/wireless/mwifiex/ie.c | 12 ++++-
drivers/net/wireless/mwifiex/main.h | 5 ++
4 files changed, 136 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 08c12ae..d794686 100644
--- a/drivers/net/wireless/mwifiex/11h.c
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -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);
+}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 7a969fd..2d1ea93 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -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;
@@ -3116,6 +3139,62 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
}
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
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef,
@@ -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 |
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index a6af7b8..f3b6ed2 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -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);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index ad9d679..599698c 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -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);
--
1.8.1.4
next prev parent reply other threads:[~2015-01-28 4:56 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-28 10:24 [PATCH v2 00/10] mwifiex: DFS support for mwifiex AP Avinash Patil
2015-01-28 10:24 ` [PATCH v2 01/10] mwifiex: do not send regulatory update while starting AP Avinash Patil
2015-01-29 8:26 ` [v2, " Kalle Valo
2015-01-28 10:24 ` [PATCH v2 02/10] mwifiex: store AP configuration in private structure Avinash Patil
2015-01-28 10:24 ` [PATCH v2 03/10] mwifiex: update IEs after AP has started Avinash Patil
2015-01-28 10:24 ` [PATCH v2 04/10] mwifiex: refactor start_ap handler Avinash Patil
2015-01-28 10:24 ` [PATCH v2 05/10] mwifiex: separate function for parsing head and tail IEs Avinash Patil
2015-01-28 10:24 ` [PATCH v2 06/10] mwifiex: add cfg80211 start_radar_detection handler Avinash Patil
2015-01-28 10:24 ` [PATCH v2 07/10] mwifiex: support for channel report for radar detection Avinash Patil
2015-01-28 10:24 ` [PATCH v2 08/10] mwifiex: handle radar detect event from FW Avinash Patil
2015-01-28 10:24 ` Avinash Patil [this message]
2015-01-28 10:24 ` [PATCH v2 10/10] mwifiex: 11h handling for AP interface Avinash Patil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1422440665-3940-10-git-send-email-patila@marvell.com \
--to=patila@marvell.com \
--cc=akarwar@marvell.com \
--cc=cluo@marvell.com \
--cc=gaoqs@marvell.com \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).