Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: reprogram in interface order

During reprogramming, mac80211 currently first adds all the channel
contexts, then binds them to the vifs and then goes to reconfigure
all the interfaces. Drivers might, perhaps implicitly, rely on the
operation order for certain things that typically happen within a
single function elsewhere in mac80211. To avoid problems with that,
reorder the code in mac80211's restart/reprogramming to work fully
within the interface loop so that the order of operations is like
in normal operation.

For iwlwifi, this fixes a firmware crash when reprogramming with an
AP/GO interface active.

Reported-by: David Spinadel <david.spinadel@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

+37 -39
+37 -39
net/mac80211/util.c
··· 1723 1723 mutex_unlock(&local->chanctx_mtx); 1724 1724 } 1725 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 + 1726 1747 int ieee80211_reconfig(struct ieee80211_local *local) 1727 1748 { 1728 1749 struct ieee80211_hw *hw = &local->hw; ··· 1879 1858 WARN_ON(drv_add_chanctx(local, ctx)); 1880 1859 mutex_unlock(&local->chanctx_mtx); 1881 1860 1882 - list_for_each_entry(sdata, &local->interfaces, list) { 1883 - if (!ieee80211_sdata_running(sdata)) 1884 - continue; 1885 - ieee80211_assign_chanctx(local, sdata); 1886 - } 1887 - 1888 1861 sdata = rtnl_dereference(local->monitor_sdata); 1889 1862 if (sdata && ieee80211_sdata_running(sdata)) 1890 1863 ieee80211_assign_chanctx(local, sdata); 1891 - } 1892 - 1893 - /* add STAs back */ 1894 - mutex_lock(&local->sta_mtx); 1895 - list_for_each_entry(sta, &local->sta_list, list) { 1896 - enum ieee80211_sta_state state; 1897 - 1898 - if (!sta->uploaded) 1899 - continue; 1900 - 1901 - /* AP-mode stations will be added later */ 1902 - if (sta->sdata->vif.type == NL80211_IFTYPE_AP) 1903 - continue; 1904 - 1905 - for (state = IEEE80211_STA_NOTEXIST; 1906 - state < sta->sta_state; state++) 1907 - WARN_ON(drv_sta_state(local, sta->sdata, sta, state, 1908 - state + 1)); 1909 - } 1910 - mutex_unlock(&local->sta_mtx); 1911 - 1912 - /* reconfigure tx conf */ 1913 - if (hw->queues >= IEEE80211_NUM_ACS) { 1914 - list_for_each_entry(sdata, &local->interfaces, list) { 1915 - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || 1916 - sdata->vif.type == NL80211_IFTYPE_MONITOR || 1917 - !ieee80211_sdata_running(sdata)) 1918 - continue; 1919 - 1920 - for (i = 0; i < IEEE80211_NUM_ACS; i++) 1921 - drv_conf_tx(local, sdata, i, 1922 - &sdata->tx_conf[i]); 1923 - } 1924 1864 } 1925 1865 1926 1866 /* reconfigure hardware */ ··· 1895 1913 1896 1914 if (!ieee80211_sdata_running(sdata)) 1897 1915 continue; 1916 + 1917 + ieee80211_assign_chanctx(local, sdata); 1918 + 1919 + switch (sdata->vif.type) { 1920 + case NL80211_IFTYPE_AP_VLAN: 1921 + case NL80211_IFTYPE_MONITOR: 1922 + break; 1923 + default: 1924 + ieee80211_reconfig_stations(sdata); 1925 + /* fall through */ 1926 + case NL80211_IFTYPE_AP: /* AP stations are handled later */ 1927 + for (i = 0; i < IEEE80211_NUM_ACS; i++) 1928 + drv_conf_tx(local, sdata, i, 1929 + &sdata->tx_conf[i]); 1930 + break; 1931 + } 1898 1932 1899 1933 /* common change flags for all interface types */ 1900 1934 changed = BSS_CHANGED_ERP_CTS_PROT |