Commit b9dcf712 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: clean up ifdown/cleanup paths

There's a lot of redundant code in mac80211's
interface cleanup/down, for example freeing
AP beacons is done both when the interface is
set DOWN as well as when it is torn down, of
which only the former has any effect.

Also, a bunch of things should be closer to
where they matter, like the MLME timers that
we should cancel when disassociating, rather
than only when the interface is set DOWN.

Clean up all this code.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2337db8d
...@@ -370,12 +370,9 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -370,12 +370,9 @@ static int ieee80211_stop(struct net_device *dev)
* (because if we remove a STA after ops->remove_interface() * (because if we remove a STA after ops->remove_interface()
* the driver will have removed the vif info already!) * the driver will have removed the vif info already!)
* *
* We could relax this and only unlink the stations from the * This is relevant only in AP, WDS and mesh modes, since in
* hash table and list but keep them on a per-sdata list that * all other modes we've already removed all stations when
* will be inserted back again when the interface is brought * disconnecting etc.
* up again, but I don't currently see a use case for that,
* except with WDS which gets a STA entry created when it is
* brought up.
*/ */
sta_info_flush(local, sdata); sta_info_flush(local, sdata);
...@@ -410,11 +407,21 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -410,11 +407,21 @@ static int ieee80211_stop(struct net_device *dev)
struct ieee80211_sub_if_data *vlan, *tmpsdata; struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon = sdata->u.ap.beacon; struct beacon_data *old_beacon = sdata->u.ap.beacon;
/* sdata_running will return false, so this will disable */
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
/* remove beacon */ /* remove beacon */
rcu_assign_pointer(sdata->u.ap.beacon, NULL); rcu_assign_pointer(sdata->u.ap.beacon, NULL);
synchronize_rcu(); synchronize_rcu();
kfree(old_beacon); kfree(old_beacon);
/* free all potentially still buffered bcast frames */
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
local->total_ps_buffered--;
dev_kfree_skb(skb);
}
/* down all dependent devices, that is VLANs */ /* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list) u.vlan.list)
...@@ -454,27 +461,6 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -454,27 +461,6 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_configure_filter(local); ieee80211_configure_filter(local);
break; break;
case NL80211_IFTYPE_STATION:
del_timer_sync(&sdata->u.mgd.chswitch_timer);
del_timer_sync(&sdata->u.mgd.timer);
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
/*
* If any of the timers fired while we waited for it, it will
* have queued its work. Now the work will be running again
* but will not rearm the timer again because it checks
* whether the interface is running, which, at this point,
* it no longer is.
*/
cancel_work_sync(&sdata->u.mgd.chswitch_work);
cancel_work_sync(&sdata->u.mgd.monitor_work);
cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
/* fall through */
case NL80211_IFTYPE_ADHOC:
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
del_timer_sync(&sdata->u.ibss.timer);
/* fall through */
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
if (ieee80211_vif_is_mesh(&sdata->vif)) { if (ieee80211_vif_is_mesh(&sdata->vif)) {
/* other_bss and allmulti are always set on mesh /* other_bss and allmulti are always set on mesh
...@@ -502,17 +488,19 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -502,17 +488,19 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_scan_cancel(local); ieee80211_scan_cancel(local);
/* /*
* Disable beaconing for AP and mesh, IBSS can't * Disable beaconing here for mesh only, AP and IBSS
* still be joined to a network at this point. * are already taken care of.
*/ */
if (sdata->vif.type == NL80211_IFTYPE_AP || if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
ieee80211_bss_info_change_notify(sdata, ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED); BSS_CHANGED_BEACON_ENABLED);
}
/* free all remaining keys, there shouldn't be any */ /*
* Free all remaining keys, there shouldn't be any,
* except maybe group keys in AP more or WDS?
*/
ieee80211_free_keys(sdata); ieee80211_free_keys(sdata);
drv_remove_interface(local, &sdata->vif); drv_remove_interface(local, &sdata->vif);
} }
...@@ -593,8 +581,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) ...@@ -593,8 +581,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct beacon_data *beacon;
struct sk_buff *skb;
int flushed; int flushed;
int i; int i;
...@@ -607,37 +593,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) ...@@ -607,37 +593,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
__skb_queue_purge(&sdata->fragments[i].skb_list); __skb_queue_purge(&sdata->fragments[i].skb_list);
sdata->fragment_next = 0; sdata->fragment_next = 0;
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
beacon = sdata->u.ap.beacon;
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
synchronize_rcu();
kfree(beacon);
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
local->total_ps_buffered--;
dev_kfree_skb(skb);
}
break;
case NL80211_IFTYPE_MESH_POINT:
if (ieee80211_vif_is_mesh(&sdata->vif)) if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_rmc_free(sdata); mesh_rmc_free(sdata);
break;
case NL80211_IFTYPE_ADHOC:
if (WARN_ON(sdata->u.ibss.presp))
kfree_skb(sdata->u.ibss.presp);
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
BUG();
break;
}
flushed = sta_info_flush(local, sdata); flushed = sta_info_flush(local, sdata);
WARN_ON(flushed); WARN_ON(flushed);
......
...@@ -991,6 +991,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -991,6 +991,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
if (remove_sta) if (remove_sta)
sta_info_destroy_addr(sdata, bssid); sta_info_destroy_addr(sdata, bssid);
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
del_timer_sync(&sdata->u.mgd.timer);
del_timer_sync(&sdata->u.mgd.chswitch_timer);
} }
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
......
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