Commit d8d9008c authored by Johannes Berg's avatar Johannes Berg

mac80211: shut down interfaces before destroying interface list

If the hardware is unregistered while interfaces are up, mac80211 will
unregister all interfaces, which in turns causes mac80211 to be called
again to remove them all from the driver and eventually shut down the
hardware.

During this shutdown, however, it's currently already unsafe to iterate
the list of interfaces atomically, as the list is manipulated in an
unsafe manner. This puts an undue burden on the driver - it must stop
all its activities before calling ieee80211_unregister_hw(), while in
the normal stop path it can do all cleanup in the stop method. If, for
example, it's using the iteration during RX for some reason, it would
have to stop RX before unregistering to avoid crashes.

Fix this problem by closing all interfaces before unregistering them.
This will cause the driver stop to have completed before we manipulate
the interface list, and after the driver is stopped *and* has called
ieee80211_unregister_hw() it really musn't be iterating any more as
the memory will be freed as well.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 541b6ed7
...@@ -1863,10 +1863,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) ...@@ -1863,10 +1863,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
ieee80211_teardown_sdata(sdata); ieee80211_teardown_sdata(sdata);
} }
/*
* Remove all interfaces, may only be called at hardware unregistration
* time because it doesn't do RCU-safe list removals.
*/
void ieee80211_remove_interfaces(struct ieee80211_local *local) void ieee80211_remove_interfaces(struct ieee80211_local *local)
{ {
struct ieee80211_sub_if_data *sdata, *tmp; struct ieee80211_sub_if_data *sdata, *tmp;
...@@ -1875,14 +1871,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) ...@@ -1875,14 +1871,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
ASSERT_RTNL(); ASSERT_RTNL();
/* /* Before destroying the interfaces, make sure they're all stopped so
* Close all AP_VLAN interfaces first, as otherwise they * that the hardware is stopped. Otherwise, the driver might still be
* might be closed while the AP interface they belong to * iterating the interfaces during the shutdown, e.g. from a worker
* is closed, causing unregister_netdevice_many() to crash. * or from RX processing or similar, and if it does so (using atomic
* iteration) while we're manipulating the list, the iteration will
* crash.
*
* After this, the hardware should be stopped and the driver should
* have stopped all of its activities, so that we can do RCU-unaware
* manipulations of the interface list below.
*/ */
list_for_each_entry(sdata, &local->interfaces, list) cfg80211_shutdown_all_interfaces(local->hw.wiphy);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
dev_close(sdata->dev); WARN(local->open_count, "%s: open count remains %d\n",
wiphy_name(local->hw.wiphy), local->open_count);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment