diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 120 |
1 files changed, 68 insertions, 52 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 74058020b7d6..3943d4bf289c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -288,10 +288,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
288 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) | 288 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) |
289 | return; | 289 | return; |
290 | 290 | ||
291 | if (!refcounted) | 291 | if (!refcounted) { |
292 | local->q_stop_reasons[queue][reason] = 0; | 292 | local->q_stop_reasons[queue][reason] = 0; |
293 | else | 293 | } else { |
294 | local->q_stop_reasons[queue][reason]--; | 294 | local->q_stop_reasons[queue][reason]--; |
295 | if (WARN_ON(local->q_stop_reasons[queue][reason] < 0)) | ||
296 | local->q_stop_reasons[queue][reason] = 0; | ||
297 | } | ||
295 | 298 | ||
296 | if (local->q_stop_reasons[queue][reason] == 0) | 299 | if (local->q_stop_reasons[queue][reason] == 0) |
297 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 300 | __clear_bit(reason, &local->queue_stop_reasons[queue]); |
@@ -1641,6 +1644,29 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1641 | drv_stop(local); | 1644 | drv_stop(local); |
1642 | } | 1645 | } |
1643 | 1646 | ||
1647 | static void ieee80211_flush_completed_scan(struct ieee80211_local *local, | ||
1648 | bool aborted) | ||
1649 | { | ||
1650 | /* It's possible that we don't handle the scan completion in | ||
1651 | * time during suspend, so if it's still marked as completed | ||
1652 | * here, queue the work and flush it to clean things up. | ||
1653 | * Instead of calling the worker function directly here, we | ||
1654 | * really queue it to avoid potential races with other flows | ||
1655 | * scheduling the same work. | ||
1656 | */ | ||
1657 | if (test_bit(SCAN_COMPLETED, &local->scanning)) { | ||
1658 | /* If coming from reconfiguration failure, abort the scan so | ||
1659 | * we don't attempt to continue a partial HW scan - which is | ||
1660 | * possible otherwise if (e.g.) the 2.4 GHz portion was the | ||
1661 | * completed scan, and a 5 GHz portion is still pending. | ||
1662 | */ | ||
1663 | if (aborted) | ||
1664 | set_bit(SCAN_ABORTED, &local->scanning); | ||
1665 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); | ||
1666 | flush_delayed_work(&local->scan_work); | ||
1667 | } | ||
1668 | } | ||
1669 | |||
1644 | static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) | 1670 | static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) |
1645 | { | 1671 | { |
1646 | struct ieee80211_sub_if_data *sdata; | 1672 | struct ieee80211_sub_if_data *sdata; |
@@ -1660,6 +1686,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) | |||
1660 | local->suspended = false; | 1686 | local->suspended = false; |
1661 | local->in_reconfig = false; | 1687 | local->in_reconfig = false; |
1662 | 1688 | ||
1689 | ieee80211_flush_completed_scan(local, true); | ||
1690 | |||
1663 | /* scheduled scan clearly can't be running any more, but tell | 1691 | /* scheduled scan clearly can't be running any more, but tell |
1664 | * cfg80211 and clear local state | 1692 | * cfg80211 and clear local state |
1665 | */ | 1693 | */ |
@@ -1698,6 +1726,27 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, | |||
1698 | mutex_unlock(&local->chanctx_mtx); | 1726 | mutex_unlock(&local->chanctx_mtx); |
1699 | } | 1727 | } |
1700 | 1728 | ||
1729 | static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata) | ||
1730 | { | ||
1731 | struct ieee80211_local *local = sdata->local; | ||
1732 | struct sta_info *sta; | ||
1733 | |||
1734 | /* add STAs back */ | ||
1735 | mutex_lock(&local->sta_mtx); | ||
1736 | list_for_each_entry(sta, &local->sta_list, list) { | ||
1737 | enum ieee80211_sta_state state; | ||
1738 | |||
1739 | if (!sta->uploaded || sta->sdata != sdata) | ||
1740 | continue; | ||
1741 | |||
1742 | for (state = IEEE80211_STA_NOTEXIST; | ||
1743 | state < sta->sta_state; state++) | ||
1744 | WARN_ON(drv_sta_state(local, sta->sdata, sta, state, | ||
1745 | state + 1)); | ||
1746 | } | ||
1747 | mutex_unlock(&local->sta_mtx); | ||
1748 | } | ||
1749 | |||
1701 | int ieee80211_reconfig(struct ieee80211_local *local) | 1750 | int ieee80211_reconfig(struct ieee80211_local *local) |
1702 | { | 1751 | { |
1703 | struct ieee80211_hw *hw = &local->hw; | 1752 | struct ieee80211_hw *hw = &local->hw; |
@@ -1833,50 +1882,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1833 | WARN_ON(drv_add_chanctx(local, ctx)); | 1882 | WARN_ON(drv_add_chanctx(local, ctx)); |
1834 | mutex_unlock(&local->chanctx_mtx); | 1883 | mutex_unlock(&local->chanctx_mtx); |
1835 | 1884 | ||
1836 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1837 | if (!ieee80211_sdata_running(sdata)) | ||
1838 | continue; | ||
1839 | ieee80211_assign_chanctx(local, sdata); | ||
1840 | } | ||
1841 | |||
1842 | sdata = rtnl_dereference(local->monitor_sdata); | 1885 | sdata = rtnl_dereference(local->monitor_sdata); |
1843 | if (sdata && ieee80211_sdata_running(sdata)) | 1886 | if (sdata && ieee80211_sdata_running(sdata)) |
1844 | ieee80211_assign_chanctx(local, sdata); | 1887 | ieee80211_assign_chanctx(local, sdata); |
1845 | } | 1888 | } |
1846 | 1889 | ||
1847 | /* add STAs back */ | ||
1848 | mutex_lock(&local->sta_mtx); | ||
1849 | list_for_each_entry(sta, &local->sta_list, list) { | ||
1850 | enum ieee80211_sta_state state; | ||
1851 | |||
1852 | if (!sta->uploaded) | ||
1853 | continue; | ||
1854 | |||
1855 | /* AP-mode stations will be added later */ | ||
1856 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) | ||
1857 | continue; | ||
1858 | |||
1859 | for (state = IEEE80211_STA_NOTEXIST; | ||
1860 | state < sta->sta_state; state++) | ||
1861 | WARN_ON(drv_sta_state(local, sta->sdata, sta, state, | ||
1862 | state + 1)); | ||
1863 | } | ||
1864 | mutex_unlock(&local->sta_mtx); | ||
1865 | |||
1866 | /* reconfigure tx conf */ | ||
1867 | if (hw->queues >= IEEE80211_NUM_ACS) { | ||
1868 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1869 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||
1870 | sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1871 | !ieee80211_sdata_running(sdata)) | ||
1872 | continue; | ||
1873 | |||
1874 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
1875 | drv_conf_tx(local, sdata, i, | ||
1876 | &sdata->tx_conf[i]); | ||
1877 | } | ||
1878 | } | ||
1879 | |||
1880 | /* reconfigure hardware */ | 1890 | /* reconfigure hardware */ |
1881 | ieee80211_hw_config(local, ~0); | 1891 | ieee80211_hw_config(local, ~0); |
1882 | 1892 | ||
@@ -1889,6 +1899,22 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1889 | if (!ieee80211_sdata_running(sdata)) | 1899 | if (!ieee80211_sdata_running(sdata)) |
1890 | continue; | 1900 | continue; |
1891 | 1901 | ||
1902 | ieee80211_assign_chanctx(local, sdata); | ||
1903 | |||
1904 | switch (sdata->vif.type) { | ||
1905 | case NL80211_IFTYPE_AP_VLAN: | ||
1906 | case NL80211_IFTYPE_MONITOR: | ||
1907 | break; | ||
1908 | default: | ||
1909 | ieee80211_reconfig_stations(sdata); | ||
1910 | /* fall through */ | ||
1911 | case NL80211_IFTYPE_AP: /* AP stations are handled later */ | ||
1912 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
1913 | drv_conf_tx(local, sdata, i, | ||
1914 | &sdata->tx_conf[i]); | ||
1915 | break; | ||
1916 | } | ||
1917 | |||
1892 | /* common change flags for all interface types */ | 1918 | /* common change flags for all interface types */ |
1893 | changed = BSS_CHANGED_ERP_CTS_PROT | | 1919 | changed = BSS_CHANGED_ERP_CTS_PROT | |
1894 | BSS_CHANGED_ERP_PREAMBLE | | 1920 | BSS_CHANGED_ERP_PREAMBLE | |
@@ -2074,17 +2100,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
2074 | mb(); | 2100 | mb(); |
2075 | local->resuming = false; | 2101 | local->resuming = false; |
2076 | 2102 | ||
2077 | /* It's possible that we don't handle the scan completion in | 2103 | ieee80211_flush_completed_scan(local, false); |
2078 | * time during suspend, so if it's still marked as completed | ||
2079 | * here, queue the work and flush it to clean things up. | ||
2080 | * Instead of calling the worker function directly here, we | ||
2081 | * really queue it to avoid potential races with other flows | ||
2082 | * scheduling the same work. | ||
2083 | */ | ||
2084 | if (test_bit(SCAN_COMPLETED, &local->scanning)) { | ||
2085 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); | ||
2086 | flush_delayed_work(&local->scan_work); | ||
2087 | } | ||
2088 | 2104 | ||
2089 | if (local->open_count && !reconfig_due_to_wowlan) | 2105 | if (local->open_count && !reconfig_due_to_wowlan) |
2090 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); | 2106 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); |