wil6210: abort P2P search when stopping P2P device
authorLior David <qca_liord@qca.qualcomm.com>
Wed, 8 Jun 2016 17:07:48 +0000 (20:07 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Tue, 14 Jun 2016 13:20:18 +0000 (16:20 +0300)
The nl80211 layer expects P2P search operation to be aborted
if needed when stopping P2P device. If the P2P search operation
is still running after returning from stop_p2p_device
it causes a WARN_ON and possibly a kernel crash.
Fix this by aborting the P2P search in wil_cfg80211_stop_p2p_device
and preventing P2P search from being started on a stopped P2P
device.
Note, the fix does not cover the case where a regular scan
is started on the P2P device. It will be completed in the
future when support is added for aborting a scan operation.

Signed-off-by: Lior David <qca_liord@qca.qualcomm.com>
Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/wil6210.h

index 5769811291bf4e085afe76dd1cba48f0c7212c35..62bf9331bd7f35409ba9bd3e11a310b7d88cb0a7 100644 (file)
@@ -378,6 +378,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        /* social scan on P2P_DEVICE is handled as p2p search */
        if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
            wil_p2p_is_social_scan(request)) {
+               if (!wil->p2p.p2p_dev_started) {
+                       wil_err(wil, "P2P search requested on stopped P2P device\n");
+                       return -EIO;
+               }
                wil->scan_request = request;
                wil->radio_wdev = wdev;
                rc = wil_p2p_search(wil, request);
@@ -1351,6 +1355,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
        wil_dbg_misc(wil, "%s: entered\n", __func__);
+       wil->p2p.p2p_dev_started = 1;
        return 0;
 }
 
@@ -1358,8 +1363,19 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
                                         struct wireless_dev *wdev)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       u8 started;
 
        wil_dbg_misc(wil, "%s: entered\n", __func__);
+       mutex_lock(&wil->mutex);
+       started = wil_p2p_stop_discovery(wil);
+       if (started && wil->scan_request) {
+               cfg80211_scan_done(wil->scan_request, 1);
+               wil->scan_request = NULL;
+               wil->radio_wdev = wil->wdev;
+       }
+       mutex_unlock(&wil->mutex);
+
+       wil->p2p.p2p_dev_started = 0;
 }
 
 static struct cfg80211_ops wil_cfg80211_ops = {
index 1feaf5a16fab64db7511d430e9c2198bbd89b713..ecab4af90602f39e39c9c9b378a0da513a1932db 100644 (file)
@@ -458,6 +458,7 @@ struct wil_tid_crypto_rx {
 struct wil_p2p_info {
        struct ieee80211_channel listen_chan;
        u8 discovery_started;
+       u8 p2p_dev_started;
        u64 cookie;
        struct timer_list discovery_timer; /* listen/search duration */
        struct work_struct discovery_expired_work; /* listen/search expire */