aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
authorAvinash Patil <patila@marvell.com>2015-01-28 05:24:24 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-01-29 03:22:10 -0500
commit7d652034d1a08bd240c98727bbd55901a174c245 (patch)
treea8473d503aeb2e51a70a59b10ff3d10871807280 /drivers/net/wireless/mwifiex
parent3b57c1a713a9dd3b8da74b6df9f16ce1f8f9144b (diff)
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>
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/11h.c37
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c85
-rw-r--r--drivers/net/wireless/mwifiex/ie.c12
-rw-r--r--drivers/net/wireless/mwifiex/main.h5
4 files changed, 136 insertions, 3 deletions
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 08c12aece9ae..d794686e31d6 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,
240 240
241 return 0; 241 return 0;
242} 242}
243
244/* This is work queue function for channel switch handling.
245 * This function takes care of updating new channel definitin to
246 * bss config structure, restart AP and indicate channel switch success
247 * to cfg80211.
248 */
249void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
250{
251 struct mwifiex_uap_bss_param *bss_cfg;
252 struct delayed_work *delayed_work =
253 container_of(work, struct delayed_work, work);
254 struct mwifiex_private *priv =
255 container_of(delayed_work, struct mwifiex_private,
256 dfs_chan_sw_work);
257
258 if (WARN_ON(!priv))
259 return;
260
261 bss_cfg = &priv->bss_cfg;
262 if (!bss_cfg->beacon_period) {
263 dev_err(priv->adapter->dev,
264 "channel switch: AP already stopped\n");
265 return;
266 }
267
268 mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef);
269
270 if (mwifiex_config_start_uap(priv, bss_cfg)) {
271 dev_dbg(priv->adapter->dev,
272 "Failed to start AP after channel switch\n");
273 return;
274 }
275
276 dev_notice(priv->adapter->dev,
277 "indicating channel switch completion to kernel\n");
278 cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef);
279}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 7a969fd2f0cd..2d1ea938e08e 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,
2399 struct mwifiex_private *priv; 2399 struct mwifiex_private *priv;
2400 struct net_device *dev; 2400 struct net_device *dev;
2401 void *mdev_priv; 2401 void *mdev_priv;
2402 char dfs_cac_str[MWIFIEX_MAX_WQ_LEN]; 2402 char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN];
2403 2403
2404 if (!adapter) 2404 if (!adapter)
2405 return ERR_PTR(-EFAULT); 2405 return ERR_PTR(-EFAULT);
@@ -2582,6 +2582,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
2582 2582
2583 INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); 2583 INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
2584 2584
2585 strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW");
2586 strcat(dfs_chsw_str, name);
2587 priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str,
2588 WQ_HIGHPRI | WQ_UNBOUND |
2589 WQ_MEM_RECLAIM, 1);
2590 if (!priv->dfs_chan_sw_workqueue) {
2591 wiphy_err(wiphy, "cannot register virtual network device\n");
2592 free_netdev(dev);
2593 priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
2594 priv->netdev = NULL;
2595 memset(&priv->wdev, 0, sizeof(priv->wdev));
2596 priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
2597 return ERR_PTR(-ENOMEM);
2598 }
2599
2600 INIT_DELAYED_WORK(&priv->dfs_chan_sw_work,
2601 mwifiex_dfs_chan_sw_work_queue);
2602
2585 sema_init(&priv->async_sem, 1); 2603 sema_init(&priv->async_sem, 1);
2586 2604
2587 dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); 2605 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)
2637 priv->dfs_cac_workqueue = NULL; 2655 priv->dfs_cac_workqueue = NULL;
2638 } 2656 }
2639 2657
2658 if (priv->dfs_chan_sw_workqueue) {
2659 flush_workqueue(priv->dfs_chan_sw_workqueue);
2660 destroy_workqueue(priv->dfs_chan_sw_workqueue);
2661 priv->dfs_chan_sw_workqueue = NULL;
2662 }
2640 /* Clear the priv in adapter */ 2663 /* Clear the priv in adapter */
2641 priv->netdev->ieee80211_ptr = NULL; 2664 priv->netdev->ieee80211_ptr = NULL;
2642 priv->netdev = NULL; 2665 priv->netdev = NULL;
@@ -3116,6 +3139,62 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
3116} 3139}
3117 3140
3118static int 3141static int
3142mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3143 struct cfg80211_csa_settings *params)
3144{
3145 struct ieee_types_header *chsw_ie;
3146 struct ieee80211_channel_sw_ie *channel_sw;
3147 int chsw_msec;
3148 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
3149
3150 if (priv->adapter->scan_processing) {
3151 dev_err(priv->adapter->dev,
3152 "radar detection: scan in process...\n");
3153 return -EBUSY;
3154 }
3155
3156 if (priv->wdev.cac_started)
3157 return -EBUSY;
3158
3159 if (cfg80211_chandef_identical(&params->chandef,
3160 &priv->dfs_chandef))
3161 return -EINVAL;
3162
3163 chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
3164 params->beacon_csa.tail,
3165 params->beacon_csa.tail_len);
3166 if (!chsw_ie) {
3167 dev_err(priv->adapter->dev,
3168 "Could not parse channel switch announcement IE\n");
3169 return -EINVAL;
3170 }
3171
3172 channel_sw = (void *)(chsw_ie + 1);
3173 if (channel_sw->mode) {
3174 if (netif_carrier_ok(priv->netdev))
3175 netif_carrier_off(priv->netdev);
3176 mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
3177 }
3178
3179 if (mwifiex_del_mgmt_ies(priv))
3180 wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
3181
3182 if (mwifiex_set_mgmt_ies(priv, &params->beacon_csa)) {
3183 wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
3184 return -EFAULT;
3185 }
3186
3187 memcpy(&priv->dfs_chandef, &params->chandef, sizeof(priv->dfs_chandef));
3188 memcpy(&priv->beacon_after, &params->beacon_after,
3189 sizeof(priv->beacon_after));
3190
3191 chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100);
3192 queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work,
3193 msecs_to_jiffies(chsw_msec));
3194 return 0;
3195}
3196
3197static int
3119mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, 3198mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
3120 struct net_device *dev, 3199 struct net_device *dev,
3121 struct cfg80211_chan_def *chandef, 3200 struct cfg80211_chan_def *chandef,
@@ -3210,6 +3289,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
3210 .add_station = mwifiex_cfg80211_add_station, 3289 .add_station = mwifiex_cfg80211_add_station,
3211 .change_station = mwifiex_cfg80211_change_station, 3290 .change_station = mwifiex_cfg80211_change_station,
3212 .start_radar_detection = mwifiex_cfg80211_start_radar_detection, 3291 .start_radar_detection = mwifiex_cfg80211_start_radar_detection,
3292 .channel_switch = mwifiex_cfg80211_channel_switch,
3213}; 3293};
3214 3294
3215#ifdef CONFIG_PM 3295#ifdef CONFIG_PM
@@ -3313,7 +3393,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
3313 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | 3393 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
3314 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | 3394 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
3315 WIPHY_FLAG_AP_UAPSD | 3395 WIPHY_FLAG_AP_UAPSD |
3316 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 3396 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
3397 WIPHY_FLAG_HAS_CHANNEL_SWITCH;
3317 3398
3318 if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) 3399 if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
3319 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 3400 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index a6af7b88bf05..f3b6ed249403 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,
325{ 325{
326 struct mwifiex_ie *gen_ie; 326 struct mwifiex_ie *gen_ie;
327 struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL; 327 struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
328 struct ieee_types_header *chsw_ie = NULL;
328 u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; 329 u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
329 const u8 *vendor_ie; 330 const u8 *vendor_ie;
330 331
@@ -356,9 +357,18 @@ static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
356 ie_len += wpa_ie->len + 2; 357 ie_len += wpa_ie->len + 2;
357 gen_ie->ie_length = cpu_to_le16(ie_len); 358 gen_ie->ie_length = cpu_to_le16(ie_len);
358 } 359 }
360
361 chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
362 info->tail, info->tail_len);
363 if (chsw_ie) {
364 memcpy(gen_ie->ie_buffer + ie_len,
365 chsw_ie, chsw_ie->len + 2);
366 ie_len += chsw_ie->len + 2;
367 gen_ie->ie_length = cpu_to_le16(ie_len);
368 }
359 } 369 }
360 370
361 if (rsn_ie || wpa_ie) { 371 if (rsn_ie || wpa_ie || chsw_ie) {
362 if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, 372 if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL,
363 NULL, NULL, NULL)) { 373 NULL, NULL, NULL)) {
364 kfree(gen_ie); 374 kfree(gen_ie);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index ad9d679c3eed..599698c6b627 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -591,6 +591,10 @@ struct mwifiex_private {
591 struct cfg80211_chan_def dfs_chandef; 591 struct cfg80211_chan_def dfs_chandef;
592 struct workqueue_struct *dfs_cac_workqueue; 592 struct workqueue_struct *dfs_cac_workqueue;
593 struct delayed_work dfs_cac_work; 593 struct delayed_work dfs_cac_work;
594 struct timer_list dfs_chan_switch_timer;
595 struct workqueue_struct *dfs_chan_sw_workqueue;
596 struct delayed_work dfs_chan_sw_work;
597 struct cfg80211_beacon_data beacon_after;
594}; 598};
595 599
596enum mwifiex_ba_status { 600enum mwifiex_ba_status {
@@ -1394,6 +1398,7 @@ struct sk_buff *
1394mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, 1398mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
1395 struct sk_buff *skb, u8 flag, u64 *cookie); 1399 struct sk_buff *skb, u8 flag, u64 *cookie);
1396void mwifiex_dfs_cac_work_queue(struct work_struct *work); 1400void mwifiex_dfs_cac_work_queue(struct work_struct *work);
1401void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work);
1397void mwifiex_abort_cac(struct mwifiex_private *priv); 1402void mwifiex_abort_cac(struct mwifiex_private *priv);
1398int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, 1403int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
1399 struct sk_buff *skb); 1404 struct sk_buff *skb);