mac80211: do not scan and monitor connection in parallel
authorStanislaw Gruszka <sgruszka@redhat.com>
Wed, 28 Mar 2012 14:01:19 +0000 (16:01 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 13 Apr 2012 18:31:49 +0000 (14:31 -0400)
Before we send probes in connection monitoring we check if scan is not
pending. But we do that check without locking. Fix that and also do not
start scan if connection monitoring is in progress.

Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/scan.c
net/mac80211/work.c

index 4be11ea3dfc4c5dc06e17d51ca67b6f66e76fe46..1fd8cb26b3ffde2af308179ad701e4efa1905fcd 100644 (file)
@@ -1260,6 +1260,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
 void ieee80211_scan_cancel(struct ieee80211_local *local);
+void ieee80211_run_deferred_scan(struct ieee80211_local *local);
 ieee80211_rx_result
 ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 
index bbf1100d90d6d7a50e3566f435fc9551508a735b..c8836fa7d627c65b6aa5a5e276c56af790f8b9bc 100644 (file)
@@ -1447,19 +1447,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_local *local = sdata->local;
 
+       mutex_lock(&local->mtx);
        if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
-                             IEEE80211_STA_CONNECTION_POLL)))
-           return;
+                             IEEE80211_STA_CONNECTION_POLL))) {
+               mutex_unlock(&local->mtx);
+               return;
+       }
 
        ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
                          IEEE80211_STA_BEACON_POLL);
-       mutex_lock(&sdata->local->iflist_mtx);
-       ieee80211_recalc_ps(sdata->local, -1);
-       mutex_unlock(&sdata->local->iflist_mtx);
+
+       mutex_lock(&local->iflist_mtx);
+       ieee80211_recalc_ps(local, -1);
+       mutex_unlock(&local->iflist_mtx);
 
        if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
-               return;
+               goto out;
 
        /*
         * We've received a probe response, but are not sure whether
@@ -1471,6 +1476,9 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
        mod_timer(&ifmgd->conn_mon_timer,
                  round_jiffies_up(jiffies +
                                   IEEE80211_CONNECTION_IDLE_TIME));
+out:
+       ieee80211_run_deferred_scan(local);
+       mutex_unlock(&local->mtx);
 }
 
 void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1546,17 +1554,18 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       if (sdata->local->scanning)
-               return;
-
-       if (sdata->local->tmp_channel)
-               return;
-
        mutex_lock(&ifmgd->mtx);
 
        if (!ifmgd->associated)
                goto out;
 
+       mutex_lock(&sdata->local->mtx);
+
+       if (sdata->local->tmp_channel || sdata->local->scanning) {
+               mutex_unlock(&sdata->local->mtx);
+               goto out;
+       }
+
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (beacon && net_ratelimit())
                printk(KERN_DEBUG "%s: detected beacon loss from AP "
@@ -1583,6 +1592,8 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        else
                ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
 
+       mutex_unlock(&sdata->local->mtx);
+
        if (already)
                goto out;
 
index c70e176771359b5e9371df1da486b29a157084f7..56175933c28f0ca7d487ddc39e622747f981a389 100644 (file)
@@ -387,6 +387,33 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        return 0;
 }
 
+static bool ieee80211_can_scan(struct ieee80211_local *local,
+                              struct ieee80211_sub_if_data *sdata)
+{
+       if (!list_empty(&local->work_list))
+               return false;
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+                                 IEEE80211_STA_CONNECTION_POLL))
+               return false;
+
+       return true;
+}
+
+void ieee80211_run_deferred_scan(struct ieee80211_local *local)
+{
+       lockdep_assert_held(&local->mtx);
+
+       if (!local->scan_req || local->scanning)
+               return;
+
+       if (!ieee80211_can_scan(local, local->scan_sdata))
+               return;
+
+       ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
+                                    round_jiffies_relative(0));
+}
 
 static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                                  struct cfg80211_scan_request *req)
@@ -399,7 +426,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        if (local->scan_req)
                return -EBUSY;
 
-       if (!list_empty(&local->work_list)) {
+       if (!ieee80211_can_scan(local, sdata)) {
                /* wait for the work to finish/time out */
                local->scan_req = req;
                local->scan_sdata = sdata;
index c6e230efa04952314cf3f995f4c58d08ba142038..1f74af33901bd3829773d3c1663e71d704508112 100644 (file)
@@ -226,13 +226,8 @@ static void ieee80211_work_work(struct work_struct *work)
                run_again(local, jiffies + HZ/2);
        }
 
-       if (list_empty(&local->work_list) && local->scan_req &&
-           !local->scanning)
-               ieee80211_queue_delayed_work(&local->hw,
-                                            &local->scan_work,
-                                            round_jiffies_relative(0));
-
        ieee80211_recalc_idle(local);
+       ieee80211_run_deferred_scan(local);
 
        mutex_unlock(&local->mtx);