aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c45
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
24static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) 41static 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}