diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 113 |
1 files changed, 63 insertions, 50 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 74058020b7d6..33344f5a66a8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1641,6 +1641,29 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1641 | drv_stop(local); | 1641 | drv_stop(local); |
1642 | } | 1642 | } |
1643 | 1643 | ||
1644 | static void ieee80211_flush_completed_scan(struct ieee80211_local *local, | ||
1645 | bool aborted) | ||
1646 | { | ||
1647 | /* It's possible that we don't handle the scan completion in | ||
1648 | * time during suspend, so if it's still marked as completed | ||
1649 | * here, queue the work and flush it to clean things up. | ||
1650 | * Instead of calling the worker function directly here, we | ||
1651 | * really queue it to avoid potential races with other flows | ||
1652 | * scheduling the same work. | ||
1653 | */ | ||
1654 | if (test_bit(SCAN_COMPLETED, &local->scanning)) { | ||
1655 | /* If coming from reconfiguration failure, abort the scan so | ||
1656 | * we don't attempt to continue a partial HW scan - which is | ||
1657 | * possible otherwise if (e.g.) the 2.4 GHz portion was the | ||
1658 | * completed scan, and a 5 GHz portion is still pending. | ||
1659 | */ | ||
1660 | if (aborted) | ||
1661 | set_bit(SCAN_ABORTED, &local->scanning); | ||
1662 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); | ||
1663 | flush_delayed_work(&local->scan_work); | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1644 | static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) | 1667 | static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) |
1645 | { | 1668 | { |
1646 | struct ieee80211_sub_if_data *sdata; | 1669 | struct ieee80211_sub_if_data *sdata; |
@@ -1660,6 +1683,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) | |||
1660 | local->suspended = false; | 1683 | local->suspended = false; |
1661 | local->in_reconfig = false; | 1684 | local->in_reconfig = false; |
1662 | 1685 | ||
1686 | ieee80211_flush_completed_scan(local, true); | ||
1687 | |||
1663 | /* scheduled scan clearly can't be running any more, but tell | 1688 | /* scheduled scan clearly can't be running any more, but tell |
1664 | * cfg80211 and clear local state | 1689 | * cfg80211 and clear local state |
1665 | */ | 1690 | */ |
@@ -1698,6 +1723,27 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, | |||
1698 | mutex_unlock(&local->chanctx_mtx); | 1723 | mutex_unlock(&local->chanctx_mtx); |
1699 | } | 1724 | } |
1700 | 1725 | ||
1726 | static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata) | ||
1727 | { | ||
1728 | struct ieee80211_local *local = sdata->local; | ||
1729 | struct sta_info *sta; | ||
1730 | |||
1731 | /* add STAs back */ | ||
1732 | mutex_lock(&local->sta_mtx); | ||
1733 | list_for_each_entry(sta, &local->sta_list, list) { | ||
1734 | enum ieee80211_sta_state state; | ||
1735 | |||
1736 | if (!sta->uploaded || sta->sdata != sdata) | ||
1737 | continue; | ||
1738 | |||
1739 | for (state = IEEE80211_STA_NOTEXIST; | ||
1740 | state < sta->sta_state; state++) | ||
1741 | WARN_ON(drv_sta_state(local, sta->sdata, sta, state, | ||
1742 | state + 1)); | ||
1743 | } | ||
1744 | mutex_unlock(&local->sta_mtx); | ||
1745 | } | ||
1746 | |||
1701 | int ieee80211_reconfig(struct ieee80211_local *local) | 1747 | int ieee80211_reconfig(struct ieee80211_local *local) |
1702 | { | 1748 | { |
1703 | struct ieee80211_hw *hw = &local->hw; | 1749 | struct ieee80211_hw *hw = &local->hw; |
@@ -1833,50 +1879,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1833 | WARN_ON(drv_add_chanctx(local, ctx)); | 1879 | WARN_ON(drv_add_chanctx(local, ctx)); |
1834 | mutex_unlock(&local->chanctx_mtx); | 1880 | mutex_unlock(&local->chanctx_mtx); |
1835 | 1881 | ||
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); | 1882 | sdata = rtnl_dereference(local->monitor_sdata); |
1843 | if (sdata && ieee80211_sdata_running(sdata)) | 1883 | if (sdata && ieee80211_sdata_running(sdata)) |
1844 | ieee80211_assign_chanctx(local, sdata); | 1884 | ieee80211_assign_chanctx(local, sdata); |
1845 | } | 1885 | } |
1846 | 1886 | ||
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 */ | 1887 | /* reconfigure hardware */ |
1881 | ieee80211_hw_config(local, ~0); | 1888 | ieee80211_hw_config(local, ~0); |
1882 | 1889 | ||
@@ -1889,6 +1896,22 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1889 | if (!ieee80211_sdata_running(sdata)) | 1896 | if (!ieee80211_sdata_running(sdata)) |
1890 | continue; | 1897 | continue; |
1891 | 1898 | ||
1899 | ieee80211_assign_chanctx(local, sdata); | ||
1900 | |||
1901 | switch (sdata->vif.type) { | ||
1902 | case NL80211_IFTYPE_AP_VLAN: | ||
1903 | case NL80211_IFTYPE_MONITOR: | ||
1904 | break; | ||
1905 | default: | ||
1906 | ieee80211_reconfig_stations(sdata); | ||
1907 | /* fall through */ | ||
1908 | case NL80211_IFTYPE_AP: /* AP stations are handled later */ | ||
1909 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
1910 | drv_conf_tx(local, sdata, i, | ||
1911 | &sdata->tx_conf[i]); | ||
1912 | break; | ||
1913 | } | ||
1914 | |||
1892 | /* common change flags for all interface types */ | 1915 | /* common change flags for all interface types */ |
1893 | changed = BSS_CHANGED_ERP_CTS_PROT | | 1916 | changed = BSS_CHANGED_ERP_CTS_PROT | |
1894 | BSS_CHANGED_ERP_PREAMBLE | | 1917 | BSS_CHANGED_ERP_PREAMBLE | |
@@ -2074,17 +2097,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
2074 | mb(); | 2097 | mb(); |
2075 | local->resuming = false; | 2098 | local->resuming = false; |
2076 | 2099 | ||
2077 | /* It's possible that we don't handle the scan completion in | 2100 | 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 | 2101 | ||
2089 | if (local->open_count && !reconfig_due_to_wowlan) | 2102 | if (local->open_count && !reconfig_due_to_wowlan) |
2090 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); | 2103 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); |