diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b9074824862a..00562a8b99cf 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -21,6 +21,23 @@ | |||
21 | #include "mesh.h" | 21 | #include "mesh.h" |
22 | #include "led.h" | 22 | #include "led.h" |
23 | 23 | ||
24 | /** | ||
25 | * DOC: Interface list locking | ||
26 | * | ||
27 | * The interface list in each struct ieee80211_local is protected | ||
28 | * three-fold: | ||
29 | * | ||
30 | * (1) modifications may only be done under the RTNL | ||
31 | * (2) modifications and readers are protected against each other by | ||
32 | * the iflist_mtx. | ||
33 | * (3) modifications are done in an RCU manner so atomic readers | ||
34 | * can traverse the list in RCU-safe blocks. | ||
35 | * | ||
36 | * As a consequence, reads (traversals) of the list can be protected | ||
37 | * by either the RTNL, the iflist_mtx or RCU. | ||
38 | */ | ||
39 | |||
40 | |||
24 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 41 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
25 | { | 42 | { |
26 | int meshhdrlen; | 43 | int meshhdrlen; |
@@ -383,6 +400,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
383 | atomic_dec(&local->iff_promiscs); | 400 | atomic_dec(&local->iff_promiscs); |
384 | 401 | ||
385 | dev_mc_unsync(local->mdev, dev); | 402 | dev_mc_unsync(local->mdev, dev); |
403 | del_timer_sync(&local->dynamic_ps_timer); | ||
404 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
386 | 405 | ||
387 | /* APs need special treatment */ | 406 | /* APs need special treatment */ |
388 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 407 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
@@ -441,6 +460,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
441 | WLAN_REASON_DEAUTH_LEAVING); | 460 | WLAN_REASON_DEAUTH_LEAVING); |
442 | 461 | ||
443 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); | 462 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); |
463 | del_timer_sync(&sdata->u.sta.chswitch_timer); | ||
444 | del_timer_sync(&sdata->u.sta.timer); | 464 | del_timer_sync(&sdata->u.sta.timer); |
445 | /* | 465 | /* |
446 | * If the timer fired while we waited for it, it will have | 466 | * If the timer fired while we waited for it, it will have |
@@ -450,6 +470,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
450 | * it no longer is. | 470 | * it no longer is. |
451 | */ | 471 | */ |
452 | cancel_work_sync(&sdata->u.sta.work); | 472 | cancel_work_sync(&sdata->u.sta.work); |
473 | cancel_work_sync(&sdata->u.sta.chswitch_work); | ||
453 | /* | 474 | /* |
454 | * When we get here, the interface is marked down. | 475 | * When we get here, the interface is marked down. |
455 | * Call synchronize_rcu() to wait for the RX path | 476 | * Call synchronize_rcu() to wait for the RX path |
@@ -459,7 +480,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
459 | synchronize_rcu(); | 480 | synchronize_rcu(); |
460 | skb_queue_purge(&sdata->u.sta.skb_queue); | 481 | skb_queue_purge(&sdata->u.sta.skb_queue); |
461 | 482 | ||
462 | sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; | 483 | sdata->u.sta.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | |
484 | IEEE80211_STA_TKIP_WEP_USED); | ||
463 | kfree(sdata->u.sta.extra_ie); | 485 | kfree(sdata->u.sta.extra_ie); |
464 | sdata->u.sta.extra_ie = NULL; | 486 | sdata->u.sta.extra_ie = NULL; |
465 | sdata->u.sta.extra_ie_len = 0; | 487 | sdata->u.sta.extra_ie_len = 0; |
@@ -627,6 +649,13 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
627 | kfree(sdata->u.sta.assocreq_ies); | 649 | kfree(sdata->u.sta.assocreq_ies); |
628 | kfree(sdata->u.sta.assocresp_ies); | 650 | kfree(sdata->u.sta.assocresp_ies); |
629 | kfree_skb(sdata->u.sta.probe_resp); | 651 | kfree_skb(sdata->u.sta.probe_resp); |
652 | kfree(sdata->u.sta.ie_probereq); | ||
653 | kfree(sdata->u.sta.ie_proberesp); | ||
654 | kfree(sdata->u.sta.ie_auth); | ||
655 | kfree(sdata->u.sta.ie_assocreq); | ||
656 | kfree(sdata->u.sta.ie_reassocreq); | ||
657 | kfree(sdata->u.sta.ie_deauth); | ||
658 | kfree(sdata->u.sta.ie_disassoc); | ||
630 | break; | 659 | break; |
631 | case NL80211_IFTYPE_WDS: | 660 | case NL80211_IFTYPE_WDS: |
632 | case NL80211_IFTYPE_AP_VLAN: | 661 | case NL80211_IFTYPE_AP_VLAN: |
@@ -788,7 +817,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
788 | params->mesh_id_len, | 817 | params->mesh_id_len, |
789 | params->mesh_id); | 818 | params->mesh_id); |
790 | 819 | ||
820 | mutex_lock(&local->iflist_mtx); | ||
791 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 821 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
822 | mutex_unlock(&local->iflist_mtx); | ||
792 | 823 | ||
793 | if (new_dev) | 824 | if (new_dev) |
794 | *new_dev = ndev; | 825 | *new_dev = ndev; |
@@ -804,7 +835,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | |||
804 | { | 835 | { |
805 | ASSERT_RTNL(); | 836 | ASSERT_RTNL(); |
806 | 837 | ||
838 | mutex_lock(&sdata->local->iflist_mtx); | ||
807 | list_del_rcu(&sdata->list); | 839 | list_del_rcu(&sdata->list); |
840 | mutex_unlock(&sdata->local->iflist_mtx); | ||
841 | |||
808 | synchronize_rcu(); | 842 | synchronize_rcu(); |
809 | unregister_netdevice(sdata->dev); | 843 | unregister_netdevice(sdata->dev); |
810 | } | 844 | } |
@@ -820,7 +854,16 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
820 | ASSERT_RTNL(); | 854 | ASSERT_RTNL(); |
821 | 855 | ||
822 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 856 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { |
857 | /* | ||
858 | * we cannot hold the iflist_mtx across unregister_netdevice, | ||
859 | * but we only need to hold it for list modifications to lock | ||
860 | * out readers since we're under the RTNL here as all other | ||
861 | * writers. | ||
862 | */ | ||
863 | mutex_lock(&local->iflist_mtx); | ||
823 | list_del(&sdata->list); | 864 | list_del(&sdata->list); |
865 | mutex_unlock(&local->iflist_mtx); | ||
866 | |||
824 | unregister_netdevice(sdata->dev); | 867 | unregister_netdevice(sdata->dev); |
825 | } | 868 | } |
826 | } | 869 | } |