diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4be11ea3dfc4c5dc06e17d51ca67b6f66e76fe46..1fd8cb26b3ffde2af308179ad701e4efa1905fcd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -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); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bbf1100d90d6d7a50e3566f435fc9551508a735b..c8836fa7d627c65b6aa5a5e276c56af790f8b9bc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -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; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c70e176771359b5e9371df1da486b29a157084f7..56175933c28f0ca7d487ddc39e622747f981a389 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -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; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index c6e230efa04952314cf3f995f4c58d08ba142038..1f74af33901bd3829773d3c1663e71d704508112 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -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);